无效变体崩溃

发布于 2024-07-29 07:54:26 字数 1354 浏览 8 评论 0原文

我遇到过这样的情况:我用 C++/CLI 包装了 Native C++ DLL,以便最终在 C# 中使用。

有一些回调函数在运行时会导致一些问题。 特别是,我得到以下异常:

未处理的类型异常 'System.Runtime.InteropServices.InvalidOleVariantTypeException' 发生在ToadWrapTest.dll

附加信息:指定的 OLE 变体无效。

在这行代码 (C++/CLI) 上:

public delegate int ManagedCallbackFunction (Object^ inst, const Object^ data);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

ManagedCallbackFunction^ m_callbackFn;

int intermidiaryCallback(void * pInstance, const void * pData)
    {   
        void* temp = (void*)pData;
        System::IntPtr ip1 = IntPtr(pInstance);
        System::IntPtr ip2 = IntPtr(temp);
        Object^ oInst = Marshal::GetObjectForNativeVariant(ip1);
        Object^ oData = Marshal::GetObjectForNativeVariant(ip2);
        //invoke the callback to c#
        //return m_callbackFn::Invoke(oInst, oData);
        return 0;
    };

我进行此“中间回调”的原因是试图规避当我尝试将委托从 C# 直接映射到本机 C++ 代码时引发的 Invalid Variable 异常。 作为尝试的解决方法,我在 C# 端声明一个委托并将该 funcptr 传递给 C++/CLI 包装器。 然后,我将中间 funcptr 传递给本机 C++,并将这些调用以菊花链方式连接在一起。

我所知道的是,这一切都适用于本机 C++ 世界。 问题是将 void* 映射到托管世界。 以下代码显示了回调的本机 C++ 版本:

int (*CallbackFunction) (void *inst, const void *data);

如果有人可以在这里提供帮助,我将非常感激。

I have a situation where I've wrapped a Native C++ DLL with C++/CLI for eventual use in C#.

There are a few callback functions that are causing some issues at run time. Particularly, I get the following exception:

An unhandled exception of type
'System.Runtime.InteropServices.InvalidOleVariantTypeException'
occurred in ToadWrapTest.dll

Additional information: Specified OLE
variant is invalid.

On this line of code (C++/CLI):

public delegate int ManagedCallbackFunction (Object^ inst, const Object^ data);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

ManagedCallbackFunction^ m_callbackFn;

int intermidiaryCallback(void * pInstance, const void * pData)
    {   
        void* temp = (void*)pData;
        System::IntPtr ip1 = IntPtr(pInstance);
        System::IntPtr ip2 = IntPtr(temp);
        Object^ oInst = Marshal::GetObjectForNativeVariant(ip1);
        Object^ oData = Marshal::GetObjectForNativeVariant(ip2);
        //invoke the callback to c#
        //return m_callbackFn::Invoke(oInst, oData);
        return 0;
    };

The reason I've made this "intermediary callback" was an attempt to circumvent the Invalid variant exception being thrown when I tried to directly map the delegate from C# to the native C++ code. As an attempted work-around, I declare a delegate on the C# side and pass that funcptr to the C++/CLI wrapper. I then pass the intermediary funcptr to the native C++ and just daisy chain the calls together.

What I know is that it all works in native C++ world. The problem is mapping the void* to the managed world. The following code shows the native C++ version of the callback:

int (*CallbackFunction) (void *inst, const void *data);

If anyone can help here, I'd really appreciate it.

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

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

发布评论

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

