none
c# and Marshaling a 32 bite DLL RRS feed

  • Question

  • I have a little problem to Marshaling a 32 Bite DLL
    The Problem is that I cna call the DLL I can work in dte DLL but I become no data back from the DLL...
    Is this a security problem or a Marshaling "Return" problem?
    Here is the C# Marshal Code:

    public
    class
    HalloMyDLL
    {

    public
    string strHelp;

    [
    DllImport(@"c:\Test\MYDLL.dll")]
    [
    SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]

    public
    static extern int HALLOWORLD([MarshalAs(UnmanagedType.LPStr )] string strHelp);
    public string
    RufMichAuch()
       {
        HALLOWORLD(strHelp);
        return
    strHelp;
        } 
    }

     

    Monday, June 22, 2009 3:37 PM

Answers

  • You cannot use a string here, you must use StringBuilder:

      [DllImport(...)]
      public static extern int HALLOWORLD(StringBuilder strHelp);

    You must initialize the argument you pass so it can store the returned string:

      StringBuilder strHelp = new StringBuilder(999);
      HALLOWORD(strHelp);
      return strHelp.ToString();

    Picking the right capacity (arbitrarily 999 in my example) is very important.  If you make it too small, the unmanaged code will destroy the garbage collected heap and your program will ultimate crash and burn on a FatalExecutionEngine exception.  Unmanaged code like this should always have an extra argument that indicates the size of the passed buffer.
    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:16 PM
    Moderator
  •  

    In the 32 Bit DLL Debugger I can see that the String was change.
    In the return strHelp ist the same string then before (before I call the 32 Bite DLL)
    Example:

    Before I call the 32 Bite DLL:
    strHelp = "Hello"

    In the MyDLL I become the string "Hello"
    I change the string to "Hello World" and then I leave the program

    If I come back to the C# programm in the steHelp is standing "Hello" and not "Hello World"

    What you men with ref?

    that?
    public string RufMichAuch()
    {
       HALLOWORLD(
    ref strHelp);
       return strHelp;
    }

    the problem is that "ref" will give me an .Net Error like:
    The variable is "overload..."
    Can I set any parameter that the return is changing right?

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:18 PM
  • Yup, this would be a good example of corrupting the heap.  You also corrupted the string, strings are immutable.  That cannot be enforced by the CLR in a P/Invoke call.

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:28 PM
    Moderator
  • What can I do?
    I need the string back...
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:30 PM
  • Did you actually try StringBuilder like I recommended?

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:39 PM
    Moderator
  • How?

    public
    static extern int HALLOWORLD([MarshalAs(UnmanagedType.BStr)] StringBuilder strHelp);
    public string RufMichAuch()
    {
       HALLOWORLD(strHelp);
       return strHelp;
    }

    That gives me an error...

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:49 PM
  • Check out example at the end of MSDN Default Marshaling for Strings.
    Here's another version:
    // C# source:
    using System;
    using System.Text;
    using System.Runtime.InteropServices;
    
    class HelloWorld
    {
        static void Main() {
            StringBuilder s = new StringBuilder("Managed string value", 256);
            MyFunction(s, s.Capacity);
            Console.WriteLine("Returned string: {0}", s);
        }
        
        [DllImport("Library.dll")]
        public static extern void MyFunction(StringBuilder buffer, int bufferSize);
    }
    
    // C++ source:
    #include <stdio.h>
    #include <string.h>
    const char * g_wszReturnString = "Native string value";
    extern "C" {
    __declspec(dllexport) void MyFunction(char * wszBuffer, int cbBufferSize) 
        printf("MyFunction called with: %s\n    max size: %d\n", wszBuffer, cbBufferSize);
        if (strcpy_s(wszBuffer, cbBufferSize, g_wszReturnString) != 0) {
            if (cbBufferSize > 0) {
                *wszBuffer = 0;
            }
        }
    }
    }
    
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 5:20 PM
    Moderator
  • That gives me an error...

    Please don't force us to guess at the error you see.  You suddenly switched to BSTR.  What does the actual definition of this function look like in the unmanaged code?

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 6:11 PM
    Moderator
  • Sigh.  Copy and paste the actual declaration of the unmanaged function into a post.

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 8:57 AM
    Moderator
  • It is Cobol Code...

    Are you sure...
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 9:19 AM
  • You hav only heard something form "cobol"...
    No Problem : -)
    I am a Cobol Specialist and so I can say that it works with Strings....
    That is what I will tell you...
    I can send you the finish DLL with only one string parameter
    You must install nothing...  (only copy)
    If I see your Name then I think that you come from germany!?

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 12:15 PM

