我正在用 C++ 加载一个 delphi dll。当我使用带有 char* 的函数作为缓冲区(char* 作为过程的参数)时,我只得到垃圾数据。当我有返回 char* 的函数时,一切都很好。
我是 C++ 新手,我花了很多时间试图破解它。请帮忙。
一切都在下面的代码中解释。我已经放了 3 个函数来准确显示我的意思。
缓冲区有问题的示例函数是:DLL_PingConnection(var avXml:PChar):Boolean; - 它返回真/假,作为参数它需要缓冲区并且函数在缓冲区中完成应该有有效的xml(但只有垃圾)
#include <windows.h> //this will load delphi dll
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>
using namespace std;
// ------------------------------------------------ pointers on functions inside Delphi DLL (32 bits)
typedef bool(*TYPE_DLL_SetLicense)(char*, char*); //initialize dll stuff - I load licence from a file into char* - everything works fine
typedef bool(*TYPE_DLL_PingConnection)(char*); //the char* is buffer - I give empty char* as parameter and I should get correct xml with serwer data - I GET ONLY TRASH :(
typedef char*(*TYPE_DLL_ERR_DESCRIPTION)(void); //this function does not use buffer it returns char* - everything works fine
//so as you see problem is with buffers and function like this: DLL_PingConnection(buffer)
int main()
{
// ------------------------------------------------ Loading the library
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\full_path\\SOMEDLL.dll");
//checking the library
if (hGetProcIDDLL == NULL) {std::cout << "Could NOT load the dynamic library" << std::endl;return EXIT_FAILURE;}
else{std::cout << "dynamic library loaded" << std::endl;}
// ------------------------------------------------ START: resolving functions adresses
TYPE_DLL_SetLicense DLL_SetLicense = (TYPE_DLL_SetLicense)GetProcAddress(hGetProcIDDLL, "DLL_SetLicense");
if (!DLL_SetLicense) {std::cout << "Could NOT locate the function: DLL_SetLicense" << std::endl;return EXIT_FAILURE;}
else{std::cout << "Function DLL_SetLicense located" << std::endl;}
TYPE_DLL_PingConnection DLL_PingConnection = (TYPE_DLL_PingConnection)GetProcAddress(hGetProcIDDLL, "DLL_PingConnection");
if (!DLL_PingConnection) {std::cout << "Could NOT locate the function: DLL_PingConnection" << std::endl;return EXIT_FAILURE;}
else{std::cout << "Function DLL_PingConnection located" << std::endl;}
TYPE_DLL_ERR_DESCRIPTION DLL_ERR_DESCRIPTION = (TYPE_DLL_ERR_DESCRIPTION)GetProcAddress(hGetProcIDDLL, "DLL_ERR_DESCRIPTION");
if (!DLL_ERR_DESCRIPTION) {std::cout << "Could NOT locate the function: DLL_ERR_DESCRIPTION" << std::endl;return EXIT_FAILURE;}
else{std::cout << "Function DLL_ERR_DESCRIPTION located" << std::endl;}
std::cout << "\n\nInitialization over. \n\n" << std::endl;
// ------------------------------------------------ START: calling functions from delphi dll
//DLL_SetLicence - this function take buffer as parameter, but dont return anything into the buffer. All works fine.
//start - we read licence from file
char buffer_licence[1242];
memset(buffer_licence,0,sizeof(buffer_licence));
//I read content of buffer_licence usinf ifstream from the file here (but I don't put the code, to keep sample minimal)
//we set licence with dll function
bool is_licence = DLL_SetLicense(buffer_licence,(char*)"");
//the output
if (is_licence == TRUE)
std::cout << "Licence has been set\n";
else
std::cout << "Licence has been NOT set\n";
//DLL_PingConnection - it takes empty buffer as parameter, it should save xml into buffer but it saves only trash.
//we try to save ping to the file - buffer
char buffor_ping_xml[2000];
memset(buffor_ping_xml,0,sizeof(buffor_ping_xml));
//this should gieve proper xml, but it returns only trash.... please help
bool is_ping = DLL_PingConnection(buffor_ping_xml);
if(is_ping)
{
std::cout << "DLL_PingConnection True\n"; //function returned true, so it worked correct.
std::cout << buffor_ping_xml; //but in the buffer is trash that I show on the screen. I also tried to put buffor_ping_xml info the file (diferent ways) but always result was trash just like on screen.
}
else
{
std::cout << "DLL_PingConnection False: \n";
}
//DLL_ERR_DESCRIPTION - if will automaticly return error description if there is any error to report. No buffer, no problems.
std::cout << buffor_ping_xml; //the data on screet is fine, so is in file and everywhere else.
return EXIT_SUCCESS;
}
PingConnection 函数将只返回这个而不是好的 xml。
编辑:
最初我使用的是 Netbeans + MinGW,但正如评论中所建议的,我使用了替代编译器:Borland builder c++ 6.0 和 Embarcadero RAD Studio XE3 (C++ Builder)。即使我使用了 Remy Lebeau 提到的所有调用约定类型,问题仍然存在。
typedef bool(*TYPE_DLL_PingConnection)(char*); //standard calling convention default for compiler - returns trash
typedef bool(__cdecl *TYPE_DLL_PingConnection)(char*); //returns trash also
typedef bool(__stdcall *TYPE_DLL_PingConnection)(char*); //doesnt write anything to the buffer
typedef bool(__fastcall *TYPE_DLL_PingConnection)(char*); //returns trash
我在 c++ builder 下遇到了小问题。在这种环境下我无法清理缓冲区:
memset(buffer,0,sizeof(buffer)); // will crash the program under c++ builder
尝试使用 'char *&' 也会使程序崩溃。
typedef bool(__cdecl *TYPE_DLL_PingConnection)(char*&);
OR
typedef bool(__stdcall *TYPE_DLL_PingConnection)(char*&);
OR
typedef bool(__fastcall *TYPE_DLL_PingConnection)(char*&);
char * buffer;
bool is_ping = DLL_PingConnection(buffer);
使用 char ** 会导致类型与缓冲区不匹配。
编辑2:
根据 David Heffernan 的要求,我附上了文档样本。重要部分被翻译成英文。Rest 只是 PIngConnection 应该返回的 xlm 结构。那里没有太多帮助 - 整个文档都是这样的。
PS:我在这里问过类似的问题:Trash characters when using buffers in c++ - code based on WxWidgets(我虽然 WxWidgets 会产生问题,但事实并非如此。也许有人会发现 WxWidgets 代码对你有用)。
编辑 3:
我设法获得了有关 dll 的更多信息。
德尔福版本是7。
确定调用类型是stdcall。( DLL_PingConnection: function(var avXml: PChar): Boolean; stdcall; )
这是在 delphi 中调用此 dll 中的函数的方式:
lPointer := nil; //pointer
lOSOZPointer := nil; //pointer
lpXML := nil; //pChar
lpXML:=StringToPChar(lXML);
lPointer := lpXML;
lWynik:=OSOZ_GetServerDataTime(lpXML);
if lWynik then
begin
lOSOZPointer := lpXML;
//akcja na wyniku
end;
if lPointer <> nil then begin
Freemem(lPointer);
end;
if lOSOZPointer <> nil then begin
OSOZ_FreeMem(lOSOZPointer);
end;