【问题标题】:How do I invoke a COM method in C++ when the output parameter is a class?当输出参数是类时,如何在 C++ 中调用 COM 方法?
【发布时间】:2014-03-05 06:57:07
【问题描述】:

背景

我是一名 C# 开发人员,对 C++ 的经验几乎为零,而对 COM 的经验仅略多一点。我的同事是一名 C++ 开发人员,对 .Net 的使用经验几乎为零,而对 COM 的使用经验不多。我们正在尝试让他的 C++ MFC 应用程序使用我在 .Net 3.5 上用 C# 编写的 DLL。

我主要关注这个教程:http://www.codeproject.com/Articles/12673/Calling-Managed-NET-C-COM-Objects-from-Unmanaged-C

但是,我找不到任何返回对象而不是简单类型的 COM 接口示例。

DLL

在汇编级别我有ComVisible(false),因为在真正的 DLL 中有大量的类不会在 C++ 中使用。这让我可以在我希望在 COM 中显示的类和接口上使用 ComVisible(true)

using System;
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: ComVisible( false )]
[assembly: Guid( "59db8b2b-572d-42fc-83ae-36fe1a97695f" )]
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]

namespace ComTest
{
    [Guid( "9600F16D-2ECA-446C-83C9-B15FD472D12D" )]
    [ComVisible( true )]
    public interface ITestClass
    {
        ISerialInfo GetSerialInfo( string serial );
    }

    [Guid( "3C63AF8C-4730-4526-94C9-D8AA6805962A" )]
    [ComVisible( true )]
    [ClassInterface( ClassInterfaceType.None )]
    public class TestClass : ITestClass
    {
        public ISerialInfo GetSerialInfo( string serial )
        {
            //Other properties excluded for brevity.
            return new SerialInfo
            {
                SerialNumber = serial
            };
        }
    }

    [Guid( "F2885515-EEE8-49B1-B795-B92955EFEF0D" )]
    [ComVisible( true )]
    public interface ISerialInfo
    {
        string BomRevision { get; set; }
        string InteroperationStep { get; set; }
        bool IsValid { get; set; }
        string Job { get; set; }
        string JobSalesOrder { get; set; }
        int JobSalesOrderLine { get; set; }
        string MaterialStatus { get; set; }
        int OperationSequence { get; set; }
        string Organization { get; set; }
        string ParentSerialNumber { get; set; }
        string PartNumber { get; set; }
        string SerialNumber { get; set; }
        string State { get; set; }
    }

    [Guid( "D60020F1-823D-497E-A91D-427AEA1195C6" )]
    [ComVisible( true )]
    [ClassInterface( ClassInterfaceType.None )]
    public class SerialInfo : ISerialInfo
    {
        public bool IsValid { get; set; }
        public string SerialNumber { get; set; }
        public string Organization { get; set; }
        public string PartNumber { get; set; }
        public string Job { get; set; }
        public string BomRevision { get; set; }
        public string JobSalesOrder { get; set; }
        public int JobSalesOrderLine { get; set; }
        public int OperationSequence { get; set; }
        public string InteroperationStep { get; set; }
        public string ParentSerialNumber { get; set; }
        public string MaterialStatus { get; set; }
        public string State { get; set; }
    }
}

COM 注册

我使用以下批处理文件为 COM 注册 DLL 并生成 TLB 文件。

"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil" /i ComTest.dll
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" ComTest.dll /tlb:ComTest.tlb

TLH 文件片段

virtual HRESULT __stdcall GetSerialInfo (
        /*[in]*/ BSTR serial,
        /*[out,retval]*/ struct ISerialInfo * * pRetVal ) = 0;

MFC 应用程序

我不知道为这个方法的输出参数传递什么。我已经尝试了几件事,我可以构建它,但不能运行。我不知道我是否必须实例化一个具体的 TestClass 然后将它转换为一个接口并传递一个指向它的指针,或者什么。我在这里不知所措。我做了很多谷歌搜索,但找不到任何示例显示 COM 返回的不仅仅是字符串或整数。如果我的方法返回一个 int,我可以让它正常工作。

我已排除所有样板代码。

#import "C:\\Users\\Glazed\\Documents\\Visual Studio 2012\\Projects\\ComTest\\ComTest\\bin\\Debug\\ComTest.tlb" named_guids raw_interfaces_only

CMainFrame::CMainFrame()
{
    CoInitialize(NULL);

    ComTest::ITestClassPtr testClassPtr;

    HRESULT hRes = testClassPtr.CreateInstance(ComTest::CLSID_TestClass);

    if (hRes == S_OK)
    {
        //What goes here to initialize an entity to pass into the following method

        testClassPtr->GetSerialInfo( L"TE-006",  );
    }

    CoUninitialize();
}

【问题讨论】:

    标签: c# c++ dll com mfc


    【解决方案1】:

    你需要一个指向对象的指针。看起来有一堆通过#import 进行的包装,所以看起来合适的类应该是ComTest::ISerialInfoPtr

    if (hRes == S_OK)
    {
        ComTest::ISerialInfoPtr pInfo;
        hRes = testClassPtr->GetSerialInfo( L"TE-006", &pInfo);
    }
    

    【讨论】:

    • 谢谢!那行得通。我可以调试 DLL 项目并让它运行 C++ EXE 并且我的断点被命中。但是,输入参数“serial”以空字符串的形式出现,而不是“TE-006”。我不认为你对此也有同样简单的答案。 :) imgur.com/q84imEZ 我更改了返回常量“Testing”的方法,现在我可以在 C++ 中看到了。
    • 我想通了。我需要使用 ATL::CComBSTR 的一个实例。即ATL::CComBSTR serialInput = L"TE-006";
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 2019-07-21
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多