由于 OLE for Retail POS (OPOS) 服务对象仅作为 32 位对象存在,因此在某些情况下,引用适用于 .NET 的 Microsoft 服务点 (POS for .NET) 程序集的 64 位应用程序可能无法加载 OPOS 服务对象。 如果应用程序满足某些要求,则可以使用本主题中讨论的两个过程之一来与 32 位 OPOS 服务对象进行互操作。
编译为 32 位的 POS for .NET 应用程序应适用于所有 OPOS 服务对象,不需要本主题中所述的任何过程。
要求
应用程序必须满足以下所有条件才能使用本主题中所述的过程:
- 应用程序在 64 位 Windows 上运行。
- 应用程序使用 OPOS 服务对象。
- 引用 POS for .NET 的可执行文件编译为 Microsoft 中间语言 (MSIL)(“anycpu”平台)。
- 应用程序引用的所有托管程序集也编译为 MSIL。
在这些情况下,公共库运行时 (CLR) 将看到所有托管程序集都是 MSIL,因此它将选择将托管应用程序作为 64 位进程运行。 当 POS for .NET 尝试将 32 位 OPOS 服务对象加载为进程内 COM 服务器时,它将无法加载,并且设备对应用程序不可见。 这是因为 64 位进程无法将 32 位 COM 服务器加载到其进程空间中。
可以使用以下两种解决方案之一来解决此问题:
将托管进程编译为 32 位进程
可以通过编译主可执行文件以面向 x86 或 anycpu32bitpreferred 平台来强制进程作为 32 位进程运行。 这会导致托管应用以 32 位形式运行,并将 OPOS 对象加载为进程内 COM 服务器。
在命令提示符下将应用程序编译为 32 位
将
/platform:x86
编译器选项添加到 C# 编译器命令,如以下示例所示:csc /platform:x86 <filename>.cs
有关详细信息,请参阅 MSDN 上的 /platform(C# 编译器选项)。
在 Visual Studio 2013 中将应用程序编译为 32 位
在 Microsoft Visual Studio 2013 中打开项目。
打开“生成”菜单,选择“Configuration Manager”。
在“Configuration Manager”对话框的“平台”列中,单击单元格以展开下拉菜单,然后选择“x86”。 如果“x86”不可用,请选择“<新建...>”,然后选择“x86”作为新平台并单击“确定”。
重新生成项目。
将托管进程编译为 64 位进程并修改 OPOS 对象的 COM 注册表
可以修改 OPOS 服务对象的 COM 注册以使用 32 位主机进程。 这会导致 Windows 处理进程内通信 (IPC) 和 64 位托管进程与 32 位 COM 代理主机进程之间的数据封送。
修改 OPOS 服务对象的 COM 注册表
在注册表中,在 HKEY_CLASSES_ROOT/Wow6432Node/CLSID 下找到 COM 对象 GUID 项。
找到 COM 对象 GUID 键后,添加新字符串值 (REG_SZ)。 将名称设置为 AppID,并将数据设置为 COM 对象 GUID,包括大括号。
在 HKEY_CLASSES_ROOT/Wow6432Node/AppID 下添加新键,其名称与 COM 对象 GUID 键相同。
在刚刚添加的新键下,添加新的字符串值 (REG_SZ)。 将名称设置为 DllSurrogate。 将此值留空。
在 HKEY_LOCAL_MACHINE/Software/Classes/AppID 下创建一个与 COM 对象的 GUID 同名的新键(如果尚不存在)。 无需向此键添加任何值。
或者,可以使用以下 Windows PowerShell 脚本修改所有 OPOS 公用控件对象 (CCO) 的 COM 注册表,以使用进程外 COM 服务器。 可以运行此脚本,确保所有 OPOS 服务对象都能够与 64 位应用程序互操作。 必须从管理员 Windows PowerShell 提示符运行脚本。
# This Windows PowerShell script modifies the COM registry for all OPOS
# Common Control Objects (CCO) so that they use out of process COM servers.
# This enables OPOS service objects to work with both 32-bit and 64-bit
# POS for .NET applications.
# .Synopsis
# Create-Regkey: This function creates a new key in the registry
function Create-Regkey {
param(
[string] $Key
)
if (!(test-path -path $Key -pathType container)) {
New-Item -path $Key -type container | Out-Null
}
}
# .Synopsis
# Set-RegEntry: This function creates a new registry key in the registry and
# creates a new value in the key.
function Set-RegEntry {
param(
[string] $Key,
[string] $Name,
[string] $PropertyType,
$Value
)
Create-RegKey -Key $Key
Remove-ItemProperty -Path $Key -Name $Name -ErrorAction SilentlyContinue
New-ItemProperty -Path $Key -Name $Name -PropertyType $PropertyType -Value $Value | Out-Null
}
# Iterate through all of the OPOS Common Control Objects, setting registry
# entries and values for each object.
for ($i = 2; $i -lt 38; $i++) {
$clsid = '{{CCB90{0:D2}2-B81E-11D2-AB74-0040054C3719}}' -f $i
Set-RegEntry -Key "hklm:\SOFTWARE\Classes\Wow6432Node\CLSID\$clsid" -Name 'AppID' -PropertyType String -Value $clsid
Set-RegEntry -Key "hklm:\SOFTWARE\Classes\Wow6432Node\AppID\$clsid" -Name 'DllSurrogate' -PropertyType String
Create-RegKey -Key "hklm:\SOFTWARE\Classes\AppID\$clsid"
}
If you need to revert the COM registry after running the previous script, you can run the following Windows PowerShell script to remove the new COM registry entries:
# This Windows PowerShell script restores the COM registry for all OPOS
# Common Control Objects (CCO) to their original values.
for ($i = 2; $i -lt 38; $i++) {
$clsid = '{{CCB90{0:D2}2-B81E-11D2-AB74-0040054C3719}}' -f $i
Remove-ItemProperty -Path "hklm:\SOFTWARE\Classes\Wow6432Node\CLSID\$clsid" -Name 'AppID'
Remove-Item -Path "hklm:\SOFTWARE\Classes\Wow6432Node\AppID\$clsid"
Remove-Item -Path "hklm:\SOFTWARE\Classes\AppID\$clsid"
}