1

I am new in microsoft world. I have lot of problem trying to pass a simple string from c# to dll/c++ I have read a lot of post and documentation about but the problem is the same.

C++ code

extern "C" __declspec(dllexport) int Init( long l , char* url );

C# code

[DllImport("MCRenderer.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = false)]
    public static extern int Init(long a, StringBuilder url);


Init(hndl.ToInt64(), str );

what haeppen is that long value is passed correctly while string parameter is

0x00000000 <Bad Ptr>

can you help me ... Iam really confused thanks!! AG

4 Answers 4

2

You should pass a string, url should be of type string and not StringBuilder.

Sign up to request clarification or add additional context in comments.

3 Comments

I did a quick lookup - StringBuilder is useful for unicode, so that may be the reason it's there.
No, obviously it doesn't, because it still has the int/long problem... :) (Also: Why wouldn't StringBuilder work? Can't you pass it as [In, Out]?)
@Lambert - StringBuilder is passed as [InAttribute, OutAttribute] by default
2

It's because you're marshalling incorrectly: long and int in C++ are both (usually) int in C#.

3 Comments

Why this is bad is that passing a long will cause the upper 32-bits (i.e., 0x00000000) to be used as the value of of the url parameter, explaining the problem that is being observed.
Footnote: IIRC, that^ is only true on a 32-bit system. 64-bit systems pass the parameters in registers, and so you might mistakenly get correct results because the registers are 64-bit regardless of whether the parameters are 64-bit or not.
OK I found a solution. C++ extern "C" __declspec(dllexport) int Init( int l , LPCTSTR url ); // Note I changed char* into LPCSTR data type C# [DllImport("MCRenderer.dll" , CharSet=CharSet.Unicode) ] // forced Charset, without Unicode I catch strange characters in the variable url in c++ side public static extern int Init(int a, string url); IntPtr hndl = renderPanel.Handle; string url = textBox1.Text; Init(hndl.ToInt32(), url); Hope this is useful for you ... thanx everybody.
2

From MSDN, you need to:

The only caveat is that the StringBuilder must be allocated enough space for the return value, or the text will overflow, causing an exception to be thrown by P/Invoke

Also from Marshaling between Managed and Unmanaged Code

  • Don't pass StringBuilder by reference (using out or ref). Otherwise, the CLR will expect the signature of this argument to be wchar_t ** instead of wchar_t *, and it won't be able to pin StringBuilder's internal buffer. Performance will be significantly degraded.
  • Use StringBuilder when the unmanaged code is using Unicode. Otherwise, the CLR will have to make a copy of the string and convert it between Unicode and ANSI, thus degrading performance. Usually you should marshal StringBuilder as LPARRAY of Unicode characters or as LPWSTR.
  • Always specify the capacity of StringBuilder in advance and make sure the capacity is big enough to hold the buffer. The best practice on the unmanaged code side is to accept the size of the string buffer as an argument to avoid buffer overruns. In COM, you can also use size_is in IDL to specify the size.

So in your example, you need to specify the native size as the parameter of the StringBuilder like this StringBuilder str = new StringBuilder(SIZE_OF_NATIVE_STRING);

Comments

1

Try using LPCSTR in the dll function parameter

extern "C" __declspec(dllexport) int Init( long l , **LPCTSTR** url );

Here is a good example that I found on how to do this.

C++:

extern "C" __declspec(dllexport) void doSomething(LPCTSTR asString)
{
    std::cout << "here" << (wchar_t)asString << endl;
    system ("pause");
}

C#:

class Program
{
    static void Main(string[] args)
    {
        String myString = "String in C#";
        doSomething(myString);
    }
    private const String path = @"C:\testdll2.dll"; //Make sure that the DLL is in this location

    [DllImport(path)]
    private static extern void doSomething(string asString);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.