FASM — передача строки в DLL Delphi

У меня есть dll, закодированная в Delphi XE2 со следующим кодом:

procedure xMain(MSG:String);export;
begin
  MessageBox(0,PWideChar(MSG),'Title',0);
end;

exports xMain;

Теперь я импортирую эту функцию в приложение FASM следующим образом:

library  dllfile, "testdll.dll"

import   dllfile,\
         xMain,   "xMain"

И использование таково:

section ".data" data readable writeable

szMSG     db "Message from FASM application!",0

section ".code" code readable executable

invoke    xMain,szMSG

Но результирующее окно сообщений появляется с искаженными символами:

введите здесь описание изображения

Это точный результат вызова функции.

Как мне подойти к решению этой проблемы?


person Josh Line    schedule 22.10.2012    source источник
comment
Эта ошибка может возникнуть из-за того, что либо ваша библиотека DLL, либо ваше приложение использует кодировку Unicode для хранения строк, в то время как другая использует кодировку ASCII. Я часто получал подобные тексты, когда совершал одну и ту же ошибку. Хотя это всего лишь предположение.   -  person beta    schedule 23.10.2012
comment
Вместо этого я попытался вызвать MessageBoxW, тот же результат. Я также попытался преобразовать строку, однажды переданную функции в dll, в AnsiString. Тем не менее, не повезло.   -  person Josh Line    schedule 23.10.2012
comment
Джош. Вы не обращаетесь к тому, о чем предупреждает @beta, используя MessageBoxW. (Принимая во внимание ответ Йенса), если FASM - это анси, используйте procedure xMain(MSG:PAnsiChar);export; и MessageBoxA, если это юникод, используйте procedure xMain(MSG:PChar);export; и MessageBox. Также укажите свое соглашение о вызовах в экспорте (например, stdcall), я не знаю, как бы вы это сделали на стороне FASM.   -  person Sertac Akyuz    schedule 23.10.2012
comment
Да, это то, что я сделал, в основном. Я заявил, что пытался преобразовать в Ansi, то есть использовал xMain(MSG:PAnsiChar);export; Прочитав ваше сообщение, я попробовал xMain(MSG:PAnsiChar);export;stdcall; окно сообщений теперь отображается пустым .... И отображается так же, как в OP без stdcall в dll.   -  person Josh Line    schedule 23.10.2012
comment
@Josh - Может быть, вы хотели бы рискнуть с другими разработчиками Delphi, добавив соответствующий тег.   -  person Sertac Akyuz    schedule 23.10.2012
comment
@SertacAkyuz Лол, спасибо. Я добавил это.   -  person Josh Line    schedule 23.10.2012
comment
@JoshLine попробуйте включить win32w и использовать du вместо db, тогда это должно сработать   -  person    schedule 26.10.2012
comment
@Josh - я опубликовал ответ - посмотрите, рабочий ли это ответ.   -  person Sertac Akyuz    schedule 30.10.2012


Ответы (3)


Вот два рабочих примера (с использованием FASM 1.70.03 для Windows):

Версия Ansi,
dll:

library testdll;

uses
  windows;

procedure xMain(MSG: PAnsiChar); export; stdcall;
begin
  MessageBoxA(0, PAnsiChar(MSG), 'Title', 0);
end;

exports xMain;

begin
end.

EXE:

format PE CONSOLE 4.0
entry start

include 'win32a.inc'

section '.code' code readable executable
  start:
    invoke xMain, szMSG
    invoke ExitProcess, 0

section '.data' data readable writeable
    szMSG db 'Message from FASM application!', 0

section '.idata' import data readable writeable
  library kernel32, 'kernel32.dll',\
          dllfile, 'testdll.dll'

  include 'api\kernel32.inc'

  import dllfile,\
         xMain, 'xMain'


Версия Unicode,
dll:

library testdll;

uses
  windows;

procedure xMain(MSG: PChar); export; stdcall;
begin
  MessageBox(0, PChar(MSG), 'Title', 0);
