C++ 接口问题使用 .NET POS SDK 进行 POS 控制

发布于 2024-08-12 04:27:39 字数 4419 浏览 7 评论 0 原文

我们正在尝试实现一个支持 COM 接口来模拟 POSPrinter 但仍与旧技术兼容的 .NET 服务对象。

我们的接口和类对象位于以下类中。

using [...]

namespace yRPOSPrinterDotNet
{
    [Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface yRPosPrinterCOM
    {

        long Open(String DeviceName);
        long PrintNormal(long Station, String Data);

    }

    [Guid("478176F4-5105-435c-8EBC-D4CB90B7B1C7")]
    [ClassInterface(ClassInterfaceType.None)]
    //[ProgId("yRPOSPrinterDotNet.POSPrinter")] //will be set automatically as the progid <namespace><clsid>
    public class POSPrinter : yRPosPrinterCOM
    {

        #region yRPosPrinterCOM Members
        public long Open()
        {
            return 0;
        }

        public long Open(String DeviceName)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
            FileStream objStream = new FileStream("C:\\yRPOSLog.txt", FileMode.OpenOrCreate);
            TextWriterTraceListener objTraceListener = new TextWriterTraceListener(objStream);
            Trace.Listeners.Add(objTraceListener);
            Trace.AutoFlush = true;
            Trace.Indent();
            Trace.WriteLine("Entering Main");
            Debug.WriteLine("How does this one do??");
            Console.WriteLine("Hello World.");
            Trace.WriteLine("Exiting Main");
            Trace.Unindent();
            return 0;
        }


        public long PrintNormal(long Station, string Data)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

}

并将我们的 yRPosPrinterDotNet.POSPrinter ProgID 放入 HKEY_LOCAL_MACHINE\SOFTWARE\OLEforRetail\ServiceOPOS\POSPrinter\yReceipts

HKEY_CLASSES_ROOT\CLSID\{478176F4- 5105-435C-8EBC-D4CB90B7B1C7} 在构建后正确地具有我们的 ProgID (yRPosPrinterDotNet.POSPrinter)

我们可以使用此类通过测试类调用 DLL,如下所示(查找 ProgID)

using [...]

namespace TestYRPosPrinterDotNet
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTest1
    {
        public UnitTest1()
        {

        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        [TestMethod]
        public void TestMethod1()
        {
            String sProgID = "yRPosPrinterDotNet.POSPrinter";
            // We get the type using just the ProgID
            Type oType = Type.GetTypeFromProgID(sProgID);
            if (oType != null)
            {
               POSPrinter pp = (POSPrinter)Activator.CreateInstance(oType);
               long retVal = pp.Open("Nothing");
            }

        }
    }
}

但是当我们尝试通过示例 TestApp 调用时(它确实显示为服务对象)

{"Method Open threw an exception.  The service object does not support one or more of the methods required by its release."} System.Exception {Microsoft.PointOfService.PosControlException}

通过示例 C++ 控制对象,我们收到在 opos.h 中定义为 (const LONG OPOS_E_NOSERVICE = 4 + OPOSERR;) 的 104,其堆栈跟踪如下

----------------------------------- Doesn't work --------------------------------------------------------

