3

I want to convert long filenames/path to short filenames (8.3). I'm developing a script that calls a command line tool that only accepts short filenames.

So i need to convert

C:\Ruby193\bin\test\New Text Document.txt

to

C:\Ruby193\bin\test\NEWTEX~1.TXT

So far i found How to get long filename from ARGV which uses WIN32API to convert short to long filenames (the opposite of what I want to achieve).

Is there any way to get the short filename in Ruby?

Community
  • 1
  • 1
user1251007
  • 15,891
  • 14
  • 50
  • 76

3 Answers3

3

You can do this using FFI; there's actually an example that covers your exact scenario in their wiki under the heading "Convert a path to 8.3 style pathname":

require 'ffi'

module Win
  extend FFI::Library
  ffi_lib 'kernel32'
  ffi_convention :stdcall

  attach_function :path_to_8_3, :GetShortPathNameA, [:pointer, :pointer, :uint], :uint
end
out = FFI::MemoryPointer.new 256 # bytes
Win.path_to_8_3("c:\\program files", out, out.length)
p out.get_string # be careful, the path/file you convert to 8.3 must exist or this will be empty
Abe Voelker
  • 30,124
  • 14
  • 81
  • 98
  • +1 Thanks for your answer. Though I prefer not installing additional modules. Sorry, I did not mentioned that in my question. – user1251007 Apr 20 '12 at 10:32
3

This ruby code uses getShortPathName and don't need additional modules to be installed.

def get_short_win32_filename(long_name)
    require 'win32api'
    win_func = Win32API.new("kernel32","GetShortPathName","PPL"," L")
    buf = 0.chr * 256
    buf[0..long_name.length-1] = long_name
    win_func.call(long_name, buf, buf.length)
    return buf.split(0.chr).first
end
user1251007
  • 15,891
  • 14
  • 50
  • 76
1

The windows function you require is GetShortPathName. You could use that in the same manner as described in your linked post.

EDIT: sample usage of GetShortPathName (just as a quick example) - shortname will contain "C:\LONGFO~1\LONGFI~1.TXT" and returned value is 24.

TCHAR* longname = "C:\\long folder name\\long file name.txt";
TCHAR* shortname = new TCHAR[256];
GetShortPathName(longname,shortname,256);
msam
  • 4,259
  • 3
  • 19
  • 32
  • I did not manage to adjust that code to _GetShortPathName_. Are you familiar with that and could provide an example? – user1251007 Apr 19 '12 at 14:11
  • 1
    added code in c++, can't help you with the Ruby code but i would guess it would have to be as in the post by Peter in your linked post. Note that normally you should first call it with NULL as shortname and 0 as size. This will return the required size, then call it again with the appropriate size and allocated buffer. – msam Apr 19 '12 at 14:45
  • Thanks for the code, i finally managed to port it to Ruby code - See my answer – user1251007 Apr 20 '12 at 10:40