none
Native to Managed Conversion RRS feed

  • Question

  • Hello CLR,

    I am trying to convert some native code to managed code.  Below is what I have so far.

    The trouble I am running into is with PtrToStructure on the NHCIServerList Struct.  This struct contains another struct that is of fixed size in the native code.  I'm not sure that I'm even allocating the right size for the pointer...

    Also, why are all the dll entry points all goofy:::
    ?NHCIAPIinit@@YAHXZ
    ?NHCIAPIstop@@YAXXZ
    ?NHCIGetServerList@@YAHPAUNHCIServerList@@@Z
    ?NHCIGetServerList@@YAHPAUNHCIServerList@@@Z
    ...



    Any thoughts?
    Thanks

    CODE

    retVal = NativeMethods.NHCIAPIinit()
    
    Dim
     serverList As
     NHCIServerList = New
     NHCIServerList
     'ReDim serverList.serverEntries(7)
    
    Dim
     server As
     NHCIServerEntry = New
     NHCIServerEntry
    Dim
     deviceList As
     NHCIDeviceList = New
     NHCIDeviceList
     'ReDim deviceList.deviceEntries(7)
    
    Dim
     device As
     NHCIDeviceEntry = New
     NHCIDeviceEntry
    
    Dim
     serverListPtr As
     IntPtr = IntPtr.Zero
    serverListPtr = Marshal.AllocHGlobal(Marshal.SizeOf(serverList))
    serverList = Marshal.PtrToStructure(serverListPtr, GetType
    (NHCIServerList))
    
    For
     i As
     Integer
     = 1 To
     serverList.countServers
    ...
    
    NativeMethods.NHCIAPIstop()
    




    Managed Signatures

    Imports System.Runtime.InteropServices
    
    Public Class Native
    
        Public Const kNHCIMaxServerNameLen As Integer = 63
        Public Const kNHCIMaxServers As Integer = 7
        Public Const kNHCIMaxDevicesServer As Integer = 7
        Public Const kNHCIMaxDeviceNameLen As Integer = 31
        Public Const kNHCIMaxSerialStringLen As Integer = 255
        Public Const kNHCIMaxClientNameLen As Integer = 63
    
    
        Public Enum NHCIServerEntryFlags
            '''kNHCIServerNeedsPassword -> 0x0001
            kNHCIServerNeedsPassword = 1
            '''kNHCIServerModelUS4A -> 0x0002
            kNHCIServerModelUS4A = 2
            '''kNHCIServerModelU2S2A -> 0x0004
            kNHCIServerModelU2S2A = 4
        End Enum
    
        Public Enum NHCIDeviceEntryFlags
            '''kNHCIDeviceBusy -> 0x0001
            kNHCIDeviceBusy = 1
            '''kNHCIDeviceUsesPswd -> 0x0002
            kNHCIDeviceUsesPswd = 2
            '''kNHCIDeviceConnected -> 0x0004
            kNHCIDeviceConnected = 4
        End Enum
    
        <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=System.Runtime.InteropServices.CharSet.[Ansi])> _
        Public Structure NHCIServerEntry
            Public serialNo As UInteger
            Public IPAddr As UInteger
            Public flags As UInteger
            <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=kNHCIMaxServerNameLen)> _
            Public serverName As String
            Public refnum As UInteger
        End Structure
    
        <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIServerList
            Public countServers As Integer
            '<System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Struct)> _
            Public serverEntries() As NHCIServerEntry
        End Structure
    
        <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=System.Runtime.InteropServices.CharSet.[Ansi])> _
        Public Structure NHCIDeviceEntry
            <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=kNHCIMaxDeviceNameLen)> _
            Public productName As String ' size
            Public NHCIdeviceName()() As Byte ' size
            Public USBSerialString()() As Byte ' size
            Public userName()() As Byte ' size
            Public refnum As Integer
            Public USBVid As UShort
            Public USBPid As UShort
            Public USBClass As Byte
            Public USBSubClass As Byte
            Public USBProtocol As Byte
            Public fill As Byte
            Public flags As Integer
        End Structure
    
        <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIDeviceList
            Public countDevices As Integer
            Public deviceEntries() As NHCIDeviceEntry
        End Structure
    
        Public Enum Status
            kNHCINotifyNewServerConn = 1
            kNHCINotifyServerConnLost = 2
            kNHCINotifyDeviceAdded = 3
            kNHCINotifyDeviceRemoved = 4
            kNHCINotifyDeviceStatusUpdate = 5
            kNHCINotifyAttachComplete = 6
            kNHCIDeviceStatusAvailable = 1
            kNHCIDeviceStatusBusy = 2
            kNHCIDeviceStatusLocalConnect = 3
        End Enum
    
        <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=System.Runtime.InteropServices.CharSet.[Ansi])> _
        Public Structure NHCInotification
            Public note As Integer
            Public serverSerial As Integer
            Public serverIP As Integer
            Public deviceVid As Integer
            Public devicePid As Integer
            Public deviceLocationID As Integer
            Public status As Integer
            Public p1 As Integer
            Public p2 As Integer
            Public p3 As Integer
            Public p4 As Integer
            ''char[]
            '<System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=-1)> _
            Public name As String
        End Structure
    
        Public Delegate Sub NHCInotifiyCallback(ByVal refnum As System.IntPtr, ByRef pNote As NHCInotification)
    
        Partial Public Class NativeMethods
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIAPIinit@@YAHXZ")> _
            Public Shared Function NHCIAPIinit() As Integer
            End Function
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIAPIstop@@YAXXZ")> _
            Public Shared Sub NHCIAPIstop()
            End Sub
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIGetServerList@@YAHPAUNHCIServerList@@@Z")> _
            Public Shared Function NHCIGetServerList(ByRef pSList As NHCIServerList) As Integer
            End Function
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIGetServerList@@YAHPAUNHCIServerList@@@Z")> _
            Public Shared Function NHCIGetServerListPtr(ByRef pSList As IntPtr) As Integer
            End Function
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIGetDeviceList@@YAHHPAUNHCIDeviceList@@@Z")> _
            Public Shared Function NHCIGetDeviceList(ByVal refnum As Integer, ByRef pDList As NHCIDeviceList) As Integer
            End Function
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIpostNotify@@YAXP6AXPAXPAUNHCInotification@@@Z0@Z")> _
            Public Shared Sub NHCIpostNotify(ByVal notify As NHCInotifiyCallback, ByVal refnum As System.IntPtr)
            End Sub
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIcancelNotify@@YAXPAX@Z")> _
            Public Shared Sub NHCIcancelNotify(ByVal refnum As System.IntPtr)
            End Sub
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIAttachDevice@@YAHHH@Z")> _
            Public Shared Function NHCIAttachDevice(ByVal serverRefnum As Integer, ByVal deviceRefnum As Integer) As Integer
            End Function
    
            <System.Runtime.InteropServices.DllImportAttribute("nhciClientApi.dll", EntryPoint:="?NHCIDetachDevice@@YAHHH@Z")> _
            Public Shared Function NHCIDetachDevice(ByVal serverRefnum As Integer, ByVal deviceRefnum As Integer) As Integer
            End Function
        End Class
    
    End Class
    Native Header

    enum
    {
    	kNHCIMaxServerNameLen	= 64,
    	kNHCIMaxServers			= 8,
    	kNHCIMaxDevicesServer	= 8,
    	kNHCIMaxDeviceNameLen	= 32,
    	kNHCIMaxSerialStringLen	= 256,
    	kNHCIMaxClientNameLen	= 64
    };
    
    
    enum													// NHCIServerEntry flags
    {
    	kNHCIServerNeedsPassword	= 0x0001,
    	kNHCIServerModelUS4A		= 0x0002,
    	kNHCIServerModelU2S2A		= 0x0004
    };
    
    
    enum													// NHCIDeviceEntry flags
    {
    	kNHCIDeviceBusy				= 0x0001,				// device is in use (including locally)
    	kNHCIDeviceUsesPswd			= 0x0002,				// when device needs password
    	kNHCIDeviceConnected		= 0x0004				// device connected locally
    };
    
    
    
    struct NHCIServerEntry
    {
    	unsigned long		serialNo,								// Server serial number as a 32 bit binary
    				IPAddr,									// IP address in standard network byte order
    				flags;						
    	char		serverName[kNHCIMaxServerNameLen];	// C-string assigned name of server
    	unsigned long			refnum;								// for calls that need to refer to this Server
    };
    
    
    struct NHCIServerList
    {
    	int						countServers;
    	struct NHCIServerEntry	serverEntries[kNHCIMaxServers];
    };
    
    
    struct NHCIDeviceEntry
    {
    	char		productName[kNHCIMaxDeviceNameLen],			// USB product Name or 1284 string
    				NHCIdeviceName[kNHCIMaxDeviceNameLen],		// if present, assigned NHCI name
    				USBSerialString[kNHCIMaxSerialStringLen],	// if present, USB Serial number text, in ascii
    				userName[kNHCIMaxClientNameLen];				// name of user, if busy
    				
    	int			refnum;										// for calls that need to refer to this Device (within server)
    				
    	unsigned short		USBVid,									// USB Vendor ID
    						USBPid;									// USB Product ID
    	unsigned char		USBClass,
    						USBSubClass,
    						USBProtocol,
    						fill;
    	int					flags;									// NHCI API flags, defined above
    };
    
    
    struct NHCIDeviceList
    {
    	int						countDevices;
    	struct NHCIDeviceEntry	deviceEntries[kNHCIMaxDevicesServer];
    };
    
    
    //
    // initialize API
    //
    NHCICLIENTAPI_API int
    	NHCIAPIinit();
    NHCICLIENTAPI_API void
    	NHCIAPIstop();
    
    
    //
    // API Query calls
    //
    
    //
    // get the list of currently known servers to pSList[], fills in countServers
    // return 0 if ok, <0 error
    //
    NHCICLIENTAPI_API int
    	NHCIGetServerList(struct NHCIServerList *pSList);
    
    //
    // get the list of currently known devices for server with refnum, to pDList[], fills in countDevice
    // return 0 if ok, < 0 if error
    //
    NHCICLIENTAPI_API int
    	NHCIGetDeviceList(int refnum, struct NHCIDeviceList *pDList);
    	
    
    enum
    {
    	kNHCINotifyNewServerConn		= 1,
    	kNHCINotifyServerConnLost		= 2,
    	kNHCINotifyDeviceAdded			= 3,
    	kNHCINotifyDeviceRemoved		= 4,
    	kNHCINotifyDeviceStatusUpdate	= 5,
    	kNHCINotifyAttachComplete		= 6,				// p1 0 if good, !=0 if bad (not supported on windows)
    	
    	kNHCIDeviceStatusAvailable		= 1,
    	kNHCIDeviceStatusBusy			= 2,
    	kNHCIDeviceStatusLocalConnect	= 3
    };
    
    struct NHCInotification
    {
    	int			note,
    				serverSerial,
    				serverIP,
    				deviceVid,
    				devicePid,
    				deviceLocationID,
    				status,
    				p1,
    				p2,
    				p3,
    				p4;
    	char		name[kNHCIMaxServerNameLen];
    };
    
    typedef void (*NHCInotifiyCallback)(void * refnum, struct NHCInotification *pNote);
    
    NHCICLIENTAPI_API void NHCIpostNotify(NHCInotifiyCallback notify, void *refnum);
    NHCICLIENTAPI_API void NHCIcancelNotify(void *refnum);
    	
    	
    //
    // Actions
    //
    
    //
    // Attach the given device locally
    // returns <0 if error, 0 if request sent
    // request completes asynchronously and results in notification
    NHCICLIENTAPI_API int
    	NHCIAttachDevice(int serverRefnum, int deviceRefnum);
    	
    //
    // unsubscribe device
    // returns <0 if error, 0 if request sent
    // request completes asynchronously
    NHCICLIENTAPI_API int
    	NHCIDetachDevice(int serverRefnum, int deviceRefnum);
    


    • Edited by fixitchris Tuesday, April 21, 2009 3:17 PM edit
    Tuesday, April 21, 2009 3:13 PM