评论(2

暮光沉寂 2024-08-05 07:54:26

pInstance 和 pData 真的是 VARIANT 吗? 如果是,我希望您的回调函数具有更强的类型:

int (*CallbackFunction)(VARIANT *inst, VARIANT *data);

如果是这种情况,在您的代码中您应该能够查看实际的 VARIANT 手动检查它。 如果您没有真正获得 VARIANT(即,您实际上只是获得 void * 指针),则不应尝试将它们转换为 C# 对象,因为它们没有固有的含义。 它们应该作为 IntPtr 传递。 如果您知道它们应该具有某种其他类型的固有含义,则需要将它们编组为适当的类型。

Are pInstance and pData really VARIANT? If they are, I would expect your callback function to be more strongly typed:

int (*CallbackFunction)(VARIANT *inst, VARIANT *data);

If that's the case, in your code you should be able to look at the actual VARIANT to hand check it. If you are not really getting VARIANTs (ie, you are really just getting void * pointers), you shouldn't try to turn them into C# objects since there is no inherent meaning to them. They should get passed through as IntPtr. If you know that they should have some other type of inherent meaning, you need to marshal them as appropriate types.

⒈起吃苦の倖褔 2024-08-05 07:54:26

非常感谢这个底座! 我将下面的最终解决方案发布给任何其他必须处理像这样的第 3 方乐趣的人! 请随意批评,因为我还没有完成代码优化。 这可能仍然是一种迂回的解决方案。

首先,回调函数变成了:

public delegate int ManagedCallbackFunction (IntPtr oInst, IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
ManagedCallbackFunction^ m_callbackFn;

这个函数的重要支撑。 如果您尝试从 void* 直接转换为 Object^,那么它显然不起作用。 使用 IntPtr 和我的中间回调:

int intermidiaryCallback(void * pInstance, const void * pData)
{   
    void* temp = (void*)pData;
    return m_callbackFn->Invoke(IntPtr(pInstance), IntPtr(temp));
};

我们最终在 C# 端获得了一个工作模型,并对对象进行了一些按摩:

public static int hReceiveTestMessage(IntPtr pInstance, IntPtr pData)
{
   // provide object context for static member function
   helloworld2 hw = (helloworld2)GCHandle.FromIntPtr(pInstance).Target;
   if (hw == null || pData == null)
   {
      Console.WriteLine("hReceiveTestMessage received NULL data or instance pointer\n");
      return 0;
   }

   // populate message with received data
   IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataPacketWrap(pData)));
   DataPacketWrap dpw = (DataPacketWrap)GCHandle.FromIntPtr(ip2).Target;
   uint retval = hw.m_testData.load_dataSets(ref dpw);
   // display message contents
   hw.displayTestData();

   return 1;
}

我提到“按摩”对象是因为委托并不特定于此回调函数,而且我不知道是什么对象pData 将一直保留到运行时(来自代表 POV)。 由于这个问题,我必须对 pData 对象做一些额外的工作。 我基本上必须重载包装器中的构造函数才能接受 IntPtr。 提供代码是为了完全“清晰”:

DataPacketWrap (IntPtr dp)
{ 
DataPacket* pdp = (DataPacket*)(dp.ToPointer());
m_NativeDataPacket = pdp;
};

Big Thanks to plinth on this one! I am posting the final solution below to anyone else who has to deal with 3rd party fun like this one! Please feel free to critique, as I am not done optimizing the code. This may still be to roundabout a solution.

First, the callback functions became:

public delegate int ManagedCallbackFunction (IntPtr oInst, IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
ManagedCallbackFunction^ m_callbackFn;

Big props on this one. It just plain won't work if you try to cast from void* directly to Object^. Using the IntPtr and my intermediary callback:

int intermidiaryCallback(void * pInstance, const void * pData)
{   
    void* temp = (void*)pData;
    return m_callbackFn->Invoke(IntPtr(pInstance), IntPtr(temp));
};

We finally get a working model on the C# side with some massaging of the objects:

public static int hReceiveTestMessage(IntPtr pInstance, IntPtr pData)
{
   // provide object context for static member function
   helloworld2 hw = (helloworld2)GCHandle.FromIntPtr(pInstance).Target;
   if (hw == null || pData == null)
   {
      Console.WriteLine("hReceiveTestMessage received NULL data or instance pointer\n");
      return 0;
   }

   // populate message with received data
   IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataPacketWrap(pData)));
   DataPacketWrap dpw = (DataPacketWrap)GCHandle.FromIntPtr(ip2).Target;
   uint retval = hw.m_testData.load_dataSets(ref dpw);
   // display message contents
   hw.displayTestData();

   return 1;
}

I mention "massaging" the objects because the delegate is not specific to this callback function and I don't know what object pData will be until run time(from the delegates POV). Because of this issue, I have to do some extra work with the pData object. I basically had to overload the constructor in my wrapper to accept an IntPtr. Code is provided for full "clarity":

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