首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未能为COM互操作包装器强制转换Marshal.GetActiveObject的结果

未能为COM互操作包装器强制转换Marshal.GetActiveObject的结果
EN

Stack Overflow用户
提问于 2013-05-01 04:41:57
回答 2查看 1.3K关注 0票数 0

我很难找到如何访问C++应用程序提供的COM接口,并从C# .NET应用程序中使用它。

我尝试从我的C#应用程序中访问COM对象(它是由正在运行的进程提供的),如下所示:

代码语言:javascript
复制
object obj = Marshal.GetActiveObject("MyLibrary.Application");
MyLibrary.IMainApp app = (MyLibrary.IMainApp)obj;

obj的值是非空的,但是当我试图转换它时,我得到了System.InvalidCastException

我尝试实现一个自定义包装器,并将其链接到TlbImp.exe生成的DLL中。两者都产生了同样的例外。

似乎有很多关于互操作的文档,但这对我来说没有意义--主要是因为我不懂COM--(我被困于维护别人开发的代码),我正一头扎进C#、.NET和WPF的可怕世界。

这是我在C++端的资料.

IDL文件

实际上,扩展是.odl。我不知道这是不是另一回事。请注意,我已经用GUID-1GUID-2等占位符替换了GUID.

代码语言:javascript
复制
import "oaidl.idl";

[ uuid(GUID-1), helpstring("My Type Library"), version(1.1) ]
library MyLibrary
{
    importlib("stdole32.tlb");

    //  Primary dispatch interface for CMainApp

    [ uuid(GUID-2) ]
    dispinterface IMainApp
    {
    properties:
        [id(1)] BOOL Mode;

    methods:
        [id(2)] void Quit();
        [id(3)] void LogEventMessage(BSTR szMessageType, BSTR szMessage);
        [id(4)] BOOL GetNoteDetails(BSTR szQualifiedName, BSTR* lpbstrOperator, DATE* lpdtDate);
    };

    //  Class information for CMainApp
    [ uuid(GUID-3) ]
    coclass Application
    {
        [default] dispinterface IMainApp;
    };
};

示例用法

当另一个C++应用程序想要调用一个函数(例如Quit)时,它们会这样做:

代码语言:javascript
复制
CLSID       clsid;
HRESULT     hr;
LPUNKNOWN   lpUnk;
LPDISPATCH  lpDisp;
BOOL        bReturn = FALSE;

// Get Class ID
if (CLSIDFromProgID( OLESTR("MyLibrary.Application"), &clsid ) == S_OK )
{
    // Get Active Object from ROT
    if ( ( hr = GetActiveObject( clsid, NULL, &lpUnk ) ) == S_OK )
    {
        hr = lpUnk->QueryInterface( IID_IDispatch, (LPVOID*)&lpDisp );
        lpUnk->Release();
        if ( hr == S_OK )
        {
            CMainApp oMainApp;
            oMainApp.AttachDispatch( lpDisp );

            TRY
            {
                oMainApp.Quit();
                bReturn = TRUE;
            }
            CATCH( CException, e )
            {
                bReturn = FALSE;
            }
            END_CATCH
        }
    }
}

CMainApp类似乎是由IDL编译器自动生成的。该文件被编译到希望使用它的项目中,基本上可以执行大量的InvokeHelper调用。我很高兴能接受这正是它的工作方式,我希望C#不是那么复杂。

试图包装在C#

我遵循了关于C#中COM互操作的MSDN指南。它暗示我可以使用TlbImp.exe,但它发出了足够多的警告,让我望而却步。另外,我不想再分发另一个DLL。所以我采取了另一种方法来编写一个包装器。

我就是这么写的:

代码语言:javascript
复制
using System.Runtime.InteropServices;

namespace MyLibrary
{
    // Declare MainApp COM coclass
    [ComImport, Guid("GUID-3")]
    class MainApp
    {
    }

    [Guid("GUID-2"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
    interface IMainApp
    {
        public void Quit();

        public void LogEventMessage(
            [In, MarshalAs(UnmanagedType.BStr)] string szMessageType,
            [In, MarshalAs(UnmanagedType.BStr)] string szMessage );

        public bool GetNoteDetails(
            [In, MarshalAs(UnmanagedType.BStr)] string szQualifiedName,
            [Out, MarshalAs(UnmanagedType.BStr)] out string lpbstrOperator );
            out DateTime lpdtDate );
    }
}

有人能帮我明白这一点吗?也许可以指出我犯了一个明显的愚蠢的错误?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-01 09:38:32

您的示例C++代码正在通过IDispatch使用后期绑定。这是正确的方法,您的COM服务器不支持早期绑定。从IDL中可以看出,它使用的是分配接口而不是接口。

C#中的等效方法是使用C# dynamic关键字。如下所示:

代码语言:javascript
复制
dynamic obj = Marshal.GetActiveObject("MyLibrary.Application");
obj.Quit();
票数 1
EN

Stack Overflow用户

发布于 2022-11-27 14:19:24

谢谢。我可以通过将ExcelWorkBook声明为动态来控制Excel中的每一项。

代码语言:javascript
复制
static void Main(string[] args)
    {
        Excel.Application oXL;
        Excel._Workbook AWB;
        Excel._Worksheet ASH;
        dynamic ExcelWorkbook;
        try
        {
            ExcelWorkbook = Marshal.GetActiveObject("Excel.Application");
            AWB = ExcelWorkbook.ActiveWorkBook;
            String naam = AWB.Name;
             ASH = AWB.ActiveSheet;
            oXL = ExcelWorkbook.Application();
            object theValue = oXL.get_Range("A1", "A1").Value2;
            ASH.Cells[1, 1] = "First Name";
            ASH.Cells[1, 2] = "second Name";
            ASH.Cells[1, 3] = "Third Name";
            ASH.get_Range("A1", "D1").Font.Bold = true;
        }
        catch { }
        String tekst="test";
     }
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16312837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档