2013-07-03 4 views
0

Я пытаюсь использовать PInvoke для вызова неуправляемой функции из C dll. В связи с тем, что источник dll не может быть выпущен разработчикам, некоторые из них вызвали функцию в Delphi, используя следующую декларацию. Мы используем SAT.dll с конвенцией о вызове CDECL.AccessViolationException при вызове функции C из dll на C#

function AssociarAssinatura(numeroSessao : Longint; codigoDeAtivacao: PChar; 
       CNPJvalue : PChar; assinaturaCNPJs : PChar) : PChar ; 
       cdecl; External 'SAT.DLL'; 

На основе этой структуры, я сделал следующее консольное приложение в C#, чтобы проверить ту же самую функцию из одной и той же DLL. Я сделал некоторые исследования и выяснил, что эквивалент Longint в delphi является int в C#, и эквивалент PChar является указателем на строку (но я использовал строку C#).

class Program 
{ 
    [DllImport("SAT.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern string AssociarAssinatura(int numeroSessao, 
     string codigoDeAtivacao, string CNPJvalue, string assinaturaCNPJs); 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Comienza"); 
     int numeroSessao = 111111; 
     string codigoDeAtivacao = "123123123"; 
     string cnpJvalue = "2222222222222211111111111111"; 
     string assinaturaCnpJs = "lrafwegmqcgvpzpbdmcmcgdvf"; 
     string resposta = AssociarAssinatura(numeroSessao, codigoDeAtivacao, 
       cnpJvalue, assinaturaCnpJs); 

     Console.WriteLine(resposta); 

    } 
} 

Когда я вызываю функцию, вызывается исключение AccesViolationException. Код AssociarAssinatura имеет некоторые внутренние отпечатки, которые показывают, что код из функции действительно работает хорошо. Из-за этого, я думаю, проблема связана, когда функция возвращает ее значение. Мое лучшее предположение заключается в том, что у меня возникают проблемы с вызывающим соглашением. Есть предположения?

+0

Он падает, когда маркерщик pinvoke пытается освободить возвращенную строку. Вам нужно объявить возвращаемый тип как IntPtr и маршалировать его самостоятельно с помощью Marshal.PtrToStringAnsi(). Но у вас все еще нет хорошего способа освободить строку, которая станет утечкой памяти, которая в конечном итоге приведет к сбою вашей программы с помощью OOM. –

+0

Есть ли что-нибудь, что я могу сделать? – Levrak

+0

Это сработало! Благодаря! @HansPassant – Levrak

ответ

0

Ваша проблема здесь, скорее всего, связана с вашим типом PChar в Delphi. В C# строки по умолчанию Unicode, и при вызове функции func фактически будет преобразование из PChar в PWideChar, что означает, что новый блок памяти будет выделен для хранения этого нового PWideChar. Этот interop и разница между тем, как строки обрабатываются в .NET и Delphi, более чем вероятно вызывает ваш AccessViolationException.

Вы можете использовать атрибут MarshalAs явно указать .NET, как обрабатывать конкретный тип:

[DllImport("SAT.dll", CallingConvention = CallingConvention.Cdecl)] 
private static extern string AssociarAssinatura(int numeroSessao, 
    [MarshalAs(UnmanagedType.LPStr)] string codigoDeAtivacao, [MarshalAs(UnmanagedType.LPStr)] string CNPJvalue, [MarshalAs(UnmanagedType.LPStr)] string assinaturaCNPJs); 

Какой будет явно указать, как обрабатывается строка. После этого ваш код должен быть в порядке.

+0

К сожалению, это все равно бросает одно и то же исключение. Должен ли я попытаться использовать другие неуправляемые типы для строк? – Levrak

+0

Как насчет типа возврата? Должен ли он быть также организован? – Levrak

+0

Вы можете попробовать добавить '[return: MarshalAs (UnmanagedType.LPStr)]' к вашей сигнатуре pinvoke. – aevitas

Смежные вопросы