end;

exports xMain;

begin
end.

EXE:

format PE CONSOLE 4.0
entry start

include 'win32w.inc'

section '.code' code readable executable
  start:
    invoke xMain, szMSG
    invoke ExitProcess, 0

section '.data' data readable writeable
    szMSG du 'Message from FASM application!', 0

section '.idata' import data readable writeable
  library kernel32, 'kernel32.dll',\
          dllfile, 'testdll.dll'

  include 'api\kernel32.inc'

  import dllfile,\
         xMain, 'xMain'
person Sertac Akyuz    schedule 29.10.2012
comment
Действительно очень хорошо. Ради ясности я бы предпочел использовать PWideChar. И W версии вызовов API. Кроме того, нет необходимости в несуществующем ключевом слове экспорта. +1 - person David Heffernan; 01.11.2012
comment
@David - Спасибо! Я считаю маловероятным, что ни один из комментариев/ответов здесь не помогает решить исходную проблему. Сейчас я считаю этот вопрос фиктивным и за него проголосовали как таковой. Жаль, что многие люди потратили время на такое.. - person Sertac Akyuz; 02.11.2012
comment
Мне нравится, что этот ответ был принят и награжден наградой. Но мой ответ был признан неверным, несмотря на то, что в этом ответе содержится код, идентичный версии ANSI. - person David Heffernan; 10.11.2012
comment
@David - Награда (половина) была присуждена сообществом в соответствии с правилами вознаграждения, а не ОП. Что касается принятия, я бы обычно предположил, что все, что сдерживало OP, было преодолено только с помощью фактического компилируемого кода. Но я ожидаю, что это произойдет около недели назад, поэтому я действительно не знаю. ответ во время принятия. - person Sertac Akyuz; 11.11.2012

Ваш вывод — это то, что происходит, когда вы отправляете текст ANSI функции, которая ожидает текст в кодировке UTF-16. Из чего я делаю вывод, что ваш код FASM отправляет полезную нагрузку ANSI в DLL. И DLL скомпилирована в Delphi, поддерживающем Unicode, для которого string означает UnicodeString, Char означает WideChar и так далее.

Вам нужно, чтобы две стороны совпадали. Например, изменив код Delphi:

procedure xMain(Msg: PAnsiChar); stdcall;
begin
  MessageBoxA(0, Msg, 'Title', 0);
end;

Некоторые другие моменты, на которые следует обратить внимание:

  1. Вам не нужно export в конце объявления функции. Он игнорируется современными компиляторами Delphi.
  2. Не используйте управляемую строку Delphi за пределами модуля. В любом случае на стороне FASM вы объявили параметр как указатель с завершающим нулем на массив символов в кодировке ANSI. А это PAnsiChar.
  3. В вашем коде используется соглашение о вызовах Delphi register. Трудно поверить, что FASM использует это. Я ожидаю stdcall, и ответ Сертака подтверждает это
person David Heffernan    schedule 23.10.2012
comment
@Sertac Очевидно, что происходит. Иногда требуется ответ с некоторыми подробностями, чтобы донести сообщение. - person David Heffernan; 23.10.2012
comment
Разве это не так? Я не вижу никаких доказательств того, что вы исправили все проблемы, которые я поднял. - person David Heffernan; 28.10.2012

Вы уверены, что ваш аргумент MSG должен быть String, а не PChar?

person Jens Björnhager    schedule 22.10.2012
comment
Я также безуспешно пытался использовать PChar для типа переменной param в dll. Тот же результат, что и раньше. - person Josh Line; 23.10.2012
comment
PAnsichar, а не PChar: строка хранится в FASM как «db», а не «du». - person Roddy; 23.10.2012
comment
@JensBjörnhager Действительно. docwiki.embarcadero.com/Libraries/XE2/en/System.PChar - person Roddy; 24.10.2012
comment
Я также пробовал PAnsiChar. Я пробовал каждый тип данных, который мог придумать в отношении символов/строк.... - person Josh Line; 25.10.2012