FASM - Предаване на низ към Delphi DLL

Имам 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. (Като вземем предвид отговора на Jens), ако FASM е ansi, използвайте procedure xMain(MSG:PAnsiChar);export; и MessageBoxA, ако е unicode, използвайте procedure xMain(MSG:PChar);export; и MessageBox. Също така посочете вашата конвенция за повикване в експорта (f.i. 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 Lol, благодаря. Добавих го.   -  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. Що се отнася до приемането, обикновено предполагам, че каквото и да задържаше OP, беше преодоляно само с действителен компилируем код. Но бих очаквал това да се случи преди около седмица, така че наистина не знам.. Във всеки случай съм сигурен, че 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 и отговорът на Sertac подкрепя това
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: Низът се съхранява като „db“ във FASM, а не като „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