2011-01-19 2 views
0

Я новичок в мире микрософт. У меня много проблем, пытаясь передать простую строку из C# в dll/C++ Я прочитал много сообщений и документации, но проблема такая же.Marshalling string from C# to C++

C++ код

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

C# код

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


Init(hndl.ToInt64(), str); 

, что haeppen является то, что передается долго значение правильно, а параметр строки

0x00000000 <Bad Ptr> 

вы можете мне помочь ... И действительно смущен спасибо !! AG

ответ

1

Вы должны передать строку, url должен быть типа string, а не StringBuilder.

+0

Я сделал быстрый поиск - StringBuilder полезен для Юникода, так что может быть причиной его там. – Tesserex

+0

, но если вы поместите строку, это сработает? –

+0

Нет, очевидно, это не так, потому что у него все еще есть проблема 'int' /' long' ... :) (Также: Почему бы не работать 'StringBuilder'? Не можете ли вы передать его как' [In, Out] '?) – Mehrdad

2

Это потому, что вы неправильно сортируете: long и int в C++ оба (обычно) int в C#.

+0

Почему это плохо, так как передача длинной приведет к тому, что верхние 32-битные (т. Е. 0x00000000) будут использоваться как значение параметр «url», объясняющий проблему, которая наблюдается. –

+0

Сноска: IIRC, that^действует только на 32-битной системе. 64-битные системы передают параметры в регистры, и поэтому вы можете ошибочно получить правильные результаты, потому что регистры являются 64-битными независимо от того, являются ли параметры 64-разрядными или нет. – Mehrdad

+0

OK Я нашел решение. C++ extern "C" __declspec (dllexport) int Init (int l, LPCTSTR url); // Обратите внимание, я изменил символ * в тип данных LPCSTR C# [DllImport ("MCRenderer.dll", CharSet = CharSet.Unicode)] // вынуждены Charset, без Unicode Ловля странных символов в переменной URL в C++ сторона public static extern int Init (int a, string url); IntPtr hndl = renderPanel.Handle; string url = textBox1.Text; Init (hndl.ToInt32(), url); Надеюсь, это вам полезно ... спасибо всем. –

0

От MSDN, вам нужно:

Единственное ограничение в том, что StringBuilder должно быть выделено достаточно места для возвращаемого значения, или текст будет переливаться, вызывая исключение быть брошенной P/Invoke

Кроме того, из Marshaling between Managed and Unmanaged Code

  • не передавайте StringBu ilder по ссылке (с использованием или ref). В противном случае CLR ожидает, что сигнатура этого аргумента будет wchar_t ** вместо wchar_t *, и она не сможет вывести внутренний буфер StringBuilder. Производительность будет значительно снижена.
  • Используйте StringBuilder, когда неуправляемый код использует Unicode. В противном случае CLR должен будет сделать копию строки и преобразовать ее между Unicode и ANSI, что приведет к снижению производительности. Обычно вы должны упорядочить StringBuilder как LPARRAY символов Unicode или как LPWSTR.
  • Всегда указывайте емкость StringBuilder заранее и убедитесь, что емкость достаточно велика, чтобы удерживать буфер. Наилучшей практикой на неуправляемой стороне кода является принятие размера строкового буфера в качестве аргумента, чтобы избежать переполнения буфера. В COM вы также можете использовать size_is в IDL для указания размера.

Таким образом, в вашем примере, вам нужно указать родной размер в качестве параметра StringBuilder как этот StringBuilder str = new StringBuilder(SIZE_OF_NATIVE_STRING);

0

Попробуйте использовать LPCSTR в параметре функции длл

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

Вот хороший пример, который я нашел о том, как это сделать.

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); 
}