2

Вопрос по dll, inno-setup, return-value, pascalscript – Как мне вернуть строку из DLL в Inno Setup Pascal Script

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

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 без сбоев?

10-15 персонажей

от user3274591

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

от user3274591

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

от TLama
1 ответ
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.При использовании строк Unicode убедитесь, что обе стороны согласны с тем, указывается ли Max и / или возвращаемое значение в символах или байтах (в примере кода предполагается, что оно в символах).Перед вызовом функции используйте либо SetLength, либо StringOfChar, чтобы убедиться, что размер буфера соответствует требуемой максимально возможной длине результата.Убедитесь, что вызываемая функция не пытается записать после этой максимальной длины (что легче, если это предоставляется в качестве параметра функции).Убедитесь, что если вы используете Pos, вызываемая функция должна убедиться, что значение завершено нулем (или вам нужно быть более осторожным, чем показано в примере).Убедитесь, что после вызова вы усекаете строку до фактической длины, либо используя возвращаемое значение, либо найдя нулевой терминатор.

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

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

от user3274591

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

от Miral

Правда. Починил это.

от Miral

Если это решило вашу проблему, вы должныпринять это.

от Miral

Я считаю, что это должно бытьSetLength(Buffer, Pos(#0, Buffer) - 1); (Обратите внимание- 1)

от Martin Prikryl

Похожие вопросы