实现用于捕获打印文本的OPOS打印机服务对象
本文关键字:OPOS 打印机 服务 对象 文本 用于 打印 实现 | 更新日期: 2023-09-27 18:05:58
我们正在尝试为POS应用程序创建类似打印机驱动程序包装的东西,这将允许我们捕获打印的收据,然后将其再次转发到原始打印机。
到目前为止,我们在"。net的POS"之上实现了一个服务对象,它工作得很好,但事实证明一些遗留的POS应用程序只支持OPOS。为了支持它们,我们要么必须使我们的"。net的POS"服务对象作为OPOS服务对象可用,要么我们必须使用CCOs编写我们自己的OPOS服务对象。我的问题是:
- 在这些遗留的POS应用程序中,甚至可以使用我们的POS for .Net解决方案吗?(如果是,如何?)
- 如何构建OPOS服务对象?是否可以使用。net框架(例如c#)?
- 我们在做正确的事情吗?有没有更好的方法来捕获收据(特别是对于这些遗留应用程序)?
Q)在这些遗留POS应用程序中,甚至可以使用我们的POS for .Net解决方案吗?
A)不,这些应用程序不使用。net库的POS,也不使用。net注册表项的POS来搜索服务对象,这些应用程序只使用OPOS(OLE POS)注册表项来搜索注册的服务对象,并且通常调用CCO,后者反过来调用服务对象。Q)如何构建OPOS服务对象?是否可以使用。net框架(例如c#)?
A)是的,它可以使用。net来完成,但是你需要将它暴露为一个COM库,一个好方法是实现CCO中的接口,每个设备都有一个DLL,引用你需要的设备,实现它的接口,并将你的类型标记为COM可见,添加GUID和ProgId,使用regasm " path "/register/codebase/tlb命令注册它,添加所需的注册表键可以在好的规范'开发指导文档,您将完成,或至少我认为,这个你会得到一个错误,指出有缺失的方法从服务对象所需的正确运行它,我发现了这个困难的方式,但有7中引用方法不是好的规范中引用接口——尽管'开发指南文档——这些方法是:
- COFreezeEvents:与属性FreezeEvents相同。
- GetPropertyNumber:用于通过属性的索引获取数值'布尔属性的值,稍后将详细介绍。
- SetPropertyNumber:用于通过属性的索引设置数值'布尔属性的值,稍后会详细介绍。
- GetPropertyString:用于通过属性的索引获取字符串属性的值,稍后将详细介绍。
- SetPropertyString:用于通过属性的索引设置字符串属性的值,稍后会详细介绍。
- OpenService:与open方法相同。
- CloseService:与close方法相同。
在实现这些方法之后,一切都很好,这很奇怪,因为没有一个在CCO接口中被引用,但是正如我所说的,这些方法都在UPOS规范中被引用,并且有一个完整的描述。
似乎OpenService和CloseService方法存在的原因是,当CCO库被实现为com时,Open和Close方法名称不合适,必须更改为OpenService和CloseService,同样适用于Claim和Release,新名称ClaimDevice和Release Device -然而这些在接口中正确暴露,至于其他方法,我找不到原因。
Get'Set Property Methods
这4个方法用于访问对象中的所有属性,为什么?我不确定,但似乎应该从Dispatch接口使用这些来访问您的对象,为什么默认情况下该接口不可用?c++服务对象是否以相同的方式实现?我没有答案。
要以正确的方式实现这些,应该查看OPOS安装- CCO安装下的Include目录,并勾选*。hi文件,主要是操作系统。大家好,OposPtr。hi(取决于设备,在我们的例子中是打印机),您将看到这些包括CCO常量,如成功或失败枚举,以及这4种方法的属性索引和设备索引偏移量。
使用OPOS常量中的数字,您只需要打开PropIndex参数值,并获得'设置正确的属性值。
if (PropertyIndexHelper.IsStringPidx(PropIndex))
{
switch (PropIndex)
{
case PropertyIndexHelper.PIDX_CheckHealthText:
return _physicalPrinter.CheckHealthText;
case PropertyIndexHelper.PIDX_DeviceDescription:
return _physicalPrinter.DeviceDescription;
case PropertyIndexHelper.PIDX_DeviceName:
return _physicalPrinter.DeviceName;
.
.
.
.
.
为了进一步回答MEYWD的问题,我只是想发布c#中的基本接口应该是什么样子。
[ComVisible(true), Guid("Put a GUID here")]
public interface IMSR
{
//Common Opos
[DispId(0x01)]
int CheckHealth([In] int lLevel);
[DispId(0x02)]
int ClaimDevice([In] int lTimeOut);
[DispId(0x03)]
int ClearInput();
[DispId(0x04)]
int ClearInputProperties();
[DispId(0x05)]
int ClearOutput();
[DispId(0x06)]
int CloseService();
[DispId(0x07)]
int COFreezeEvents([In, MarshalAs(UnmanagedType.VariantBool)] bool Freeze);
[DispId(0x08)]
int CompareFirmwareVersion([In, MarshalAs(UnmanagedType.BStr)] string FirmwareFileName, [In, Out]ref int pResult);
[DispId(0x09)]
int DirectIO([In] int lCommand, [In, Out] ref int pData, [In, Out, MarshalAs(UnmanagedType.BStr)] ref string pString);
[DispId(0x0A)]
int OpenService([In, MarshalAs(UnmanagedType.BStr)] string lpclDevClass, [In, MarshalAs(UnmanagedType.BStr)] string lpclDevName, [In, MarshalAs(UnmanagedType.IDispatch)] object lpDispatch);
[DispId(0x0B)]
int ReleaseDevice();
[DispId(0x0C)]
int ResetStatistics([In, MarshalAs(UnmanagedType.BStr)] string StatisticsBuffer);
[DispId(0x0D)]
int RetrieveStatistics([In, Out, MarshalAs(UnmanagedType.BStr)] ref string pStatisticsBuffer);
[DispId(0x0E)]
int UpdateFirmware([In, MarshalAs(UnmanagedType.BStr)] string FirmwareFileName);
[DispId(0x0F)]
int UpdateStatistics([In, MarshalAs(UnmanagedType.BStr)] string StatisticsBuffer);
[DispId(0x10)]
int GetPropertyNumber([In] int lPropIndex);
[DispId(0x11)]
string GetPropertyString([In] int lPropIndex);
[DispId(0x12)]
void SetPropertyNumber([In] int lPropIndex, [In] int nNewValue);
[DispId(0x13)]
void SetPropertyString([In] int lPropIndex, [In, MarshalAs(UnmanagedType.BStr)] string StringData);
//MSR Specific
[DispId(0x14)]
int AuthenticateDevice([In, MarshalAs(UnmanagedType.BStr)] string deviceResponse);
[DispId(0x15)]
int DeauthenticateDevice([In, MarshalAs(UnmanagedType.BStr)] string deviceResponse);
[DispId(0x16)]
int RetrieveCardProperty([In, MarshalAs(UnmanagedType.BStr)] string propertyName, [Out, MarshalAs(UnmanagedType.BStr)] out string cardProperty);
[DispId(0x17)]
int RetrieveDeviceAuthenticationData([In, Out, MarshalAs(UnmanagedType.BStr)] ref string challenge);
[DispId(0x18)]
int UpdateKey([In, MarshalAs(UnmanagedType.BStr)]string key,[In, MarshalAs(UnmanagedType.BStr)] string keyName);
[DispId(0x19)]
int WriteTracks([In] object data,[In] int timeout);
}
假定这是针对MSR的,但是CommonOPOS方法在所有类型的设备上都是相同的。所以你唯一需要改变的是从DispID 0x14(20)到下。我所做的是与OPOS文档的签名进行比较,并将其转换为c#。我已经用这种方式创建了大约6个SO,并且在各种不同的场景中都工作得很好。
另一个注意事项是在OpenService方法中。您将看到最后一个参数是一个对象。这是Control对象的实例。您需要做的是在项目中创建另一个接口,为您公开COM对象。按照我的MSR的例子,这里是你应该写的。[ComImport, Guid("CCB91121-B81E-11D2-AB74-0040054C3719"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface COPOSMSR
{
void SOData([In] int Status);
void SODirectIO([In] int EventNumber, [In, Out] ref int pData, [In, Out, MarshalAs(UnmanagedType.BStr)] ref string pStrIng);
void SOError([In] int ResultCode, [In] int ResultCodeExtended, [In] int ErrorLocus, [In, Out] ref int pErrorResponse);
void SOOutputCompleteDummy([In] int OutputID);
void SOStatusUpdate([In] int Data);
void SOProcessID([Out] out int pProcessID);
}
I是OPOS源代码中的签名。如果你搜索源代码,你会看到像这样的小注释。(来自msr OPOS源代码),这样你就知道要实现什么,这样你就可以触发事件。
c: '程序文件(x86) '详细' oposSrc ' zMSR ' MSR.idl
[
object,
uuid(CCB91121-B81E-11D2-AB74-0040054C3719),
dual,
helpstring("IOPOSMSR 1.5 Interface"),
pointer_default(unique)
]
interface IOPOSMSR_1_5 : IDispatch
{
// Methods for use only by the Service Object
[id(1), hidden, helpstring("method SOData")] HRESULT SOData( [in] long Status );
[id(2), hidden, helpstring("method SODirectIO")] HRESULT SODirectIO( [in] long EventNumber, [in, out] long* pData, [in, out] BSTR* pString );
[id(3), hidden, helpstring("method SOError")] HRESULT SOError( [in] long ResultCode, [in] long ResultCodeExtended, [in] long ErrorLocus, [in, out] long* pErrorResponse );
[id(4), hidden, helpstring("method SOOutputCompleteDummy")] HRESULT SOOutputCompleteDummy( [in] long OutputID );
[id(5), hidden, helpstring("method SOStatusUpdate")] HRESULT SOStatusUpdate( [in] long Data );
[id(9), hidden, helpstring("method SOProcessID")] HRESULT SOProcessID( [out, retval] long* pProcessID );
有了这两个基本的东西,你就可以做一个SO..启动一个活动也非常容易。下面是我的测试方法
public int OpenService(string lpclDevClass, string lpclDevName, object lpDispatch)
{
controlObject = (COPOSMSR)lpDispatch;
controlObject.SOData(1)//I just fired a Data Event
}
根据我的经验,在c++中构建SO比在c#中更难。c#让更多的步骤变得超级简单。
一些很好的读物,这对我来说已经足够了。
COM互操作Part1: c#客户端教程
http://msdn.microsoft.com/en-us/library/aa645736 (v = vs.71) . aspx
COM互操作第2部分:c# Server教程
http://msdn.microsoft.com/en-us/library/aa645738 (v = vs.71) . aspx
COM数据类型
https://msdn.microsoft.com/en-us/library/sak564ww%28v=vs.100%29.aspx