Ruby - DOS (Win32)路径名转换为NT(本机)路径名

4
我需要在Ruby(1.9.3)中从DOS(Win32)路径获取文件的NT(本机)路径。
也就是说,我有一个字符串:
dos_path = "C:\Windows\regedit.exe"

但我需要:

nt_path = "\Device\HarddiskVolume1\Windows\regedit.exe"

有没有办法这样做呢? 谢谢!

你需要一种获取路径或转换路径的方法吗?你可以使用 gsub 将 "C:" 替换为 "\Device\HarddiskVolume1" 吗? - jkeuhlen
@jkeuhlen 我需要一种方法来转换路径,当然..我有完整的DOS路径,但我需要在不知道本地路径是什么的情况下进行转换。 - Guy
调用 QueryDosDevice(使用 Fiddle 或 Win32API),然后使用 String#sub。您需要一个示例吗? - cremno
@cremno 感激不尽 :) - Guy
1个回答

2

使用QueryDosDevice函数可以将MS-DOS设备名称转换为NT路径。通过Fiddle,可以从Ruby中调用此类函数。自1.9.3以来,它已成为Ruby标准库的一部分。但是,以下示例仅适用于2.0.0或更新版本。

require 'fiddle/import'
require 'fiddle/types'

module DOS2NT
  extend Fiddle::Importer # makes function importing easier
  dlload 'kernel32.dll'
  include Fiddle::Win32Types # so DWORD can be used instead of unsigned long
  extern 'DWORD QueryDosDeviceW(void*, void*, DWORD)', :stdcall
  extern 'DWORD GetLastError()', :stdcall
  ERROR_INSUFFICIENT_BUFFER = 122

  SIZEOF_WCHAR = 2 # sizeof(WCHAR) on Windows

  # a generic error class
  class Error < StandardError
  end

  def self.dos_device_name_to_path(devicename)
    initial_len = 256
    grow_factor = 2
    # we care about Unicode (Windows uses UTF-16LE)
    devicename.encode!(Encoding::UTF_16LE)
    # create buffer
    buf = "\0\0".force_encoding(Encoding::UTF_16LE) * initial_len
    # call QueryDosDeviceW until the call was successful
    while (written_chars = QueryDosDeviceW(devicename, buf, buf.length)) == 0
      # it wasn't
      case (error = GetLastError())
      # resize buffer as it was too short
      when ERROR_INSUFFICIENT_BUFFER
        buf *= grow_factor
      # other errors like ERROR_FILE_NOT_FOUND (2)
      else
        raise Error, "QueryDosDeviceW failed (GetLastError returned #{error})"
      end
    end
    # truncate buffer (including the null character)
    path = buf[0, written_chars - SIZEOF_WCHAR]
    # transcode the path to UTF-8 as that's usually more useful
    path.encode!(Encoding::UTF_8)
  end
end
# example strings from the question
dos_path = 'C:\Windows\regedit.exe'
nt_path = '\Device\HarddiskVolume1\Windows\regedit.exe'
# convert and print inspected result
p dos_path.sub(/\A[A-Z]:/i) { |m| DOS2NT.dos_device_name_to_path(m) } # => "\\Device\\HarddiskVolume1\\Windows\\regedit.exe"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接