0

C++ で Delphi DLL を読み込んでいます。char* をバッファーとして使用する関数 (プロシージャーのパラメーターとして char* を指定) を使用すると、ゴミデータしか得られません。char* を返す関数がある場合、すべて問題ありません。

私はC ++を初めて使用し、これをクラックするために多くの時間を費やしています。助けてください。

以下のコードですべてを説明します。私が言いたいことを正確に示すために、3つの関数を入れました。

バッファに問題がある関数の例は次のとおりです。 DLL_PingConnection(var avXml:PChar):Boolean; - true/false を返します。パラメーターとしてバッファーを取り、関数はバッファーで実行されます。有効な 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 ビルダー 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++ ビルダーで小さな問題が発生しました。この環境ではバッファを消去できません:

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 ** を使用すると、バッファとの型の不一致が発生します。

EDIT2:

David Heffernan のリクエストに応じて、ドキュメントのサンプルを添付します。重要な部分は英語に翻訳されています。Rest は、PIngConnection が返すべき xlm の単なる構造です。そこにはあまり役に立ちません - ドキュメント全体はこのようなものです。

ここに画像の説明を入力

PS: ここで同様の質問をしました: Trash characters when using buffers in c++ - code based on WxWidgets (私は WxWidgets が問題を引き起こしますが、そうではありません。おそらく誰かが WxWidgets コードを役に立つと思うでしょう)。

編集3:

dll に関する詳細情報を得ることができました。

Delphi のバージョンは 7 です。

確かに呼び出しタイプは stdcall です。( DLL_PingConnection: function(var avXml: PChar): Boolean; stdcall; )

これは、この dll の関数が Delphi で呼び出される方法です。

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;

4

1 に答える 1