Running native code on C#

Hello,

I know the basic things how to run native code dll's with C#, bus I have harder case. The function which is in native dll requires such parameters as structures and void * pointers. I have tried to use managed structures and objects as pointers, but nothig have worked. So how I can pass structures and void* pointers to unmanaged native functions

Thanks in advance.

Best regards,

alpha



Answer this question

Running native code on C#

  • kholling

    I think it's something like this:

    class NativeMethods

    {

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

    struct CMN_ERRORA

    {

    int dwError1;

    int dwError2;

    int dwError3;

    int dwError4;

    int dwError5;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=512)]

    string szErrorText;

    }

    delegate int DM_NOTIFY_PROCA(

    int dwNotifyClass,

    int dwNotifyCode,

    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)]

    byte[] lpbyData,

    int dwItems, // I hope this parameter is size of the array passed through lpbyData parameter

    IntPtr lpvUser);

    [DllImport("dllname.dll", CharSet=CharSet.Ansi, EntryPoint="DMConnectA")]

    public static extern int DMConnectA(

    string lpszAppName,

    DM_NOTIFY_PROCA lpfnNotify,

    IntPtr lpvUser,

    out CMN_ERRORA lpdmError);

    }

    DM_NOTIFY_PROCA is not a structure, it's a pointer to a function so I used a delegate for it. I hope it works.


  • Matt_

    Hello,

    Thanks for answer. I will try to use this and see how it works.

    Best regards,

    alpha


  • kangalert

    Hello,

    Thank you for answering. So I'll try to show all C/C++ code that is used in calling:

    1. Function itself (from *.h file)

    BOOL WINAPI DMConnectA(
    LPCSTR lpszAppName,
    DM_NOTIFY_PROCA lpfnNotify,
    LPVOID lpvUser,
    LPCMN_ERRORA lpdmError );

    2. DM_NOTIFY_PROCA is structure:

    typedef BOOL (* OUTSIDE DM_NOTIFY_PROCA)(
    DWORD dwNotifyClass,
    DWORD dwNotifyCode,
    LPBYTE lpbyData,
    DWORD dwItems,
    LPVOID lpvUser);

    3. LPCMN_ERRORA is structure:

    typedef struct tagCMN_ERRORA
    {
    DWORD dwError1,
    dwError2,
    dwError3,
    dwError4,
    dwError5;
    char szErrorText[512];
    } CMN_ERRORA, *PCMN_ERRORA, **PPCMN_ERRORA, FAR *LPCMN_ERRORA;

    I think it is some kind of complex calling, but I depend on it, I can't change. I have DLL and *.H. Thanks god I have *.H file ;)

    So as you can see there is also array in structure. I can make the same managed thing, but how to do it unmanaged native code I dont' know.

    Thanks in advance.

    Best regards,

    alpha


  • Tigerwood2006

    Or you can just write a wrapper class using C++ and the CLI extensions and use that class from C#.
  • madenci

    If you can show the C/C++ declarations of the functions you want to call you might a much better answer. Just structures and void * pointers is too generic.

    You can use a struct with the [StructLayout(LayourKind.Sequential)] attribute for example:

    using System.Runtime.InteropServices;

    [StructLayout(LayoutKind.Sequential)]

    struct Test

    {

    int a;

    int b;

    }

    and for void * you can use IntPtr in many cases.


  • Mart Tapp

    The counterpart of VARIANT is System.Object in .NET.

    My understanding is that System.Object is automatically marshaled to and from VARIANT when it is a parameter for PInvoke and It will instead be marshaled to IUnknown when defined in structs. You can get the gory details about how this happens in this article on the MSDN. To get a System.Object to be marshaled to VARIANT in a struct, you need to use the MarshalAsAttribute, specifying UnmanagedType.Struct.

    struct MarshalTest {
    int foo;
    [MarshalAs (UnmanagedType.Struct)]
    object bar; // this will be marshaled to a variant
    }

    HTH
    --mc


  • PiGuy

    Hello,

    Thank you very much. I will try, but I'm sure that ir will work. Thanks again.

    Best regards,

    alpha


  • Raptorix

    Hello,

    It hasn't worked. I think it is becouse VARIANT type is not the same size as OBJECT. The unmanaged function uses VARIANT type's fields and it uses like a structure with members. Maybe OBJECT just is not the good solution. Maybe I need to rewrite VARIANT struct definition in C#, but don't know how to deal with unions in C#. Please help.

    or maybe I was wrong somewhere else. Please look at code:

    UNMANEGED:

    1. Function

    BOOL WINAPI DMGetValueA(

    LPDM_VARKEYA lpdmVarKey,

    DWORD dwItems,

    LPDM_VAR_UPDATE_STRUCTA lpdmvus,

    LPCMN_ERRORA lpdmError);

    2. Structures

    typedef struct tagDM_VARKEYA

    {

    DWORD dwKeyType; /* which key is valid */

    DWORD dwID; /* Key: Varaible-ID */

    char szName[ 129 ]; /* Key: Variable-Name */

    LPVOID lpvUserData; /* User-specfic field */

    } DM_VARKEYA, FAR *LPDM_VARKEYA;

     

    typedef struct tagDM_VAR_UPDATE_STRUCTA

    {

    DM_TYPEREFA dmTypeRef; /* Type of variable-data */

    DM_VARKEYA dmVarKey; /* Variable-Access-Key */

    VARIANT dmValue; /* Update-Value */

    DWORD dwState; /* State of Variable and value */

    } DM_VAR_UPDATE_STRUCTA, FAR *LPDM_VAR_UPDATE_STRUCTA;

     

    typedef struct tagDM_TYPEREFA

    {

    DWORD dwType; /* See constants DM_TYPEREF_xxx */

    DWORD dwSize; /* size of type in byte */

    char szTypeName[ 129 ]; /* name of type */

    } DM_TYPEREFA, FAR *LPDM_TYPEREFA;

    And this is what I did in my managed code:

    1. Function

    [DllImport("dmclient.dll", CharSet = CharSet.Ansi, EntryPoint = "DMGetValueA", CallingConvention = CallingConvention.Winapi)]

    public extern static bool DMGetValueA(

    out DM_VARKEYA lpdmVarKey,

    int dwItems,

    out DM_VAR_UPDATE_STRUCTA lpdmvus,

    out CMN_ERRORA lpdmError);

    2. Structures

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

    public struct DM_VARKEYA

    {

    public int dwKeyType;

    public int dwID;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]

    public string szName;

    public IntPtr lpvUserData;

    }

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

    public struct DM_VAR_UPDATE_STRUCTA

    {

    public DM_TYPEREFA dmTypeRef;

    public DM_VARKEYA dmVarKey;

    [MarshalAs(UnmanagedType.Struct)]

    public object dwValue;

    public int dwState;

    }

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

    public struct DM_TYPEREFA

    {

    public int dwType;

    public int dwSize;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]

    public string szTypeName;

    }

     

    So maybe I am wrong somewhere else in the code, not with VARIANT type

    Best regards,

    alpha


  • fatalist

    Hello,

    Thank you very much. Your suggested method worked well. Now its all clear to me. Thanks again.

    Best regards,

    alpha


  • Ather.

    Hello,

    Well, it looks like it would be better to rewrite program in C++, becouse marshaling all needed data becomes to complicated in C#

    Best regards,

    alpha


  • Dave Cline

    Hello,

    I have one more question regarding this thread. I have structure in unmanaged dll, that contains variable of type VARIANT. I know what is VARIANT in C++, but I have no ideas how to convert it to managed code. Saying VARIANT I mean not ADO related value, but structure which has all possible variable types defined as union. So my struct in unmanaged code is:

    typedef struct tagDM_VAR_UPDATE_STRUCTA

    {

    DM_TYPEREFA dmTypeRef; /* Type of variable-data */

    DM_VARKEYA dmVarKey; /* Variable-Access-Key */

    VARIANT dmValue; /* Update-Value */

    DWORD dwState; /* State of Variable and value */

    } DM_VAR_UPDATE_STRUCTA, FAR *LPDM_VAR_UPDATE_STRUCTA;

    Have you any ideas how to convert it to managed code

    Thanks in advance.

    Best regards,

    alpha


  • Running native code on C#