 POSPrinterExample.exe!COleDispatchDriver::InvokeHelperV(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, char * argList=0x0012f110)  Line 

397 C++
 POSPrinterExample.exe!COleControlSite::InvokeHelperV(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, char * argList=0x0012f10c)  Line 1093 

C++
  POSPrinterExample.exe!CWnd::InvokeHelper(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, ...)  Line 382 C++
  POSPrinterExample.exe!COPOSPOSPrinter::Open(const char * DeviceName=0x00271f00)  Line 192 + 0x1c bytes C++

We're trying implement a .NET Service Object that supports a COM interface to emulate a POSPrinter but still be compatible with the older technologies.

We have our interface and class object in the following class..

using [...]

namespace yRPOSPrinterDotNet
{
    [Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface yRPosPrinterCOM
    {

        long Open(String DeviceName);
        long PrintNormal(long Station, String Data);

    }

    [Guid("478176F4-5105-435c-8EBC-D4CB90B7B1C7")]
    [ClassInterface(ClassInterfaceType.None)]
    //[ProgId("yRPOSPrinterDotNet.POSPrinter")] //will be set automatically as the progid <namespace><clsid>
    public class POSPrinter : yRPosPrinterCOM
    {

        #region yRPosPrinterCOM Members
        public long Open()
        {
            return 0;
        }

        public long Open(String DeviceName)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
            FileStream objStream = new FileStream("C:\\yRPOSLog.txt", FileMode.OpenOrCreate);
            TextWriterTraceListener objTraceListener = new TextWriterTraceListener(objStream);
            Trace.Listeners.Add(objTraceListener);
            Trace.AutoFlush = true;
            Trace.Indent();
            Trace.WriteLine("Entering Main");
            Debug.WriteLine("How does this one do??");
            Console.WriteLine("Hello World.");
            Trace.WriteLine("Exiting Main");
            Trace.Unindent();
            return 0;
        }


        public long PrintNormal(long Station, string Data)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

}

And put inside HKEY_LOCAL_MACHINE\SOFTWARE\OLEforRetail\ServiceOPOS\POSPrinter\yReceipts our ProgID of yRPosPrinterDotNet.POSPrinter

HKEY_CLASSES_ROOT\CLSID\{478176F4-5105-435C-8EBC-D4CB90B7B1C7} has our ProgID correctly after building (yRPosPrinterDotNet.POSPrinter)

We can call the DLL through a test class as follow (finding the ProgID) using this class

using [...]

namespace TestYRPosPrinterDotNet
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTest1
    {
        public UnitTest1()
        {

        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        [TestMethod]
        public void TestMethod1()
        {
            String sProgID = "yRPosPrinterDotNet.POSPrinter";
            // We get the type using just the ProgID
            Type oType = Type.GetTypeFromProgID(sProgID);
            if (oType != null)
            {
               POSPrinter pp = (POSPrinter)Activator.CreateInstance(oType);
               long retVal = pp.Open("Nothing");
            }

        }
    }
}

But when we try calling through sample TestApp (it does show up as a serviceObject)

{"Method Open threw an exception.  The service object does not support one or more of the methods required by its release."} System.Exception {Microsoft.PointOfService.PosControlException}

Through a Sample C++ Control Object we receive a 104 defined in opos.h as (const LONG OPOS_E_NOSERVICE = 4 + OPOSERR;) with the following stack trace

----------------------------------- Doesn't work --------------------------------------------------------

 POSPrinterExample.exe!COleDispatchDriver::InvokeHelperV(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, char * argList=0x0012f110)  Line 

397 C++
 POSPrinterExample.exe!COleControlSite::InvokeHelperV(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, char * argList=0x0012f10c)  Line 1093 

C++
  POSPrinterExample.exe!CWnd::InvokeHelper(long dwDispID=37, unsigned short wFlags=1, unsigned short vtRet=3, void * pvRet=0x0012f1e0, const unsigned char * pbParamInfo=0x00702014, ...)  Line 382 C++
  POSPrinterExample.exe!COPOSPOSPrinter::Open(const char * DeviceName=0x00271f00)  Line 192 + 0x1c bytes C++

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄居者 2024-08-19 04:27:40

这似乎是一个DispInterface。为了支持 Visual Basic,这是一个可怕的 COM 黑客攻击。基本上,所有功能都已编号。第一次调用时,将查找并缓存所有函数号。例如,您似乎缺少 Close() 函数。正如您所看到的,这将导致它查找失败。

引自《OLE for Retail POS Control Guide - Rel. 1.1》:

  • 通过调用查找所有服务对象方法的调度 ID
    服务对象实例的
    m_lpDispatch → GetIDsOfNames 函数。
    更新生成的服务对象
    将这些调度 ID 传递给的方法
    InvokeHelper 成员函数。如果
    任何所需的调度 ID 都是
    在服务对象中找不到,那么
    关闭调度界面并
    返回 OPOS_E_NOSERVICE。
  • This seems to be a DispInterface. That's a horrible COM hack to support Visual Basic. Basically, all functions are numbered. On the first call, all function numbers are looked up and cached. It seems you are missing the Close() function, for instance. This would cause it to fail in lookup, in the way you see.

    Quoting from "OLE for Retail POS Control Guide - Rel. 1.1" :

    1. Look up the dispatch IDs for all of the Service Object methods by calling
      the Service Object instance’s
      m_lpDispatch  GetIDsOfNames function.
      Update the generated Service Object
      methods to pass these dispatch IDs to
      the InvokeHelper member function. If
      any of the required dispatch IDs are
      not found in the Service Object, then
      close the dispatch interface and
      return OPOS_E_NOSERVICE.
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文