All replies

  • You cannot use a string here, you must use StringBuilder:

      [DllImport(...)]
      public static extern int HALLOWORLD(StringBuilder strHelp);

    You must initialize the argument you pass so it can store the returned string:

      StringBuilder strHelp = new StringBuilder(999);
      HALLOWORD(strHelp);
      return strHelp.ToString();

    Picking the right capacity (arbitrarily 999 in my example) is very important.  If you make it too small, the unmanaged code will destroy the garbage collected heap and your program will ultimate crash and burn on a FatalExecutionEngine exception.  Unmanaged code like this should always have an extra argument that indicates the size of the passed buffer.
    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:16 PM
    Moderator
  •  

    In the 32 Bit DLL Debugger I can see that the String was change.
    In the return strHelp ist the same string then before (before I call the 32 Bite DLL)
    Example:

    Before I call the 32 Bite DLL:
    strHelp = "Hello"

    In the MyDLL I become the string "Hello"
    I change the string to "Hello World" and then I leave the program

    If I come back to the C# programm in the steHelp is standing "Hello" and not "Hello World"

    What you men with ref?

    that?
    public string RufMichAuch()
    {
       HALLOWORLD(
    ref strHelp);
       return strHelp;
    }

    the problem is that "ref" will give me an .Net Error like:
    The variable is "overload..."
    Can I set any parameter that the return is changing right?

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:18 PM
  • Yup, this would be a good example of corrupting the heap.  You also corrupted the string, strings are immutable.  That cannot be enforced by the CLR in a P/Invoke call.

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:28 PM
    Moderator
  • What can I do?
    I need the string back...
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:30 PM
  • Did you actually try StringBuilder like I recommended?

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 4:39 PM
    Moderator
  • How?

    public
    static extern int HALLOWORLD([MarshalAs(UnmanagedType.BStr)] StringBuilder strHelp);
    public string RufMichAuch()
    {
       HALLOWORLD(strHelp);
       return strHelp;
    }

    That gives me an error...

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 2:00 PM
    Monday, June 22, 2009 4:49 PM
  • Check out example at the end of MSDN Default Marshaling for Strings.
    Here's another version:
    // C# source:
    using System;
    using System.Text;
    using System.Runtime.InteropServices;
    
    class HelloWorld
    {
        static void Main() {
            StringBuilder s = new StringBuilder("Managed string value", 256);
            MyFunction(s, s.Capacity);
            Console.WriteLine("Returned string: {0}", s);
        }
        
        [DllImport("Library.dll")]
        public static extern void MyFunction(StringBuilder buffer, int bufferSize);
    }
    
    // C++ source:
    #include <stdio.h>
    #include <string.h>
    const char * g_wszReturnString = "Native string value";
    extern "C" {
    __declspec(dllexport) void MyFunction(char * wszBuffer, int cbBufferSize) 
        printf("MyFunction called with: %s\n    max size: %d\n", wszBuffer, cbBufferSize);
        if (strcpy_s(wszBuffer, cbBufferSize, g_wszReturnString) != 0) {
            if (cbBufferSize > 0) {
                *wszBuffer = 0;
            }
        }
    }
    }
    
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 5:20 PM
    Moderator
  • That gives me an error...

    Please don't force us to guess at the error you see.  You suddenly switched to BSTR.  What does the actual definition of this function look like in the unmanaged code?

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Monday, June 22, 2009 6:11 PM
    Moderator
  • It is a zero terminated String as a refference.
    In VB with WinForms it will be run.
    But not in C# with WPF.
    I can send you the Project and the DLL if you will.
    Tuesday, June 23, 2009 8:54 AM
  • Sigh.  Copy and paste the actual declaration of the unmanaged function into a post.

    Hans Passant.
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 8:57 AM
    Moderator
  • It is Cobol Code...

    Are you sure...
    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 9:19 AM
  • You hav only heard something form "cobol"...
    No Problem : -)
    I am a Cobol Specialist and so I can say that it works with Strings....
    That is what I will tell you...
    I can send you the finish DLL with only one string parameter
    You must install nothing...  (only copy)
    If I see your Name then I think that you come from germany!?

    • Marked as answer by Bernd Riemke Tuesday, July 28, 2009 1:59 PM
    Tuesday, June 23, 2009 12:15 PM