EXCEL 64位命令行VBA代码

7
我有一段代码,用于在打开Excel工作簿(64位;但32位代码也存在#if子句下)时获取命令行参数。
例如,当我在命令提示符下运行以下代码行时,我期望能够将输入字符串作为命令行参数获取:
start Excel ".\AwajiPush.xlsm" /p/"kjh%dg.pdf"
(顺便说一下,“start”之所以存在,是为了使它能在.bat批处理文件中工作)
我期望能够捕获".\AwajiPush.xlsm"和/p/"kjh%dg.pdf"作为参数。
但实际上这段代码并没有做到这一点。
为什么它不能获取第二个参数?
我对指针的工作原理不是很了解。是否有一段代码可以用来至少捕获包含两个参数的字符串,以便我可以解析它。如果它包含更多内容,那也没关系。只要它是一致的,我就可以解释它。
我在程序中放置了存根(MsgBox),但我不确定为什么第二个存根显示为空白。
以下是代码:
'Put this code in a new module called Parameters

Option Explicit

#If Win64 Then
    Private Declare PtrSafe Function GetCommandLineL Lib "kernel32" _
     Alias "GetCommandLineA" () As LongPtr

    Private Declare PtrSafe Function lstrcpyL Lib "kernel32" _
     Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As LongPtr) As Long

    Private Declare PtrSafe Function lstrlenL Lib "kernel32" _
     Alias "lstrlenA" (ByVal lpString As LongPtr) As Long


 #Else
    Private Declare Function GetCommandLineL Lib "kernel32" _
     Alias "GetCommandLineA" () As Long

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

    Private Declare Function lstrlenL Lib "kernel32" _
     Alias "lstrlenA" (ByVal lpString As Long) As Long

 #End If

 Function GetCommandLine() As String
   Dim strReturn As String
   #If Win64 Then
   Dim lngPtr As LongPtr
   #Else
   Dim lngPtr As Long
   #End If

   Dim StringLength As Long
   'Get the pointer to the commandline string
   lngPtr = GetCommandLineL

   'get the length of the string (not including the terminating null character):
   StringLength = lstrlenL(lngPtr)
   MsgBox StringLength


   'initialize our string so it has enough characters including the null character:
   strReturn = String$(StringLength + 1, 0)
   'copy the string we have a pointer to into our new string:
   MsgBox strReturn


   lstrcpyL strReturn, lngPtr
   'now strip off the null character at the end:
   MsgBox strReturn


   GetCommandLine = Left$(strReturn, StringLength)

 End Function

并且
'Put this code in "This Workbook"

Sub workBook_open()
    MsgBox Parameters.GetCommandLine
End Sub
2个回答

6

以下是一个用于从当前进程获取命令行的函数:

Private Declare PtrSafe Function w_commandline Lib "kernel32.dll" Alias "GetCommandLineW" () As LongPtr
Private Declare PtrSafe Function w_strlen Lib "kernel32.dll" Alias "lstrlenW" (ByVal lpString As LongPtr) As Long
Private Declare PtrSafe Sub w_memcpy Lib "kernel32.dll" Alias "RtlMoveMemory" (dst As Any, src As Any, ByVal size As LongPtr)

Public Function GetCommandLine() As String
  GetCommandLine = String$(w_strlen(w_commandline()), 0)
  w_memcpy ByVal StrPtr(GetCommandLine), ByVal w_commandline(), LenB(GetCommandLine)
End Function

Sub Test()
  Debug.Print GetCommandLine()
End Sub

请注意,您需要使用/e开关来避免重定向到已启动的Excel实例,并保留提供的参数。例如:
excel.exe /e "C:\temp\myfile.xlsm" /p "myparam"

或者用 start

start "xl" excel.exe /e "C:\temp\myfile.xlsm" /p "myparam"

但如果你的目标是从批处理文件向VBA提供一些参数,那么可以使用环境变量:

Set MyArguments=abcde
start "xl" excel.exe /e "C:\temp\myfile.xlsm"

然后从Excel中获取参数:

Debug.Print Environ("MyArguments") ' >> "abcde" '

在 Windows 11 上,如果我在命令行(而不是批处理)中使用 set 命令创建一个环境变量,那么 VBA 的 Environ 函数将无法返回该变量。它会返回一个空字符串。例如,在命令提示符处执行以下操作:set test=abc - johny why
看起来你的解决方案返回了整个命令行,而不仅仅是参数。在你的例子中,我认为我们需要编写一些字符串操作来提取 /p 之后的所有内容。但是我们必须使用 /p 吗?我们可以使用除 /p 以外的其他字符或字母吗? - johny why
我现在明白为什么使用“set”分配的环境变量在批处理外部不可用于VBA了。 “set”环境变量仅在进程中可用。通过批处理,Excel VBA在与“set”相同的批处理进程中运行,因此VBA可以看到环境变量。 - johny why

0
根据2016年的微软文档,所有的Office产品都不将/P开关视为“命令行参数”开关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接