CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 3 123 LastLast
Results 1 to 15 of 37
  1. #1
    Join Date
    Feb 2003
    Location
    AR
    Posts
    228

    Smile Opening unicode filenames in XP

    Hi,
    Whenever I try to open (with the CommonDialog control) a whatever file with unicode name such as "이누야샤 犬夜叉 화 - 영원의 꿈 건곤언월도.txt", the retrieved filename is "?? ????? ??????....???.txt", and it's impossible to handle a file with this ??? name.

    I don't think it's an error of the CommonDialog control, other programs have the same issue (but not Microsoft's programs), so there must be some easy solution for this which is evading me.

    Please don't tell me to change the system language for non-unicode programs because that's not a solution. The program must adapt to the system, and not vice-versa.

    Any ideas?

  2. #2
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,279

    Re: Opening unicode filenames in XP

    Maybe this Unicode "replacement" for the CommonDialogControl will help

  3. #3
    Join Date
    Dec 2001
    Posts
    6,332

    Re: Opening unicode filenames in XP

    Perhaps StrConv() would help, as it can convert from Unicode.
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  4. #4
    Join Date
    Feb 2003
    Location
    AR
    Posts
    228

    Re: Opening unicode filenames in XP

    StrConv doesn't work either. I'm not paying for any unicode controls just for this, there must be some other workaround for this issue...

  5. #5
    Join Date
    Nov 2005
    Location
    Omaha, Nebraska, USA
    Posts
    696

    Re: Opening unicode filenames in XP

    Actually, you will need to use StrConv, but not by itself. You won't be able to use the Microsoft Common Dialog control, but API.

    Code:
    Option Explicit
    
    Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameW" (pOpenfilename As OPENFILENAME) As Long
    'Normally, the Alias is "GetOpenFileNameA", but thats for ANSI, and we want Unicode
    
    Private Type OPENFILENAME
        lStructSize As Long
        hWndOwner As Long
        hInstance As Long
        lpstrFilter As String
        lpstrCustomFilter As String
        nMaxCustFilter As Long
        nFilterIndex As Long
        lpstrFile As String
        nMaxFile As Long
        lpstrFileTitle As String
        nMaxFileTitle As Long
        lpstrInitialDir As String
        lpstrTitle As String
        flags As Long
        nFileOffset As Integer
        nFileExtension As Integer
        lpstrDefExt As String
        lCustData As Long
        lpfnHook As Long
        lpTemplateName As String
    End Type
    
    Private opFile As OPENFILENAME
    Private lRet As Long
           
    Private Function ShowOpen() As String
        With opFile
            .flags = &H2 Or &H4
            .hInstance = App.hInstance
            .hWndOwner = Me.hWnd
            .lpstrFilter = StrConv(("Text Files" & Chr(0) & "*.txt" & Chr(0) & Chr(0)), vbUnicode)
            .lpstrTitle = StrConv("Open File", vbUnicode)
            .lpstrFile = StrConv(Space(256), vbUnicode)
            .nMaxFile = 512  'Twice lpstrFile's length
            .lStructSize = Len(opFile)
        End With
        Call GetOpenFileName(opFile)
        
        ShowOpen = opFile.lpstrFile
    End Function
    That will return a very messy looking string that, as far as I can see, matches. Your filename showed up as:
    Code:
    t|  rYS  T  -   X  ȯ  t䬸ij. t x t
    The spare spaces are actually Chr(0).

    Oh, and to specify, all the strings that you will pass to the function HAVE to be converted through StrConv before they're passed, or else you'll end up with Unicode characters showing through (see attachment).

    What is weird (at least, to me) is that the options in the File Type drop down will change each time I run it, without even touching the code (sometimes legible words will show up, other times not). Of course, if you leave StrConv in there, it always goes fine.
    Attached Images Attached Images  
    Last edited by ChaosTheEternal; February 21st, 2006 at 03:06 PM.

  6. #6
    Join Date
    Feb 2003
    Location
    AR
    Posts
    228

    Re: Opening unicode filenames in XP

    Thanks, that seems to work. I hope I can save the file without much trouble.

    I previously found the GetOpenFileNameW in MSDN and tried it, but I was using vbFromUnicode instead of vbUnicode for StrConv, so I couldn't make it work correctly. I also found that this requires the Microsoft Layer For Unicode under Windows 9x, luckily that's only 300 KB.

    Thanks again.

  7. #7
    Join Date
    Nov 2005
    Location
    Omaha, Nebraska, USA
    Posts
    696

    Re: Opening unicode filenames in XP

    The problem, unfortunately, comes when you attempt to do anything with that file. Looking at trying to write to the file, or open the file for reading, or creating, and all raise error 52 (Bad file name or number).

    If you look at my next post, I give a full working method to open, read from, and (hopefully) write to files with Unicode names.

    You need the FileSystemObject. Trying with Open File For... gives an error no matter what.
    Last edited by ChaosTheEternal; February 23rd, 2006 at 04:43 PM.

  8. #8
    Join Date
    Nov 2005
    Location
    Omaha, Nebraska, USA
    Posts
    696

    Re: Opening unicode filenames in XP

    Well, last night I had a "wait a minute" moment, and thought how it might be easier to do. Unfortunately, that attempt failed, so I just fixed up my method to be a full example.

    You have to add a reference to the Microsoft Scripting Runtime.
    Code:
    Option Explicit
    
    Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameW" (pOpenfilename As OPENFILENAME) As Long
    Private Declare Function GetSaveFileName Lib "comdlg32.dll" Alias "GetSaveFileNameW" (ByRef pOpenfilename As OPENFILENAME) As Long
    
    Private Type OPENFILENAME
        lStructSize As Long
        hWndOwner As Long
        hInstance As Long
        lpstrFilter As String
        lpstrCustomFilter As String
        nMaxCustFilter As Long
        nFilterIndex As Long
        lpstrFile As String
        nMaxFile As Long
        lpstrFileTitle As String
        nMaxFileTitle As Long
        lpstrInitialDir As String
        lpstrTitle As String
        flags As Long
        nFileOffset As Integer
        nFileExtension As Integer
        lpstrDefExt As String
        lCustData As Long
        lpfnHook As Long
        lpTemplateName As String
    End Type
    
    Dim sString As String
    
    Private opFile As OPENFILENAME
    Private fso As FileSystemObject
           
    Private Function ShowOpenUnicode() As String
        With opFile
            .flags = &H2 Or &H4
            .hInstance = App.hInstance
            .hWndOwner = Me.hWnd
            .lpstrFilter = StrConv(("Text Files" & Chr(0) & "*.txt" & Chr(0) & Chr(0)), vbUnicode)
            .lpstrTitle = StrConv("Open File", vbUnicode)
            .lpstrFile = StrConv(String(256, Chr(0)), vbUnicode)
            .nMaxFile = 512
            .lStructSize = Len(opFile)
        End With
        Call GetOpenFileName(opFile)
        
        ShowOpenUnicode = opFile.lpstrFile
    End Function
    
    Private Function ShowSaveUnicode() As String
        With opFile
            .flags = &H2 Or &H4
            .hInstance = App.hInstance
            .hWndOwner = Me.hWnd
            .lpstrFilter = StrConv(("Text Files" & Chr(0) & "*.txt" & Chr(0) & Chr(0)), vbUnicode)
            .lpstrTitle = StrConv("Save File", vbUnicode)
            .nMaxFile = 512
            .lpstrFile = sString & String(512 - Len(sString), Chr(0))
            .lStructSize = Len(opFile)
        End With
        Call GetSaveFileName(opFile)
        
        ShowSaveUnicode = opFile.lpstrFile
    End Function
    
    Private Function ConvertFileName(sToConvert) As String
        Dim bFileName() As Byte
        Dim lRet As Long
        Dim sBuf As String
        'Get rid of the trailing Null characters
        sToConvert = Left$(sToConvert, InStr(sToConvert, (Chr(0) & Chr(0))) - 1)
        
        If Len(sToConvert) Mod 2 <> 0 Then
            sToConvert = sToConvert & Chr(0) 'If the file has an ANSI extension or just an ANSI last character of
                                             'a file with no extension, add one on the end
                                             'If we don't add it, the string will end one character too short
        End If
        
        bFileName = StrConv(sToConvert, vbFromUnicode) 'Put the string into a byte array
        
        sBuf = ""
        For lRet = 0 To Len(sToConvert) - 1 Step 2
            'At this point, the unicode characters will show up in sBuf as ?, but, when we actually go
            'to use this in the FSO function, it will find the right file
            sBuf = sBuf & StrConv(Chr(bFileName(lRet)) & Chr(bFileName(lRet + 1)), vbFromUnicode)
        Next
    
        'And return the string for use
        ConvertFileName = sBuf
    End Function
    
    
    Private Sub UnicodeSaveMethod()
        Dim sFileName As String
        
        'Show the save dialog and get the file path as Unicode in a VB String
        sFileName = ShowSaveUnicode
    
        If Left$(sFileName, 1) = Chr(0) Then Exit Sub 'Exit on Cancel
        'Convert the file name to be used
        sFileName = ConvertFileName(sFileName)
        
        'Here is where you'd create the file, input the text, and save it
        'For this example, I just try to create the file
        Call fso.CreateTextFile(sFileName, False)
    End Sub
    
    Private Sub UnicodeOpenMethod()
        Dim sFileName As String
        
        'Show the open dialog and get the file path as Unicode in a VB String
        sFileName = ShowOpenUnicode
        
        If Left$(sFileName, 1) = Chr(0) Then Exit Sub 'Exit on Cancel
        'Convert the file name to be used
        sFileName = ConvertFileName(sFileName)
        
        'This line will print everything in the file to show you it works
        'Otherwise, you'd have normal open/read/etc code here
        Debug.Print fso.OpenTextFile(sFileName, ForReading, False).ReadAll
    End Sub
    
    Private Sub Form_Load()
        Set fso = New FileSystemObject
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        Set fso = Nothing
    End Sub
    
    Private Sub Command1_Click()
        UnicodeOpenMethod
    End Sub
    
    Private Sub Command2_Click()
        UnicodeSaveMethod
    End Sub
    It will get full filenames accurately (path and everything), and it will open the right file and save the Unicode filename.

    I could probably just turn this into a class that will show a Unicode Open or Save Dialog and just take and use Strings...

  9. #9
    Join Date
    Feb 2003
    Location
    AR
    Posts
    228

    Re: Opening unicode filenames in XP

    Hey that's a fine piece of work, it works perfectly.

    Of course I'll have to change the way I read and save files now with the FSO, luckily I found how to easily read them line by line here.

    I wonder if this scrrun.dll (Ms Scripting Runtime) is available and compatible with older Windows versions, or if I have to distribute in my installer. This is why I hate using OCXs and external references, but there's now other solution for unicode file names.

    Thanks.

  10. #10
    Join Date
    Dec 2001
    Posts
    6,332

    Re: Opening unicode filenames in XP

    I haven't had to use the FSO in a long time, but anytime I have, I did so without adding any references.

    Here's how I have always done it:
    Code:
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Has anyone checked to see what effect the GetShortPathName API function has on this Unicode issue? Apparently there is also a GetShortPathNameW function.

    Also check this (be sure to scroll down past the ads to see the rest of the code): http://www.experts-exchange.com/Prog..._21629619.html
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  11. #11
    Join Date
    Dec 2001
    Posts
    6,332

    Re: Opening unicode filenames in XP

    Quote Originally Posted by ChaosTheEternal
    The problem, unfortunately, comes when you attempt to do anything with that file. Looking at trying to write to the file, or open the file for reading, or creating, and all raise error 52 (Bad file name or number).

    If you look at my next post, I give a full working method to open, read from, and (hopefully) write to files with Unicode names.

    You need the FileSystemObject. Trying with Open File For... gives an error no matter what.
    I have just now tried a bunch of tests to see how/when this error comes up, but the Open statement has worked perfectly every time. I do know that the test system has the Unicode layer installed, so perhaps this does the trick? I can't say I've ever run into trouble because of Unicode filenames. At least not that I'm aware of.

    Here is a test I just did:
    Code:
    Private Sub Command1_Click()
    Dim A$
    A = "F:\this is a Unicode filename test"
    A = StrConv(A, vbUnicode)
    Open A For Binary Access Write As #1
      Put #1, , A
    Close #1
    
    Open A For Binary Access Read As #1
      A = String$(LOF(1), 0)
      Get #1, , A
    Close #1
    Text1 = StrConv(A, vbFromUnicode)
    End Sub
    This works perfectly...but with one odd exception I had not expected in a million years. I cannot locate the file in windows explorer! The file doesn't show in a FileListBox, nor via FindNextFile API. Read access works now without writing the file, since it's apparently there, but how is it locating it? I can honestly say I've not run into this ever.

    <UPDATE>
    I have verified that the Kill command works on the above file, and the Name command works as well, which enables it to show in windows explorer and so forth:
    Code:
    Name A As StrConv(A, vbFromUnicode)
    <UPDATE>
    I just tried another test, which results in a file showing only the first letter for the name, but everything still works without raising errors.
    Code:
    Private Sub Command1_Click()
    Dim A$
    A = "this is a Unicode filename test"
    A = StrConv(A, vbUnicode)
    Open "F:\" & A For Binary Access Write As #1
      Put #1, , A
    Close #1
    
    Open "F:\" & A For Binary Access Read As #1
      A = String$(LOF(1), 0)
      Get #1, , A
    Close #1
    Text1 = StrConv(A, vbFromUnicode)
    End Sub
    <UPDATE>
    Since I've not had to be concerned with Unicode thus far, looking into it has turned up some interesting things. Apparently the MSLU (Unicode layer for windows 9x) must be explicitly used by the app. It's not something the system does once the layer is installed. Every application is expected to install and use its own copy of the DLL into the program's directory, not the system directory. If an xp theme is applied, this can actually present problems for Unicode. Having a Manifest file may not be advisable, but the theme can still be applied to controls from what I'm reading. Here is a link to a lot of good Unicode info including working with files: http://www.cyberactivex.com/UnicodeTutorialVb.htm
    Last edited by WizBang; February 25th, 2006 at 07:33 PM.
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  12. #12
    Join Date
    Nov 2005
    Location
    Omaha, Nebraska, USA
    Posts
    696

    Re: Opening unicode filenames in XP

    Quote Originally Posted by WizBang
    I haven't had to use the FSO in a long time, but anytime I have, I did so without adding any references.
    I didn't specifically mean that you have to add a reference. You would just need to change any of the FSO parameters that use enums to the actual value (like ForReading becomes 1).
    I'm just still not used to early binding while coding then moving to late binding when finished. Of course, since most of what I code now is for my job, and every computer is, more or less, the same, changing to late binding isn't seen as necessary.

    Quote Originally Posted by WizBang
    I have just now tried a bunch of tests to see how/when this error comes up, but the Open statement has worked perfectly every time. I do know that the test system has the Unicode layer installed, so perhaps this does the trick? I can't say I've ever run into trouble because of Unicode filenames. At least not that I'm aware of.

    Here is a test I just did:
    The issue with that test is that you're converting the file from:
    Code:
    F:\this is a Unicode filename test
    to
    Code:
    F : \ t h i s   i s   a   U n i c o d e   f i l e n a m e   t e s t
    The spaces in the even spots are actually null characters (duplicatable with Chr(0)), which, when you go to save the file, makes it so the Open statement only sees "F"..

    With my code, if you were to open a file that required Unicode (like with a filename the OP showed) via Open, you would get an error. Just add:
    Code:
    Open sFileName For Input As #1
    Close #1
    After the Debug.Print in the UnicodeOpenMethod in my code. You'll see the error occur with Unicode filenames.

    Quote Originally Posted by WizBang
    Since I've not had to be concerned with Unicode thus far, looking into it has turned up some interesting things. Apparently the MSLU (Unicode layer for windows 9x) must be explicitly used by the app. It's not something the system does once the layer is installed. Every application is expected to install and use its own copy of the DLL into the program's directory, not the system directory. If an xp theme is applied, this can actually present problems for Unicode. Having a Manifest file may not be advisable, but the theme can still be applied to controls from what I'm reading. Here is a link to a lot of good Unicode info including working with files: http://www.cyberactivex.com/UnicodeTutorialVb.htm
    That is a good piece of information, though. If I ever actually need to work in Unicode myself (this was a good break from connecting VB to Lotus Notes, which is much more agitating than figuring out Unicode with VB), I'll remember that.

  13. #13
    Join Date
    Dec 2001
    Posts
    6,332

    Re: Opening unicode filenames in XP

    Quote Originally Posted by ChaosTheEternal
    I'm just still not used to early binding while coding then moving to late binding when finished. Of course, since most of what I code now is for my job, and every computer is, more or less, the same, changing to late binding isn't seen as necessary.
    Good point about the binding. I had thought about it while posting...for about .01 seconds, but not using the FSO or variants I guess I didn't care to mention it. The only time I end up using such things is in ASP pages, but without custom components on the server, that's all I get access to.
    The issue with that test is that you're converting the file from:
    Code:
    F:\this is a Unicode filename test
    to
    Code:
    F : \ t h i s   i s   a   U n i c o d e   f i l e n a m e   t e s t
    The spaces in the even spots are actually null characters (duplicatable with Chr(0)), which, when you go to save the file, makes it so the Open statement only sees "F"..
    The only thing that bothers me about that idea is if the filename is only the drive letter, why would it allow file access? I'll have to try a few more tests on this later when I get the chance. Maybe creating a second file with such a name can reveal what's happening. If the first file is access instead of recognizing the different name, then I'd suppose you're right.
    With my code, if you were to open a file that required Unicode (like with a filename the OP showed) via Open, you would get an error. Just add:
    Code:
    Open sFileName For Input As #1
    Close #1
    After the Debug.Print in the UnicodeOpenMethod in my code. You'll see the error occur with Unicode filenames.
    Then perhaps I didn't actually have a true Unicode filename. I think I did have some at one point, but since they didn't display properly, I renamed them some time ago. It might be good for everyone interested in this issue if someone can post a zip with a file in it which has a Unicode filename. As soon as I can I'll get back to this thread with whatever I find out, if anything.
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

  14. #14
    Join Date
    Nov 2005
    Location
    Omaha, Nebraska, USA
    Posts
    696

    Re: Opening unicode filenames in XP

    Quote Originally Posted by WizBang
    The only thing that bothers me about that idea is if the filename is only the drive letter, why would it allow file access?
    For the same reason that:
    Code:
    Open "file.txt" For Input As #1
    Is valid.

    While you think it only sees the drive letter, all it really sees is "F". Because it isn't seeing the colon and backslash, it doesn't see it as a drive letter, but a filename. So it will create a file named "F" in the same directory as the app (or wherever you have VB start in, if you're in the IDE).

    Quote Originally Posted by WizBang
    Then perhaps I didn't actually have a true Unicode filename. I think I did have some at one point, but since they didn't display properly, I renamed them some time ago. It might be good for everyone interested in this issue if someone can post a zip with a file in it which has a Unicode filename. As soon as I can I'll get back to this thread with whatever I find out, if anything.
    I'd post a zip with the OP's filename, but WinZip and Windows "compressed folders" don't recognize Unicode filenames (and I can't install/use other compressors at work).

  15. #15
    Join Date
    Dec 2001
    Posts
    6,332

    Re: Opening unicode filenames in XP

    Quote Originally Posted by ChaosTheEternal
    For the same reason that:
    Code:
    Open "file.txt" For Input As #1
    Is valid.

    While you think it only sees the drive letter, all it really sees is "F". Because it isn't seeing the colon and backslash, it doesn't see it as a drive letter, but a filename. So it will create a file named "F" in the same directory as the app (or wherever you have VB start in, if you're in the IDE).
    Well, I just had to try this, and you're right! There was a file named "F" in the folder for VB.
    I'd post a zip with the OP's filename, but WinZip and Windows "compressed folders" don't recognize Unicode filenames (and I can't install/use other compressors at work).
    Thanks for that. I was wondering about WinZip and Unicode files, and seems to me I had heard a thing or two before, but I didn't know if it was because of user error or not. I guess if/when WinZip supports Unicode, it will be of much greater interest to many.
    Please remember to rate the posts and threads that you find useful.
    How can something be both new and improved at the same time?

Page 1 of 3 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured