2014-02-05 10 views
2

У меня есть две функции C в DLL, которые определены в файле определения и экспортированы для использования в Inno Setup.Как вернуть строку из DLL в Inno Setup Pascal Script

char* __stdcall GetName() 
{ 
     return "Kishore"; 
} 
void __stdcall getName(char* strName) 
{ 
    strcpy(strName, "Kishore"); 
} 

Inno Setup код будет загружать пользовательские библиотеки DLL и вызвать функцию/процедуру, чтобы вернуть имена

{ Inno Setup script } 
[Code] 
procedure getName(MacAddress: String); 
external '[email protected]:MyDll.dll stdcall setuponly'; 

function GetName():PAnsiChar; 
external '[email protected]:MyDll.dll stdcall setuponly'; 

function NextButtonClick(CurPage: Integer): Boolean; 
var 
    StrName: String; 
begin 
    SetLength(StrName,15);  
    getName(StrName); { displaying only single character } 
    StrName := GetName(); { this call is crashing } 
end 

Как я могу получить имя в Inno Setup сценарий без него сбой?

+0

Измените прототип функции 'getName', чтобы использовать' AnsiString' вместо 'string', поскольку вы использовали версию Inno Setup Unicode, но тип' char' в вашем коде на C. И не используйте функцию 'GetName', потому что DLL должна будет выделить и освободить память для строки, которая семантически ошибочна. – TLama

+0

Я хочу получить значение из getName и использовать «StrName» для какой-либо цели. Имя отображается в dll, но когда оно возвращается к сценарию inno, значение символа является одиночной цифрой. С вашим sugesstion также он не работал – user3274591

+0

10-15 символов – user3274591

ответ

2

GetName должен вернуть const char *, однако в остальном это прекрасно. Обратите внимание, однако, что возвращение такой строки может только когда-либо работать для строковых строковых констант, как показано выше. Вы не можете использовать этот шаблон для возврата вычисленного строкового значения (если вы попробуете это, оно, скорее всего, приведет к краху или даст поврежденные данные); таким образом, getName является неправильным.

Также обратите внимание, что хотя C чувствителен к регистру, Pascal нет, поэтому getName и GetName - это те же функции в скрипте Inno. Вам может избежать этого в приведенном выше случае, потому что параметры разные, но я бы не стал полагаться на это - вы должны дать им разные имена. (Не используйте то же имя на стороне C либо, так как экспорт DLL иногда посмотрел регистронезависимо тоже.)

Чтобы вернуть вычисленную строку, вы должны использовать шаблон, как это:

DLL код:

void __stdcall CalculateName(char *buffer, size_t size) 
{ 
    strncpy(buffer, "whatever", size); 
    buffer[size-1] = 0; 
} 

Inno код: есть

procedure CalculateName(Buffer: AnsiString; Max: Cardinal); 
external '[email protected]:my.dll stdcall'; 

... 
Max := 16; 
Buffer := StringOfChar(#0, Max); 
CalculateName(Buffer, Max); 
SetLength(Buffer, Pos(#0, Buffer) - 1); 
... 

несколько приемлемых вариантов, например, вы можете сделать функцию DLL возвращать число символов на самом деле написано в буфер и использовать это в последующей SetLength, а не вызывать Pos, чтобы найти нулевой ограничитель.

Но вы должны:

  • Убедитесь, что обе стороны используют одни и те же типы строк, либо как ANSI или Unicode как.
    • ANSI Inno Setup поддерживает только строки ANSI с его типом String.
    • Unicode Inno Setup поддерживает либо строки ANSI с AnsiString, либо строки Unicode с String.
  • При использовании строк в Юникоде убедитесь, что обе стороны согласны с тем, указано ли значение Max и/или возвращаемое значение в символах или байтах (код примера предполагает, что он находится в символах).
  • Перед вызовом функции используйте SetLength или StringOfChar, чтобы убедиться, что размер буфера соответствует требуемой максимально возможной длине результата.
  • Убедитесь, что вызываемая функция не пытается записать эту максимальную длину (что проще, если это предусмотрено как параметр функции).
  • Убедитесь, что если вы используете Pos, вызываемая функция должна гарантировать, что значение имеет нулевое завершение (или вам нужно быть более осторожным, чем показано в примере).
  • Убедитесь, что после вызова вы обрезаете строку до фактической длины либо с помощью возвращаемого значения, либо путем поиска нулевого терминатора.

Одно из ограничений в игре заключается в том, что память, выделенная одной стороной, должна быть освобождена с той же стороны. Вы не можете безопасно освободить память, выделенную на «неправильной» стороне границы DLL, в любом направлении.

+0

Я попробую ваш метод и подтвержу вас. Я также попытался с изменением параметра для процедуры «void __stdcall getName (char * strName)» на «void __stdcall getName» (LPTSTR strName) ", и он отлично работал и добавил setlength в inno перед вызовом getName – user3274591

+0

Если вы использовали' LPTSTR' в DLL **, а также **, скомпилированный с включенным Unicode в проекте, то он будет соответствовать типу 'String' используемый Unicode Inno (а не тип 'String', используемый Ansi Inno, если вы не скомпилировали DLL * без * Unicode). Как я уже сказал, вам нужно убедиться, что ваши типы строк совпадают с обеих сторон, чтобы они работали. – Miral

+1

Если это решило вашу проблему, вы должны [принять это] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work). – Miral

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