VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "CArgs"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
' CArgs.cls
Option Explicit

Private m_args()  As String
Private m_count   As Long

' -- Win API ------------------------------------------------------------------

Private Declare Function CommandLineToArgvW Lib "shell32.dll" _
    (ByVal lpCmdLine As Long, pNumArgs As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)

Private Declare Function LocalFree Lib "kernel32" _
    (ByVal hMem As Long) As Long

Private Declare Function lstrlenW Lib "kernel32" _
    (ByVal lpString As Long) As Long

Private Declare Function GetCommandLineW Lib "kernel32" () As Long

Private Declare Function StringToWidePtr Lib "kernel32" Alias "lstrcpyW" _
    (ByVal lpString1 As Long, ByVal lpString2 As String) As Long

Private Declare Function GlobalAlloc Lib "kernel32" _
    (ByVal uFlags As Long, ByVal dwBytes As Long) As Long

Private Declare Function GlobalFree Lib "kernel32" _
    (ByVal hMem As Long) As Long

Private Const GMEM_FIXED As Long = &H0

' -- Init / Parse -------------------------------------------------------------

Private Sub Class_Initialize()
    ' Auto-load from real command line on creation
    'does not work in the ide properly..
    'If IsIde() Then
        Parse Command
    'Else
    '    LoadFromPtr GetCommandLineW()
    'End If
End Sub


Private Function IsIde() As Boolean
    On Error GoTo out
    Debug.Print 1 / 0
out: IsIde = Err
End Function

' Reload from an arbitrary raw command line string (wide ptr via alloc)
Public Sub Parse(ByVal rawCmdLine As String)
    Dim hMem  As Long
    Dim nBytes As Long

    nBytes = (LenB(rawCmdLine) + 2)   ' +2 for null terminator (Unicode)
    hMem = GlobalAlloc(GMEM_FIXED, nBytes)
    If hMem = 0 Then Exit Sub

    CopyMemory ByVal hMem, ByVal StrPtr(rawCmdLine), nBytes
    LoadFromPtr hMem
    GlobalFree hMem
End Sub

' -- Public Interface ---------------------------------------------------------

' True if a switch exists (e.g. "/log", "-v")
Public Function Exists(ByVal name As String) As Boolean
    Exists = (FindArg(name) >= 0)
End Function

' Returns the value after a named switch, "" if not found or no value follows
Public Function GetArg(ByVal name As String) As String
    Dim idx As Long
    idx = FindArg(name)
    If idx >= 0 And idx + 1 < m_count Then
        GetArg = m_args(idx + 1)
    End If
End Function

' Raw access by index (0 = exe path)
Public Function Arg(ByVal index As Long) As String
    If index >= 0 And index < m_count Then Arg = m_args(index)
End Function

Public Property Get Count() As Long
    Count = m_count
End Property

' -- Private Helpers ----------------------------------------------------------

Private Sub LoadFromPtr(ByVal pCmdLine As Long)
    Dim pArgs  As Long
    Dim nArgs  As Long
    Dim i      As Long
    Dim pStr   As Long
    Dim nLen   As Long
    Dim buf()  As Byte

    m_count = 0
    ReDim m_args(0)

    pArgs = CommandLineToArgvW(pCmdLine, nArgs)
    If pArgs = 0 Or nArgs = 0 Then Exit Sub

    ReDim m_args(0 To nArgs - 1)
    m_count = nArgs

    For i = 0 To nArgs - 1
        CopyMemory pStr, ByVal pArgs + (i * 4), 4
        nLen = lstrlenW(pStr)
        If nLen > 0 Then
            ReDim buf(0 To (nLen * 2) - 1)
            CopyMemory buf(0), ByVal pStr, nLen * 2
            m_args(i) = buf
        End If
    Next i

    'MsgBox Join(m_args, ", ")

    LocalFree pArgs
End Sub

' Returns index of matching arg (case-insensitive), -1 if not found
Private Function FindArg(ByVal name As String) As Long
    Dim i As Long
    name = LCase(name)
    For i = 0 To m_count - 1   ' skip args(0) = exe path
        If LCase(m_args(i)) = name Then
            FindArg = i
            Exit Function
        End If
    Next i
    FindArg = -1
End Function