Answers

  • According to your native code -

    retVal should be an Int32 with the number of elements being pointed to in serverListPtr, right?  Is retVal 0?  If not, that would explain the crash, since according to your comments, that's an error.

    //
    // get the list of currently known servers to pSList[], fills in countServers
    // return 0 if ok, <0 error
    //
    NHCICLIENTAPI_API int NHCIGetServerList(struct NHCIServerList *pSList);


    I think the problem is in this, though:

    <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIServerList
            Public countServers As Integer
            '<System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Struct)> _
            Public serverEntries() As NHCIServerEntry
        End Structure

    Try changing this to:

    <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIServerList
            Public countServers As Integer
            <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType:= Struct, SizeConst:=8)> _
            Public serverEntries() As NHCIServerEntry
        End Structure

    I think the problem is that you need to setup your marshal attributes to marshall this as an array inline, instead of a pointer to an array.
    Tuesday, April 21, 2009 4:12 PM
    Moderator

All replies

  • "Also, why are all the dll entry points all goofy:::"

    This is due to name mangling in C++.

    As for your problem - the one thing I do see here that is very odd is this code:

    serverListPtr As
    IntPtr = IntPtr.Zero
    serverListPtr = Marshal.AllocHGlobal(Marshal.SizeOf(serverList))
    serverList = Marshal.PtrToStructure(serverListPtr, GetType
    (NHCIServerList))


    Right now, you're allocating a serverList on the heap using Marshall.AllocHGlobal, then marshalling (copying) it back into a new ServerList struct, but never using the pointer. It'd be much, much cleaner to just do:

    Dim serverList As New ServerList


    In any case, what is the specific error you are receiving in this code?
    Tuesday, April 21, 2009 3:28 PM
    Moderator
  • Oops, sorry Reed. I forgot a line:
     
    Dim
     serverList As
     NHCIServerList = New
     NHCIServerList
    Dim
     serverListPtr As
     IntPtr = IntPtr.Zero
    
    serverListPtr = Marshal.AllocHGlobal(Marshal.SizeOf(serverList))
    retVal = NativeMethods.NHCIGetServerListPtr(serverListPtr)
    
    serverList = Marshal.PtrToStructure(serverListPtr, GetType
    (NHCIServerList))
    
    
    


    The PtrToStructure line causes the binary to just quit with no error  I can't step through the code on that machine until later today.
    NHCIGetServerListPtr does return 0, however after the NHCIGetServerListPtr call, serverListPtr.ToString =1 which is probably no good.
    Tuesday, April 21, 2009 3:49 PM
  • According to your native code -

    retVal should be an Int32 with the number of elements being pointed to in serverListPtr, right?  Is retVal 0?  If not, that would explain the crash, since according to your comments, that's an error.

    //
    // get the list of currently known servers to pSList[], fills in countServers
    // return 0 if ok, <0 error
    //
    NHCICLIENTAPI_API int NHCIGetServerList(struct NHCIServerList *pSList);


    I think the problem is in this, though:

    <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIServerList
            Public countServers As Integer
            '<System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Struct)> _
            Public serverEntries() As NHCIServerEntry
        End Structure

    Try changing this to:

    <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
        Public Structure NHCIServerList
            Public countServers As Integer
            <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType:= Struct, SizeConst:=8)> _
            Public serverEntries() As NHCIServerEntry
        End Structure

    I think the problem is that you need to setup your marshal attributes to marshall this as an array inline, instead of a pointer to an array.
    Tuesday, April 21, 2009 4:12 PM
    Moderator
  • Thanks.  Now I'm having trouble handling callbacks on multiple threads.
    Tuesday, April 21, 2009 11:49 PM
  • What problems are you having, specifically?

    The callbacks are likely to be called on the thread where you call your native API (unless the native API is spawning its own threads).  Are you wanting to have them do work on a separate thread?  Are you trying to marshall this to your UI thread?
    Tuesday, April 21, 2009 11:52 PM
    Moderator
  • Take a look at this thread I started: http://www.xtremevbtalk.com/showthread.php?p=1327106#post1327106 and the screen http://www.xtremevbtalk.com/attachment.php?attachmentid=29578&d=1240357075

    What I want to accomplish is create a simple app that will just subscribe to the notifications and will be aware when a device is connected or disconnected.  Except the issue I am seeing is that the moment I subscribe to the callback with NativeMethods.NHCIpostNotify(np, id) and I connect/disconnect a device ,the API creates 5 threads all wanting to access the same object at the same time.  And I get garbage info + debugger crashes.

    Sorry for the previous posts... They were very vague.

    Here is a sample of what the callbacks produce::: It gets worse than this, the fields go out of order... and even the serial number on these does not match what the 'server' really is (but that could be my p/invoke).

    1**------begin
    1**Notification Callback
    1**Location: 3
    1**vid: 1193
    1**pid: 4276
    
    5**------begin
    5**Notification Callback
    5**Location: 3
    5**vid: 1193
    5**pid: 4276
    5**name:
    5**note: 3
    5**p1: 0
    5**p2: 0
    5**p3: 0
    5**p4: 0
    5**ip: 221.1.168.192
    5**s/n: 2745375256
    5**status: 0
    5**------end
    5**name:
    5**note: 3
    5**p1: 0
    5**p2: 0
    5**p3: 0
    5**p4: 0
    5**ip: 221.1.168.192
    5**s/n: 2745375256
    5**status: 0
    5**------end
    
    5**------begin
    5**Notification Callback
    5**Location: 3
    5**vid: 1193
    5**pid: 4276
    5**name:
    5**note: 3
    5**p1: 0
    5**p2: 0
    5**p3: 0
    5**p4: 0
    5**ip: 221.1.168.192
    5**s/n: 2745375256
    5**status: 0
    5**------end
    
    5**------begin
    5**Notification Callback
    5**Location: 3
    5**vid: 1193
    5**pid: 4276
    5**name:
    5**note: 3
    5**p1: 0
    5**p2: 0
    5**p3: 0
    5**p4: 0
    5**ip: 221.1.168.192
    5**s/n: 2745375256
    5**status: 0
    5**------end
    
    5**------begin
    5**Notification Callback
    5**Location: 3
    5**vid: 1193
    5**pid: 4276
    5**name:
    5**note: 3
    5**p1: 0
    5**p2: 0
    5**p3: 0
    5**p4: 0
    5**ip: 221.1.168.192
    5**s/n: 2745375256
    5**status: 0
    5**------end
    
    6**------begin
    6**Notification Callback
    6**Location: 0
    6**vid: 0
    6**pid: 0
    6**name:
    6**note: 1
    6**p1: 0
    6**p2: 0
    6**p3: 0
    6**p4: 0
    6**ip: 0.0.0.0
    6**s/n: 0
    6**status: 0
    6**------end
    
    7**------begin
    7**Notification Callback
    7**Location: 0
    7**vid: 0
    7**pid: 0
    7**name:
    8**note: 1
    8**p1: 0
    8**p2: 0
    8**p3: 0
    8**p4: 0
    8**ip: 0.0.0.0
    8**s/n: 0
    8**status: 0
    8**------end
    
    8**------begin
    8**Notification Callback
    8**Location: 0
    8**vid: 0
    8**pid: 0
    9**name:
    9**note: 1
    9**p1: 0
    9**p2: 0
    9**p3: 0
    9**p4: 0
    10**ip: 0.0.0.0
    10**s/n: 0
    10**status: 0
    10**------end
    
    10**------begin
    10**Notification Callback
    10**Location: 0
    10**vid: 0
    10**pid: 0
    10**name:
    10**note: 1
    10**p1: 0
    10**p2: 0
    10**p3: 0
    10**p4: 0
    10**ip: 0.0.0.0
    10**s/n: 0
    10**status: 0
    10**------end
    
    10**------begin
    10**Notification Callback
    10**Location: 0
    10**vid: 0
    10**pid: 0
    10**name:
    10**note: 1
    10**p1: 0
    10**p2: 0
    10**p3: 0
    10**p4: 0
    10**ip: 0.0.0.0
    10**s/n: 0
    10**status: 0
    10**------end
    
    
    Wednesday, April 22, 2009 12:05 AM
  • Reed, my race condition seems to be described well by the kitties on pg8: http://software.intel.com/file/14723

    I'm reading up on race conditions so I will eventually figure this one out... :)
    Monday, April 27, 2009 8:11 PM
  • Good luck.  If you have any other questions about them, let us know.
    Reed Copsey, Jr. - http://reedcopsey.com
    Monday, April 27, 2009 10:52 PM
    Moderator