none
Call C++ dll from C# (passing char* ) RRS feed

  • Question

  • In my C# code, i am trying to import a C++ dll and one of the arguments of the function call is char *.

     

    Actual C++ function that i am trying to call looks like:

            typedef int returnData (char*);

     

    In my C# code, the way i am importing the dll is:     

            [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")]

            public static extern int returnData(ref string fileName);

    And, while calling the function:
            string myFile = "C:\\temp\\data.txt";
             RetValue = returnData(ref myFile);

     

    However, i am unable to pass the file name correctly to the dll function.

    Note: If i remove passing the filename as an argument and hardcode the value in dll, it works fine. 

     


    Wednesday, August 17, 2011 2:30 AM

Answers

  • Hello Jay Jardosh,

     

    >> In my case, dll interop function will only consume the string since its a file name... it won't return anything except the return status code (which is int)...

    1. In this case, you should just declare the API as :

    [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")]
    
    public static extern int returnData(string fileName);
    
    
    
    

    Note that there is no "ref" keyword for the fileName parameter. This is what Louis.fr has already indicated,

     

    2. This is also equivalent to :

    [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")] 
    public static extern int returnData([MarshalAs(UnmanagedType.LPStr)] string fileName);

    The interop marshaler will internally allocate a string buffer to contain the string value inside "fileName". It will then pass a pointer to this string buffer to the "returnData" function.

    When the API returns, the string buffer will be automatically freed by the interop marshaler.


    - Bio.

     


    Please visit my blog : http://limbioliong.wordpress.com/
    • Marked as answer by Jay Jardosh Thursday, August 18, 2011 7:09 PM
    Thursday, August 18, 2011 10:00 AM

All replies

  • You would pass ref string if the parameter was char**. Remove the 'ref' keyword.

    Wednesday, August 17, 2011 7:57 AM
  • Well, I have tried all of the following but it didnt help:

             string myFile = "C:\\temp\\data.txt";
             RetValue = returnData(myFile);

    and also, 

             RetValue = returnData(byte [] myFile);
    Not sure what am I doing wrong.

    Wednesday, August 17, 2011 5:29 PM
  • Try this maybe:

            [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")]

            public static extern int returnData(char[] fileName);

    And, while calling the function:
            string myFile = "C:\\temp\\data.txt";
             RetValue = returnData(myFile.ToCharArray());
    Wednesday, August 17, 2011 6:15 PM
  • Declare the return variable as StringBuilder if you ever want interop function to return as string.

    The C function expects you allocate memory for it, then pass the pointer of memory to it,, and you help yourself to retrieve string from the pointer after it had done. However GC or even process relocation can be perform when the call is running, so the allocated memory needs to be locked down. StringBuilder will help you properly lock and free the lock in this scenerio. To retrieve the string, just call .ToString() afterwards.

    Thursday, August 18, 2011 2:03 AM
  • In my case, dll interop function will only consume the string since its a file name... it won't return anything except the return status code (which is int).

    For some reason, i am unable to correctly send string.

    Thursday, August 18, 2011 4:15 AM
  • Just try it to see if it works... the important part is the pointer sent to C function may become invalid when the C function actually executes, so you'll want some way to lock it down.
    Thursday, August 18, 2011 4:34 AM
  • as Cheong said use StringBuilder

    StringBuilder in .net corresponds to char* in C++


    Muthu Krishnan.R Use only what you need, Reduce global warming
    Thursday, August 18, 2011 4:47 AM
  • the important part is the pointer sent to C function may become invalid when the C function actually executes
    No GC or relocation can occur until the function returns. It's an obvious requirement for p/invoke to be usable. Using a StringBuilder won't add anything for input parameters.
    Thursday, August 18, 2011 9:25 AM
  • Try changing the calling convention:

    [DllImport("c:\\Temp\\MY.dll", CallingConvention = CallingConvention.Cdecl)]

    Thursday, August 18, 2011 9:50 AM
  • Hello Jay Jardosh,

     

    >> In my case, dll interop function will only consume the string since its a file name... it won't return anything except the return status code (which is int)...

    1. In this case, you should just declare the API as :

    [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")]
    
    public static extern int returnData(string fileName);
    
    
    
    

    Note that there is no "ref" keyword for the fileName parameter. This is what Louis.fr has already indicated,

     

    2. This is also equivalent to :

    [DllImport("c:\\Temp\\MY.dll", EntryPoint = "returnData")] 
    public static extern int returnData([MarshalAs(UnmanagedType.LPStr)] string fileName);

    The interop marshaler will internally allocate a string buffer to contain the string value inside "fileName". It will then pass a pointer to this string buffer to the "returnData" function.

    When the API returns, the string buffer will be automatically freed by the interop marshaler.


    - Bio.

     


    Please visit my blog : http://limbioliong.wordpress.com/
    • Marked as answer by Jay Jardosh Thursday, August 18, 2011 7:09 PM
    Thursday, August 18, 2011 10:00 AM
  • Hi Jay Jardosh,

    Based on your description, I think your problem is related to CLR(Common Language Runtime). So I have moved this thread to "CLR" forum.

    Thank you for understanding.
    Have a nice day! 


    Yoyo Jiang[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, August 19, 2011 1:43 AM
    Moderator
  • Object address can be relocated by GC (GC normally operates on other threads, why would it be blocked?), so StringBuilder is needed to avoid the overhead of copying strings for passing.
    http://msdn.microsoft.com/en-us/magazine/cc164193.aspx#S5

    Regarding the pointer become invalid part, I read it from certain article that explains the use of StringBuilder on interop which I'm unable to find now, that you need this class the lock down the buffer over the process of output parameter passing.

    Friday, August 19, 2011 1:56 AM
  • GC normally operates on other threads, why would it be blocked?

    Any parameter passed to an unmanaged function is either pinned, or copied into unmanaged memory. In either case, the GC won't move or collect the passed parameter. Read the "Copying and Pinning" section of the page you linked to.
    Tuesday, August 23, 2011 8:31 AM