2010-12-13 3 views
4

Моего вопроса немного общий, так что я не искал точный ответ, но, возможно, некоторые направления, чтобы смотреть на это мне поможет ...C# DllImport Проблема

На моем рабочем месте я программа в основном в C#. У нас есть эта сторонняя компания, с которой мы работаем, что дало нам CMS-версию Native, которую мы должны использовать. Поскольку метод C++, который мне нужен, не был показан так, как это было легко ссылаться на C#, я завернул dll в другую Native C++ Dll.

Итак, теперь у меня есть 2 родных C++ dlls, одна из которых обертывает другую.

Я создал небольшое консольное приложение C#, которое вызывает метод, который я создал на C++. Моего метод подпись выглядит следующим образом:

[DllImport("HashMethodWrapper.dll")] 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string CreateHash(
      string input, 
      [MarshalAs(UnmanagedType.LPStr)]StringBuilder output); 

В моем консольном приложении, все работает отлично, и я всегда получаю строку IM, ожидающий в результате.

Но когда я перехожу к веб-службе или созданному веб-приложению (так как это именно то, что мне действительно нужно), я вижу, что получение строки im является мусором и даже не согласовано. Кажется, что я получаю только некоторую ссылку на память, которая потеряна или что-то в этом роде, но это только моя догадка ...

Я не знаю, почему это происходит, поскольку в моем приложении консоли все работает хорошо.

Кто-нибудь есть направление, которое могло бы помочь мне ??? ...

Спасибо заранее, gillyb

Edit: Я думал, что это, возможно, придется делать с некоторыми незакрепленных предметов, поэтому я попробовал называть метод в фиксированном заявлении, что-то вроде:

unsafe public static string CreateHashWrap(string pass) 
{ 
    String bb; 
    StringBuilder outPass = new StringBuilder(); 
    fixed (char* resultStr = CreateHash(pass, outPass)) 
    { 
     bb = new String(resultStr); 
    } 
    return bb; 
} 

... но это все еще не делало этого для меня. Правильно ли это связывать объекты?

второй Edit: Метод подписи в C++ выглядит следующим образом:

extern "C" __declspec(dllexport) char *CreateRsaHash(char *inputPass, char *hashPass); 

третий Edit: Я изменил подпись метода, чтобы быть

extern "C" __declspec(dllexport) bool CreateRsaHash(char *inputPass, char *hashPass); 

и возвращаемое значение im look to находится в параметре *hashPass.

Теперь я создал простое консольное приложение для его проверки. Когда вы вставляете DllImport в мой основной класс и напрямую вызываете метод, все работает отлично, но когда я перемещаю DllImport и обертываю метод в другом классе и вызываю этот класс из метода «Main» Console, я получаю исключение StackOverflow!

У кого-нибудь есть идеи, почему это происходит?

+0

Не могли бы вы показать нам, как заголовок функции объявлен в C/C++. Это может помочь :) –

+0

Убить автора API, происходит очень четкая утечка памяти ... – leppie

+0

Почему ??? не могли бы вы объяснить, почему, и почему это так ясно из подписи? Надеюсь, мы все еще можем это исправить! – gillyb

ответ

0

Я нашел решение своей проблемы, и теперь я чувствую себя любопытным (если не очень!) Глупо ...: |

Я использовал метод LoadLibrary() в C++ для динамического вызова метода из другой родной dll. Проблема заключалась в том, что я не дал методу никакого пути и просто имя файла dll. В .net он бы искал в текущей папке, но, похоже, в собственном коде это не работает.

Большая проблема в моей практике программирования, очевидно, заключается в том, что я не полностью охватывал обработку ошибок в своей родной C++ dll!

Всех asnwers я получил на этой странице, были не зря, хотя ...

После того, как я узнал, что я имел проблемы с путем каталога, я сталкивался с разными исключениями о попытке доступа к повреждению памяти, и т. д. Затем мне нужно было создать закрепленные объекты и объявить размер для моего объекта StringBuilder.

Спасибо всем за помощь!

:)

+0

Nice. Отличная работа. –

1

Это очень трудно узнать из редкой информации, но если бы я должен был догадаться, я бы сказал, что вам нужно убедиться, что вы закрепляете выходной объект.Также я бы, вероятно, изменил выходной параметр на какой-то другой тип, кажется довольно странным, что StringBuilder работает откровенно.

Я знаю, что если вы выделите объект, он получит указатель, но это не значит, что он не будет двигаться. Поэтому, если вы попытаетесь передать указатель на управляемый объект в неуправляемую среду, вам нужно убедиться, что вы скажете GC «закрепить» память, чтобы она не вышла из-под вас.

Вот очень грубый вариант того, что я имею в виду, закрепив:

string input = "..."; 
StringBuilder output = new StringBuilder(); 
var handle = System.Runtime.InteropServices.GCHandle.Alloc(output, GCHandleType.Pinned); 
try 
{ 
    CreateHash(input, output); 
} 
finally 
{ 
    handle.Free(); 
} 
+0

Ну, о StringBuilder, я где-то читал, что мне понадобится стробоструй, если значение изменится, так как «String» является неизменным и не будет выполнять эту работу в этом случае. Это правда ? – gillyb

+0

И о закрепленном объекте, я подумал, что это может быть проблемой, поэтому я попытался сделать фиксацию. Я добавлю его в свой вопрос, не могли бы вы рассказать мне, в чем разница между тем, что я сделал, и тем, что вы показали мне с GCHandle.Alloc ?? – gillyb

+0

Две вещи: вы привязали символ *, но не StringBuilder.Также почему у вас есть StringBuilder, который называется «output», а также возвращаемое значение? Кажется, что вы полностью игнорируете StringBuilder и просто возвращаете возвращаемое значение. –

0

Я хотел бы рассмотреть, чтобы деформировать внутри C# совместно сборки/DLL вместо C++ DLL, а затем попытаться получить консольное приложение к работа с dll. Это хорошая практика, чтобы обернуть внешние зависимости таким образом в любом случае.
В противном случае некоторые традиционные проблемы - 32 против 64 бит, путь загрузки к общей библиотеке. Это действительно только строка или что-то более сложное?

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