调用托管 DLL 时 COM 互操作抛出 EEMessageException

发布于 2024-11-18 15:12:39 字数 3165 浏览 1 评论 0原文

COM 互操作对我来说是一场噩梦。我有一个简单的托管 DLL,其中包含一个 WPF 窗口。我有一个简单的 ViewController 类,最终将启动此窗口,但现在有一个不执行任何操作的空方法。

我为此托管 DLL 创建了一个托管包装器,它公开了为 COM 互操作注册的接口。我可以调用我的托管包装器了。我可以在托管包装 DLL 的入口点显示 MessageBox。但是,如果我尝试在正在包装的 DLL 中调用此 ViewController 类上的任何方法,则会收到以下消息:

MfcVSApp1.exe 中 0x7c812aeb (kernel32.dll) 处的首次机会异常:Microsoft C++ 异常:内存位置 0x0012cb30 处的 EEMessageException。昨天

显然一切都有效。现在一些代码:

我的包装器实体:

[Guid("83C799E0-9808-40c2-A1AB-80BCB77A3B18")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [ComVisible(true)]
    public interface IMaryln
    {
        void GetEphemeris(DateTime date, double latitude, double longitude);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="date"></param>
        /// <param name="latitude"></param>
        /// <param name="longitude"></param>
        void GetEphemeris1(Int64 millSecsSince1970, double latitude, double longitude);
    }

 [Guid("144DB386-D8EF-41a8-B9B1-57EE8A64600C")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("ManagedProxy.Maryln")]
    [ComVisible(true)]
    public class Maryln : IMaryln
    {
        #region IMaryln Members

        public Maryln()
        {
            System.Diagnostics.Debugger.Launch();
        }

        public void GetEphemeris(DateTime date, double latitude, double longitude)
        {
            //new EphemerisViewController().GetEphemeris(date, latitude, longitude);
        }

        public void GetEphemeris1(Int64 nanoSecsSince1970, double latitude, double longitude)
        {
            // This method does not throw.  However, it will not be executed
            // if any method in EphemerisViewController is called.
            MessageBox.Show("Called from c++" + nanoSecsSince1970.ToString());


            try
            {
                //new Maryln().Test();    // this will not throw
                new EphemerisViewController().GetString();   // this will 
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }                              
        }

        public void Test()
        {
            MessageBox.Show("maryln test");
        }

        #endregion
    }

由托管包装器 DLL 引用的托管 DLL 包含一个 UserControl 和此 ViewController:

public class EphemerisViewController
    {      
        public EphemerisViewController()
        {          
        }                 

        public void GetString()
        {
            MessageBox.Show("me");
        }

    }

此 DLL 也已注册用于 COM 互操作,但后来我取消选中该选项,因为它没有帮助。船上的大师们,我需要帮助。这已经消耗了两个工作日,而且我已经从开始的地方后退了 3 步。昨天一切都有效。

添加

本机客户端正在使用我的包装器,如下所示:

void CMfcVSApp1Doc::LaunchEphemrisDialog()
{   
    HRESULT hr;
    CoInitialize(NULL);
    try 
    {               
        ManagedProxy::IMarylnPtr maryln(__uuidof(ManagedProxy::Maryln));    
        LONG64 time = 1309897499216000000;
        hr = maryln->GetEphemeris1(time, 0, 0);
    }
    catch(...)
    {

    }
}

此外,我已经多次清理和重建解决方案,但没有运气。

What a nightmare COM interop is proving to me. I have a simple managed DLL containing a WPF window. I have a simple ViewController class that will eventually be launching this window but for now has an empty method that does nothing.

I have created a managed wrapper for this managed DLL, that exposes an interface registered for COM interop. I can call into my managed wrapper OK. I can display a MessageBox in the entry point of my managed wrapper DLL. However, if I attempt to call ANY method on this ViewController class in the DLL I am wrapping, I get this:

First-chance exception at 0x7c812aeb (kernel32.dll) in MfcVSApp1.exe: Microsoft C++ exception: EEMessageException at memory location 0x0012cb30..

It all worked yesterday apparently. Now some code:

My wrapper entities:

[Guid("83C799E0-9808-40c2-A1AB-80BCB77A3B18")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [ComVisible(true)]
    public interface IMaryln
    {
        void GetEphemeris(DateTime date, double latitude, double longitude);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="date"></param>
        /// <param name="latitude"></param>
        /// <param name="longitude"></param>
        void GetEphemeris1(Int64 millSecsSince1970, double latitude, double longitude);
    }

 [Guid("144DB386-D8EF-41a8-B9B1-57EE8A64600C")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("ManagedProxy.Maryln")]
    [ComVisible(true)]
    public class Maryln : IMaryln
    {
        #region IMaryln Members

        public Maryln()
        {
            System.Diagnostics.Debugger.Launch();
        }

        public void GetEphemeris(DateTime date, double latitude, double longitude)
        {
            //new EphemerisViewController().GetEphemeris(date, latitude, longitude);
        }

        public void GetEphemeris1(Int64 nanoSecsSince1970, double latitude, double longitude)
        {
            // This method does not throw.  However, it will not be executed
            // if any method in EphemerisViewController is called.
            MessageBox.Show("Called from c++" + nanoSecsSince1970.ToString());


            try
            {
                //new Maryln().Test();    // this will not throw
                new EphemerisViewController().GetString();   // this will 
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }                              
        }

        public void Test()
        {
            MessageBox.Show("maryln test");
        }

        #endregion
    }

The Managed DLL, referenced by the managed wrapper DLL, contains a UserControl and this ViewController:

public class EphemerisViewController
    {      
        public EphemerisViewController()
        {          
        }                 

        public void GetString()
        {
            MessageBox.Show("me");
        }

    }

This DLL was also registered for COM interop but then I unchecked that option as it did not help matters. Gurus on board, I need help here. This has consumed two working days already and I have taken 3 steps back from where I started. It all worked yesterday.

Addition

The native client is consuming my wrapper as follows:

void CMfcVSApp1Doc::LaunchEphemrisDialog()
{   
    HRESULT hr;
    CoInitialize(NULL);
    try 
    {               
        ManagedProxy::IMarylnPtr maryln(__uuidof(ManagedProxy::Maryln));    
        LONG64 time = 1309897499216000000;
        hr = maryln->GetEphemeris1(time, 0, 0);
    }
    catch(...)
    {

    }
}

Also, I have cleaned and rebuilt solution numerous times but no luck.

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

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

发布评论

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

评论(1

聊慰 2024-11-25 15:12:39

不知道这里发生了什么,但我决定放弃这个包装 DLL 并从头开始创建一个新的。我没有更改我正在包装的 C# 项目,只是为了看看这两个项目中哪一个导致了问题。仅凭这一行为,我就可以调试所包装的 C# 项目中公开的每个 API。使用 Hans P 建议的项目调试技术,我能够进一步调试我的包装器 DLL。看到托管异常,我松了一口气。绝对是向前迈出了一步。

事实证明,每次调用 EphemerisViewController 中的包装 API 都会引发管理异常,无法找到依赖项(定位的程序集清单与加载的程序集不匹配......等等......等等)。我们都知道造成这种情况的原因。

清理程序集引用从而消除上述错误后,我可以再次调用我的托管 DLL。一只手就浪费了一天的时间。另一方面学到了很多东西。为什么原来的包装器停止工作超出了我的理解范围,但我很高兴放弃它。这是命名空间损坏和 DLL 加载问题的结合,但谁知道呢。

我正准备放弃 COM 互操作并投入 MFC,但是天哪,我很高兴我坚持了自己的立场。就我而言,与 C# 相比,C++ 开发很糟糕。例如,与 C++ 中的 catch(...) 等效项相比,能够在 C# 中捕获一般异常是一个很大的好处。所有疯狂的 C++ 语法和执行简单转换的令人头疼的例程都让我头晕。别说Intellisense了,哦intellisense。过期的虚拟助手许可证每天都会提醒我它处于休眠状态,而且公司预算紧张,我会坚持使用 C# 一段时间,也许在所有这些完成后考虑研究 Boost 等 C++ 库,以防万一。但是,我很高兴回到 .NET。

我在这里学到的教训是:使用 COM 互操作,您必须密切关注细节!

Do not know what may have happened here but I decided to ditch this wrapper DLL and create a new one from scratch. I did not change the C# project I was wrapping just to see which of these two projects was causing the problem. This act alone somehow allowed me to debug each of the APIs exposed in the C# project being wrapped. Using the project debug technique suggested by Hans P, I was able to further debug my wrapper DLL. I gave a big sigh of relieve just being able to see a managed exception. Definitely a step forward.

It turned out that each call to a wrapped API in EphemerisViewController was throwing a manage exception that a dependency could not be found (located assembly manifest does not match loaded assembly....blah..blah.). We all know what causes this.

After cleaning assembly references thereby eliminating the aforementioned error, I could then call my managed DLL again. A day wasted on one hand. A lot learnt on the other hand. Why the original wrapper stopped working is beyond my comprehension but I am glad to let that go. it have have been a combination of namespace corruption and DLL loading issues but who knows.

I was getting ready to ditch COM interop and dive into MFC but boy, i am glad I stuck to my guns. Compared to C#, C++ development sucks as far as i am concerned. For example just being able to catch a general Exception in C# as apposed to the catch(...) equivalent we have for C++ is a serious benefit. All the crazy c++ syntax and head scratching routines to perform simple conversions make my head spin. Not to mention Intellisense, oh intellisense. With a expired Virtual Assist license that reminds me everyday it is laying dormant, and a tight corporate budget, I will stick to C# for a while maybe with thoughts on investigating C++ libraries like Boost when all of this is done, just in case. But boy, I am happy to get back into .NET.

Lesson learnt here for me is: with COM interop, you have to pay close attention to the details!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文