1

I'm trying to read a text file, using coommand line arguments to pass the file, that has spaces in path or filename. For example if you drop a text file on the myapplication.exe, and you get the command$ or if you run it from command line myapp.exe c:\My folder\my text file.txt or when the myapp.exe used in contex menu, so when you right click the text file and select to open it with myapp.exe

example:

"c:\My folder\my text file.txt"

But I get errors when I'm trying to access (read it).

  • Bad file name or number, when I'm try to Open.
  • List item

File not found, when I use DIR if order to check existance

Because I need the real name to create a new file with another extension, I can't use the GetShortPathNameabd for 8.3 name format.

Example: I need to read the "c:\My folder\my text file.txt" and create a new one with "c:\My folder\my text file_txt.lock" as filename

Thanks in advance for your help

1 Answers1

3

To properly split and unescape double quotes in your command line you have to use CommandLineToArgvW API function to be compatible with standard command line quoting as nicely described in the Everyone quotes command line arguments the wrong way blog post.

Try this code in a standard module:

'--- Module1.bas
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CommandLineToArgvW Lib "shell32" (ByVal lpCmdLine As Long, pNumArgs As Long) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function ApiSysAllocString Lib "oleaut32" Alias "SysAllocString" (ByVal Ptr As Long) As Long

Public Function SplitArgs(sText As String) As Variant
    Dim vRetVal         As Variant
    Dim lPtr            As Long
    Dim lArgc           As Long
    Dim lIdx            As Long
    Dim lArgPtr         As Long

    If LenB(sText) <> 0 Then
        lPtr = CommandLineToArgvW(StrPtr(sText), lArgc)
    End If
    If lArgc > 0 Then
        ReDim vRetVal(0 To lArgc - 1) As String
        For lIdx = 0 To UBound(vRetVal)
            Call CopyMemory(lArgPtr, ByVal lPtr + 4 * lIdx, 4)
            vRetVal(lIdx) = SysAllocString(lArgPtr)
        Next
    Else
        vRetVal = Split(vbNullString)
    End If
    Call LocalFree(lPtr)
    SplitArgs = vRetVal
End Function

Private Function SysAllocString(ByVal lPtr As Long) As String
    Dim lTemp           As Long

    lTemp = ApiSysAllocString(lPtr)
    Call CopyMemory(ByVal VarPtr(SysAllocString), lTemp, 4)
End Function

The SplitArgs function above can be used like this

'--- Form1.frm
Option Explicit

Private Sub Form_Load()
    Dim vArgs           As Variant
    
    vArgs = SplitArgs(Command$)
    If UBound(vArgs) >= 0 Then
        Debug.Print vArgs(0)
        Debug.Print FileReplaceExtension(vArgs(0), "lock")
    End If
End Sub

Public Function FileReplaceExtension(ByVal sFile As String, sExt As String) As String
    If InStrRev(sFile, ".") > InStrRev(sFile, "\") Then
        FileReplaceExtension = Left$(sFile, InStrRev(sFile, ".")) & sExt
    Else
        FileReplaceExtension = sFile & "." & sExt
    End If
End Function

Note that vArgs(0) will have the first argument passed to command line without the quotes i.e. the string is c:\My folder\my text file.txt stripped of double quotes so that you can Open this filename or replace file extension with simple InStrRev string manipulation like FileReplaceExtension function above does.

wqw
  • 11,771
  • 1
  • 33
  • 41