64 位 PowerShell 调用 32 位 DLL

Posted

技术标签:

【中文标题】64 位 PowerShell 调用 32 位 DLL【英文标题】:64bit PowerShell calls the 32bit DLL 【发布时间】:2019-05-31 01:14:56 【问题描述】:

在 Windows 10 计算机上,我使用 PowerShell 脚本从第 4 维 (4D) 数据库调用 QuickBooks。该脚本调用 32 位 COM 对象 QBXMLRP2.dll 与 QuickBooks 2019 对话。据我了解,如果您使用 64 位版本的 PowerShell 调用 32 位 dll,它将失败,反之亦然。但是,根据我使用的是 32 位还是 64 位版本的 4D,我会得到不同的结果。这对我来说毫无意义。这是我的测试结果:

OS  4D  PowerShell  DLL   Result
64  32  32          32    OK
64  32  64          32    OK //According to my research this should not work!

64  64  32          32    OK
64  64  64          32     X //According to my research this is the expected behavior

关于为什么 64 位版本的 PowerShell/32 位 dll 可以与 32 位版本的 4D 一起使用有什么想法吗?我真正想要的是它可以与 64 位版本的 4D 和 PowerShell 一起使用。

回答问题...这就是我正在做的事情。 4D 首先创建一个.ps1 脚本文件并将其保存到磁盘,然后在外部进程中启动 PowerShell。例如,这将启动 64 位 PowerShell(Windows 10)并且 PowerShell 将执行之前保存的脚本:

"C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -file \""+$ScriptPath+"\""

PowerShell 脚本如下所示:

[String]$requestXML = '<?xml version="1.0" ?>
<?qbxml version="2.0"?><QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CompanyQueryRq requestID="1">
</CompanyQueryRq>
</QBXMLMsgsRq>
</QBXML>'
$myQBXMLRP = New-Object -com QBXMLRP2.RequestProcessor
$myQBXMLRP.OpenConnection2("qb4D","CCFolioPro",1)
$ticket = $myQBXMLRP.BeginSession("C:\Company Files\Cadinha & Co.,LLC.QBW",$myQBXMLRP.qbFileOpenDoNotCare)
$myQBXMLRP.ProcessRequest($ticket, $requestXML) > $env:_4D_OPTION_OUTPUT_STREAM
$myQBXMLRP.EndSession($ticket)
$myQBXMLRP.CloseConnection()
"Stop" > $env:_4D_OPTION_STOP_TOKEN

据我了解,一旦 PowerShell 启动,4D 就不存在了。 4D 不与 dll 交互。都是 PowerShell/dll (COM)/QuickBooks。

【问题讨论】:

很高兴了解您是如何访问 dll 的。 对于 4D 和 DLL 32,powershell 64,我认为 DLL 不能返回额外的信息,powershell 可以解决这个问题。64 能够处理 32,而 4D 无论如何也不期待 64 位命令。但是,当您将 4D 切换到 64 时,powershell 只能使用 32 位与其交互,因此当它运行 64 位 powershell 命令并期望得到 64 位回复时,DLL 会将其缩短为 32 位,从而导致错误。对于 4D 64、PS 和 DLL 32,powershell 期望一切都在 32 中,因此 DLL 和 4D 之间的不匹配永远不会发挥作用,因为 powershell 不会尝试发送任何 64 位命令。 我更新了帖子,希望能回答您的问题。 @Shadowzee我不相信我会遵循您回答的逻辑。您是说 PS 64 能够处理 32 位 DLL 吗?如果我尝试在 64 位版本的 PowerShell ISE 中手动运行 ps 脚本,我会收到“80040154 类未注册...”错误,这是我所期望的。启动 4D 表单时,如果我显示 PowerShell 控制台,我可以看到显示的红色错误,以便快速阅读。所以我很确定我在被 4D 启动时会遇到同样的错误。 我在帖子中添加了 PowerShell 脚本。 让我换个说法。如果当我从 64 位 4D 启动 PowerShell 并将 PS 控制台设置为显示时,我可以看到控制台中显示红色错误消息,所有这些都是为了快速阅读。如果我从 32 位 4D 启动 64 位 PowerShell,控制台会打开,保持打开状态,无错误几秒钟,直到脚本成功完成。后者是我所质疑的。 【参考方案1】:

借助这个论坛的帮助和更多的研究,我现在了解到,在 64 位 Windows 操作系统中,如果操作系统检测到 32 位应用程序正在调用 System32 目录,它会自动将调用重定向到SysWow64 目录。因此,在我的场景中,当从 32 位 4D 调用时,32 位 PowerShell 将始终运行。请注意,仅当调用应用程序在 64 位计算机上为 32 位时,此重定向才起作用。因此,如果 64 位应用程序 (4D) 在 System32 目录中调用 64 位 PowerShell,则不会发生重定向。在这种情况下,如果 PowerShell 调用 32 位 dll,它将失败。 PowerShell/dll 必须匹配位数。

如果想强制 System32 目录中的 64 位版本从 32 位应用程序运行,可以使用特殊的“Sysnative”目录代替 System32 目录。请注意,这是一个虚拟目录。您不会在文件系统中找到它。同样,如果您确实强制使用 64 位 Powershell 并且 PowerShell 尝试调用 32 位 dll,它将失败。

下面的文章很好看……

https://docs.microsoft.com/en-us/windows/desktop/winprog64/file-system-redirector

这是我修正后的测试图表...

OS  4D  PowerShell  DLL   Result
64  32  32          32    OK
64  32  64-OS->32   32    OK //OS redirected to 32bit PS. Expected behavior!

64  64  32          32    OK
64  64  64          32     X //No redirect. Expected behaviour

【讨论】:

以上是关于64 位 PowerShell 调用 32 位 DLL的主要内容,如果未能解决你的问题,请参考以下文章

在 32 位 powershell 中按路径查找/杀死 64 位进程

可以通过参数“-d32”强制 64 位 JVM 使用 32 位模式吗?

PowerShell - 1

NSInteger 和 NSUInteger 在混合的 64 位 / 32 位环境中

32位程序下调用64位函数——进程32位模式与64位模式切换

64位进程调用32位dll的解决方法