在char *中获取垃圾数据,同时在函数中使用它作为缓冲区 [英] Getting trash data in char* while using it as buffer in function

查看:209
本文介绍了在char *中获取垃圾数据,同时在函数中使用它作为缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在c ++中加载了一个delphi dll。当我使用char *作为缓冲区的函数(char *作为过程的参数),我只得到垃圾数据。
当我有函数返回char *一切都很好。

I'm loading a delphi dll in c++. When I use functions with char* as buffers (char* given as parameter to the procedure) I get only trash data. When I have functions that return char* all is fine.

我是c ++的新手,我花了很多时间试图破解这个。请帮助。

I'm new to c++ and I spend a lot of time trying to crack this. Please help.

一切都在下面的代码中解释。

Everything is explained in code below. I have put there 3 functions to show exacly what I mean.

与缓冲区有问题的示例函数是:
DLL_PingConnection(var avXml:PChar):Boolean ; - 它返回true / false,作为参数它需要缓冲区和函数在缓冲区完成,应该有有效的xml(但只有垃圾桶)

Example function that has problem with buffer is: DLL_PingConnection(var avXml:PChar):Boolean; - it returns true/false, as parameter it takes buffer and the function is done in buffer there should be valid xml (but there is only trash)

#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。

PingConnection function will return only this instead of good xml.

>

编辑:

Oroginally我使用Netbeans + MinGW,但正如建议在评论中我使用替代编译器:Borland builder c ++ 6.0和Embarcadero RAD Studio XE3 (C ++ Builder)。

Oroginally I used Netbeans + MinGW, but as suggested in comments I have used alternative compilers: Borland builder c++ 6.0, and Embarcadero RAD Studio XE3 (C++ Builder). The problems stayed the same even thou I used all calling convention types Remy Lebeau mentioned.

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下遇到小问题。我不能清除这个环境下的缓冲区:

I have encountered small problem under c++ builder. I can't clean buffer under this enviroment:

memset(buffer,0,sizeof(buffer)); // will crash the program under c++ builder

尝试使用'char *&程序也。

Trying to use 'char *&' will crash the program also.

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 **会导致类型与缓冲区不匹配。

Using char ** will cause type mismatch with buffer.

EDIT2:

根据David Heffernan的要求,我附上了文档样本。重要的部分是英语。 Rest是PIngConnection应该返回的xlm的结构。

As requested by David Heffernan I attach sample of documentation. Important parts are trasnated to english. Rest is just structure of xlm that PIngConnection should return. Not much of help there - entire documentation is like this.

PS:我在这里问了类似的问题:在c ++中使用缓冲区时的废字符 - 基于WxWidgets的代码(虽然WxWidgets创建的问题,但它不会。也许有人会发现WxWidgets代码usefull youu )。

PS: I asked similar question here: Trash characters when using buffers in c++ - code based on WxWidgets (I though WxWidgets creates the problem, but it doesn't. Maybe someone will find WxWidgets code usefull thou).

编辑3:

我设法获得了关于dll的更多信息。

I managed to get some more information about dll.

Delphi版本是7。

Delphi version is 7.

确定调用类型是stdcall。 (DLL_PingConnection:function(var avXml:PChar):Boolean; stdcall;)

For sure calling type is stdcall. ( DLL_PingConnection: function(var avXml: PChar): Boolean; stdcall; )

这是如何在delphi中调用这个dll的函数:

This is how a function from this dll is called in 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;






推荐答案


DLL_PingConnection(var avXml:PChar):Boolean;

DLL_PingConnection(var avXml:PChar):Boolean;

这不是强>声明。显然,它是一个函数,因为它有一个 Boolean 返回类型。但是它也声明一个调用约定 - stdcall (C / C ++中的 __ stdcall )或 cdecl (C / C ++中的 __ cdecl )?如果不是,那么它使用Delphi的默认 register 约定(它是在Borland / CodeGear / Embarcadero C ++编译器的 __ fastcall 只有,但在任何其他C / C ++编译器没有等价)。您现有的typedef使用您的C ++编译器的默认调用约定,通常为 __ cdecl 。调用约定不匹配是使用DLL最常见的问题,因为它会导致调用堆栈管理不当,从而影响参数的传递,访问和清理。

This is not a full declaration. Obviously, it is a function since it has a Boolean return type. But does it also declare a calling convention as well - stdcall (__stdcall in C/C++) or cdecl (__cdecl in C/C++)? If not, then it is using Delphi's default register convention instead (which is __fastcall in Borland/CodeGear/Embarcadero C++ compilers only, but has no equivalent in any other C/C++ compiler). Your existing typedefs are using your C++ compiler's default calling convention, which is usually __cdecl. Calling convention mismatches are the most common problem with using DLLs, as it causes mismanagement of the call stack, which affects how parameters are passed, accessed, and cleaned up.

,什么版本的Delphi是DLL写的? PChar PAnsiChar (C ++中的 char * 2007,但在Delphi 2009和更高版本中 PWideChar (C ++中的 wchar_t * )。由于数据是XML,因此很可能正在使用 PAnsiChar / char *

Also, what version of Delphi was the DLL written in? PChar is PAnsiChar (char* in C++) in Delphi 2007, but is PWideChar (wchar_t* in C++) in Delphi 2009 and later. Chances are, since the data is XML, then PAnsiChar/char* is likely being used.

此外, PChar 参数在Delphi中作为 var 声明,它与C中的指针和C ++中的引用相同。

Also, the PChar parameter is being passed as a var in the Delphi declaration, which is the same as a pointer in C and a reference in C++.

您需要这些重要的信息才能在C / C ++中使用这个DLL函数码。除非文档明确地陈述这些细节,或者DLL有一个显示实际声明的C / C ++ .h / .hpp文件,那么你可以做的最好的是猜测,并且有几种变化可能给出了你已经显示的不完整的声明far:

You need these important pieces of information in order to use this DLL function in C/C++ code. Unless the documentation explictly states these details, or the DLL has a C/C++ .h/.hpp file showing the actual declaration, then the best you can do is guess, and there are several variations possible given the incomplete declaration you have shown so far:

char *& 可以替换为 char ** 如果需要):

(char*& can be replaced with char** if needed):

typedef bool (__cdecl *TYPE_DLL_PingConnection)(char*&);

typedef bool (__stdcall *TYPE_DLL_PingConnection)(char*&);

typedef bool (__fastcall *TYPE_DLL_PingConnection)(char*&);

typedef bool (__cdecl *TYPE_DLL_PingConnection)(wchar_t*&);

typedef bool (__stdcall *TYPE_DLL_PingConnection)(wchar_t*&);

typedef bool (__fastcall *TYPE_DLL_PingConnection)(wchar_t*&);

如果DLL函数使用 cdecl stdcall ,那么你可以,因为大多数C / C ++编译器支持这些调用约定。但是,如果DLL函数使用 register ,如果你不使用Borland / CodeGear / Embarcadero C ++编译器,那么你是SOL。您必须将DLL包装在另一个Delphi编写的DLL中,该DLL导出使用更便携式签名的包装函数。

If the DLL functions are using cdecl or stdcall, then you are OK, as most C/C++ compilers support those calling conventions. However, if the DLL functions are using register instead, and if you are not using a Borland/CodeGear/Embarcadero C++ compiler, then you are SOL. You would have to wrap the DLL inside another Delphi-written DLL that exports wrapper functions that use more portable signatures.

这篇关于在char *中获取垃圾数据,同时在函数中使用它作为缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