title: Call C DLL function from C# - convert char parameter to string
body: <p>I'm trying to call a method from a DLL written in C, from my C# application. Here is how I've implemented the call:</p>
  
  <p>--> C method signature: (from a third-part company)</p>
  
  <pre>Int16 SSEXPORT SS_Initialize(Uint16 ServerIds[], Uint16 ServerQty, const char PTR *Binding, const char PTR *LogPath, Uint16 LogDays, Int16 LogLevel,
  Uint16 MaxThreads, Uint16 ThreadTTL, Int16 (CALLBACK *ProcessMessage)(Uint16, const char PTR *, Uint32, char PTR **, Uint32 PTR *, Int16 PTR *));</pre>
  
  <p>--> C types definition:</p>
  
  <pre>
  #ifndef _CSISERVERTYPES_
  #define _CSISERVERTYPES_
  
  #if defined(OS_NT)
  
  #define CALLBACK __stdcall 
  #define SSEXPORT __stdcall
  #define PTR      
  
  typedef char                Int8;
  typedef unsigned char       Uint8;
  typedef short               Int16;
  typedef unsigned short      Uint16;
  typedef long                Int32;
  typedef unsigned long       Uint32;
  typedef unsigned char       Byte;
  typedef unsigned short      Word;
  typedef unsigned long       Dword;
  typedef short               Bool;
  
  #endif
  
  typedef Int16 (CALLBACK *PM_Function)
          (Uint16,const char PTR *,Uint32,char PTR **,Uint32 PTR *,Int16 PTR *);
  
  #define SS_OK               0
  #define SS_NOT_INIT         -1
  #define SS_PROC_ERR         -2
  #define SS_ERR_TCP_SRV      -3
  #define SS_ERR_OUT_MEM      -4
  
  #ifndef NULL
  #define NULL                0
  #endif
  
  #endif
  </pre>
  
  <p>--> C# DLL Method declaration:</p>
  
  <pre><code>[DllImport("CSITCPServer.dll", SetLastError = true)]
      static extern Int16 SS_Initialize(
          UInt16[] ServerIds,
          UInt16 ServerQty,
          ref string Binding,
          ref string LogPath,
          UInt16 LogDays,
          Int16 LogLevel,
          UInt16 MaxThreads,
          UInt16 ThreadTTL,
          ProcessMessageCallback callback);
  </code></pre>
  
  <p>Method call:</p>
  
  <pre><code>public static void Call_SS_Initialize()
      {   
          Int16 ret;
          UInt16[] serverIds = new UInt16[] { 2020, 2021 };
          string binding = "";
          string logPath = "";
  
          try
          {
              ret = SS_Initialize(
                  serverIds,
                  Convert.ToUInt16(serverIds.ToList().Count),
                  ref binding,
                  ref logPath,
                  10,
                  0,
                  256,
                  300,
                  ProcessMessage);
  
              Console.WriteLine("Call_SS_Initialize() -&gt; Result of SS_Initialize:  {0}", ret.ToString());
          }
          catch (Exception ex)
          {
              Int32 err = Marshal.GetLastWin32Error();
              throw new Win32Exception(err);
              //throw;
          }
      }
  </code></pre>
  
  <p>And then I get the <strong>Win32Exception: 1008 - An attempt was made to reference a token that does not exist</strong></p>
  
  <p>I know that the problem must be in the CHAR to STRING conversion between unmanaged (C) and managed (C#) codes. If I modify the <strong>Binding</strong> or <strong>LogPath</strong> parameters to type <strong>SByte</strong>, it doesn't give any errors. But since the method expects for a text (string), I don't know how can I pass the text to the method since it expects a SByte variable...</p>
  
  <p>I'm aware that I might have to use something like <strong>MarshalAs</strong>, but I've tried a few options and didn't had any success.</p>
  
  <p>Can anybody tell me what am I doing wrong??</p>
  
  <p>Thank you very much!!</p>
  
  <hr>
  
  <p>Here is the callback definition:</p>
  
  <pre><code> public delegate Int16 ProcessMessageCallback(
          UInt16 ServerId,
          [MarshalAs(UnmanagedType.LPStr)] ref string RequestMsg,
          UInt32 RequestSize,
          [MarshalAs(UnmanagedType.LPStr)] ref string ResponseMsg,
          ref UInt32 ResponseSize,
          ref Int16 AppErrCode);
  </code></pre>
  
  <p>The thing is that the C DLL method is expecting a "REF" parameter. The call to <strong>SS_Initialize</strong> attachs the execution to the <strong>ProcessMessage</strong> callback function. In this function I need to be able to get the modified parameters (ref) from SS_Initialize ...</p>
  
  <p>Could you please suggest how do you think the code should be structured?</p>
  
  <p>Thank you!!</p>