在调用中使用structs从vb.net中执行pinvoke

pinvoke from vb.net using structs in call

本文关键字:vb net 执行 pinvoke structs 调用      更新时间:2023-10-16

我真的很难处理下面的pinvoke调用。我尝试了很多不同的方法,但仍然没有快乐。

调用一直运行,但我收到了一条"Bad parameter"消息,表明结构有问题,因为我已经运行了该代码的c++示例,并且参数都是正确的。

如果有任何帮助,我会非常感激的,我已经在谷歌上疯了!

在c++头文件中:

int __stdcall DVSNET_OpenChannel(HANDLE hServer,unsigned long nChannel,DVSNET_CHANNEL_INFO *pChannelInfo,HANDLE *phChannel);
typedef struct tagDVSNET_CHANNEL_INFO
{
    unsigned long lStructSize;
    unsigned long dwStreamNo;
    unsigned long nProtocol;
    HWND          hWndDisplay;
    unsigned long bPlayStart;
    unsigned long dwBackFrameCount;
    unsigned long dwFlag;
} DVSNET_CHANNEL_INFO;

我对导入的定义:

<DllImport("DVSNETClient.dll")> _
Public Shared Function DVSNET_OpenChannel(ByVal hServer As System.IntPtr, ByVal nChannel As UInteger, ByRef pChannelInfo As IntPtr, ByRef phChannel As IntPtr) As Integer
End Function
<StructLayout(LayoutKind.Sequential)> _
Public Structure tagDVSNET_CHANNEL_INFO
    Public lStructSize As UInteger
    Public dwStreamNo As UInteger
    Public nProtocol As UInteger
    Public hWndDisplay As IntPtr
    Public bPlayStart As UInteger
    Public dwBackFrameCount As UInteger
    Public dwFlag As UInteger
End Structure

我的呼叫代码:

Private Sub OpenChannel()
    Dim intRet As Integer
    Dim ChannelInfo As New tagDVSNET_CHANNEL_INFO
    Dim HWD As New System.IntPtr
    ChannelInfo.lStructSize = System.Runtime.InteropServices.Marshal.SizeOf(ChannelInfo)
    ChannelInfo.nProtocol = 0
    ChannelInfo.dwStreamNo = 0
    ChannelInfo.dwBackFrameCount = 10
    ChannelInfo.hWndDisplay = HWD
    ChannelInfo.bPlayStart = 0 ' dont display
    'Channelinfo.dwFlag = 
    ' Initialize unmanged memory to hold the struct.
    Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ChannelInfo))
    System.Runtime.InteropServices.Marshal.StructureToPtr(ChannelInfo, ptr, True)
    Dim nChannel As UInteger = 1
    intRet = TotemPoleLib.DVSNET_OpenChannel(hServer, nChannel, ptr, hChannel)
    '... snip ...
End Sub

非常感谢!

我不知道VB.Net语法,但如果你理解C#,那么下面是DVSNET_CHANNEL_INFODVSNET_OpenChannel:的正确p/Invoke声明

[StructLayout(LayoutKind.Sequential)]
struct DVSNET_CHANNEL_INFO
{
    uint   lStructSize;
    uint   dwStreamNo;
    uint   nProtocol;
    IntPtr hWndDisplay;
    uint   bPlayStart;
    uint   dwBackFrameCount;
    uint   dwFlag;
}
static class DVSNETClient
{
    [DllImport("DVSNETClient.dll")]
    public static extern int DVSNET_OpenChannel(
        IntPtr hServer,
        uint nChannel,
        ref DVSNET_CHANNEL_INFO pChannelInfo,
        ref IntPtr phChannel
    );
}

您的DVSNET_CHANNEL_INFO看起来不错,但DVSNET_OpenChannel的第三个自变量应该只是ref DVSNET_CHANNEL_INFO;所有封送处理都是自动完成的,这里不需要Marshal类。您只需要在调用DVSNET_OpenChannel之前将ChannelInfo.lStructSize初始化为Marshal.SizeOf(typeof(DVSNET_CHANNEL_INFO))的值。在DVSNET_CHANNEL_INFO的非默认构造函数中这样做可能是明智的,但考虑到它是一个结构,当然没有办法强制使用该构造函数而不是隐式默认构造函数。

注意,从语义上讲,pChannelInfo和/或phChannel可能是out而不是ref,但不可能通过DVSNET_OpenChannel的签名来判断。在任何情况下,使用ref都会起作用,尽管如果确实需要out,它的效率将低于使用out