user884248
user884248

Reputation: 2244

VB6 + GetOpenFileNameW: can't read file dialog results

I'm updating an old legacy system written in VB6. I'm trying to use GetOpenFileNameW to create a file dialog. Everything works great, except that the string I'm getting back is random garbage. Can anyone help out with this? Thanks...

Public Declare Function GetOpenFileNameW Lib "comdlg32.dll" (pOpenfilename As OPENFILENAME_W) As Long
Public Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long

Private Type OPENFILENAME_W
   lStructSize          As Long     'Length of structure, in bytes
   hwndOwner            As Long     'Window that owns the dialog, or NULL
   hInstance            As Long     'Handle of mem object containing template (not used)
   lpstrFilter          As Long     'File types/descriptions, delimited with vbnullchar, ends with 2xvbnullchar
   lpstrCustomFilter    As Long     'Filters typed in by user
   nMaxCustFilter       As Long     'Length of CustomFilter, min 40x chars
   nFilterIndex         As Long     'Filter Index to use (1,2,etc) or 0 for custom
   lpstrFile            As Long     'Initial file/returned file(s), delimited with vbnullchar for multi files
   nMaxFile             As Long     'Size of Initial File long  , min 256
   lpstrFileTitle       As Long     'File.ext excluding path
   nMaxFileTitle        As Long     'Length of FileTitle
   lpstrInitialDir      As Long     'Initial file dir, null for current dir
   lpstrTitle           As Long     'Title bar of dialog
   flags                As Long     'See OFN_Flags
   nFileOffset          As Integer  'Offset to file name in full path, 0-based
   nFileExtension       As Integer  'Offset to file ext in full path, 0-based (excl '.')
   lpstrDefExt          As Long     'Default ext appended, excl '.', max 3 chars
   lCustData            As Long     'Appl defined data for lpfnHook
   lpfnHook             As Long     'Pointer to hook procedure
   lpTemplateName       As Long     'Template Name (not used)
   pvReserved           As Long     'new Win2000 / WinXP members
   dwReserved           As Long     'new Win2000 / WinXP members
   FlagsEx              As Long     'new Win2000 / WinXP members
End Type

Public Function ShowOpenDialog(ByVal wHandle As Long, _
                               Optional ByVal filters As String = "", _
                               Optional ByVal initialDir As String = "", _
                               Optional ByVal dialogTitle As String = "", _
                               Optional ByVal flags As Long = 0) As String    
Dim strBuffer   As String
Dim OFN         As OPENFILENAME_W
Dim RetVal      As Long

With OFN
    .lStructSize = Len(OFN)
    .hwndOwner = wHandle
    .hInstance = App.hInstance

    filters = Trim$(Replace(filters, "|", vbNullChar))
    If right$(filters, 2) <> vbNullChar & vbNullChar Then filters = filters & vbNullChar & vbNullChar
    .lpstrFilter = StrPtr(filters)
    If LenB(filters) > 0 Then .nFilterIndex = 1

    .lpstrFile = StrPtr(String(512, vbNullChar))
    .nMaxFile = Len(.lpstrFile)

    .lpstrDefExt = StrPtr(vbNullChar)

    .lpstrFileTitle = StrPtr(String(512, vbNullChar))
    .nMaxFileTitle = Len(OFN.lpstrFileTitle)

    If AscW(right$(initialDir, 1)) <> 0& Then initialDir = initialDir & vbNullChar & vbNullChar
    .lpstrInitialDir = StrPtr(initialDir)

    If AscW(right$(dialogTitle, 1)) <> 0& Then dialogTitle = dialogTitle & vbNullChar & vbNullChar
    .lpstrTitle = StrPtr(dialogTitle)

    .flags = flags
End With

' call API dialog
If GetOpenFileNameW(OFN) Then
    'remove trailing pair of terminating nulls
    'and Trim returned file string
    Dim result  As String
    result = String$(OFN.nMaxFile, 0)

    Dim numChars    As Long
    Dim tempString  As String

    numChars = lstrlenW(OFN.lpstrFile)
    tempString = Space$(numChars)
    CopyMemory ByVal StrPtr(tempString), ByVal OFN.lpstrFile, numChars * 2

    ShowOpenDialog = tempString
End If
End Function

Upvotes: 0

Views: 536

Answers (1)

wqw
wqw

Reputation: 11991

Your snippet might work by chance. The output buffer you assign to lpstrFile get immediately freed. First assign it to a local var, then use StrPtr to assign it to lpstrFile. Also, Len(.lpstrFile) makes to sense as lpstrFile is a long (not a string as in ANSI version).

    Dim sFileBuffer As String
    ...

    sFileBuffer = String$(512, vbNullChar)
    .lpstrFile = StrPtr(sFileBuffer)
    .nMaxFile = Len(sFileBuffer) - 1
    ...

You can access result in sFileBuffer directly, or use API calls on lpstrFile.

Use -1 for size (nMaxFile) so you can later easily use ShowOpenDialog = Left$(sFileBuffer, InStr(sFileBuffer, vbNullChar) - 1) and be sure that InStr will never return 0 (substring not found).

Upvotes: 4

Related Questions