CSDN博客

img jimek654

Delphi双指针使用

发表于2008/10/2 0:17:00  590人阅读

分类: Delphi余热

        Delphi的指针功能实际上是很少有用到的,但是它对外封装了几个指针的类型还是可以用用,如
    PChar (=^Char),
    PPChar (=^PChar, 传说中的双指针,在Delphi5与它的以下版本可能没有这个类型,但可以自己建立,如:
    type 
    PPChar = ^PChar
)
等等。
        我也是在偶然的机会下碰到这个技术话题的。在写一个DELPHI的系统中,调用一个厂家提供的DLL(VC)时,代码类似如下:
DLL模块 
  1. int _stdcall getInfo(char* info)
实现部分         
  1. int _stdcall getTest(char* info)
  2. {
  3.    char* str = "Test";
  4.    // TODO: str业务处理
  5.    strcpy(info, str);
  6.    return 0;
  7. }
Delphi客户端程序
  1. function getInfo(info: PChar): string; stdcall; External '{ Dll 函数}';
  2. // 测试过程
  3. procedure Test;
  4. var
  5.   pStr: array[0..100of Char;
  6. begin
  7.   getTest(pStr);
  8.   ShowMessage(pStr);
  9. end;
        如上,经测试成功。
        大家可能就发现问题了,Delphi这边需要申请一个内存空间,如array[0..100], 或使用strAlloc,才能调用VC提供的DLL函数。否则就会报些大家最不愿意看见的内存地址错误,如:"Access violation at address 00423A69 in module 'Demo.exe'. Read of address 74736560."。
        但是大家有没有从业务功能上考虑,我怎么知道需要申请多少内存空间呢,换句话说,DELPHI调用这边就必须设个很大的空间,这样的程序设计是不是不太合理?!所以想到这,就考虑是不是应该让Dll的函数自己来申请内存空间。修改DLL:   
  1. int _stdcall getTest(char* info)
  2. {
  3.   char* str = "Test";
  4.   // TODO: str业务处理
  5.   info = (char*) malloc(sizeof(char) * strlen(str) + 1);  // 分配内存空间
  6.   strcpy(info, str);
  7.   info[strlen(str)] = 0x00; // 标记结束符
  8.   return 0;
  9. }
        调用代码修改pStr: PChar,如;
  1. procedure Test;
  2. var
  3.   pStr: PChar;
  4. begin
  5.   getTest(pStr);
  6.   ShowMessage(pStr);
  7. end;
        经调用,数据是出来了,可惜是乱码,在记事本中显示为“?”,至今也搞不清为撒。那就只能考虑别的方式吧。
        Delphi的PChar不是表示指针吗?那把getTest(pStr)改成getTest(@pStr)传地址进去如何,结果又报内存错误,如"Access violation at address 00403A8B in module 'Demo.exe'. Read of address 00200000."(这内存地址又换了一组)。
        delphi竟然传指针过来,那DLL是不是得改一下,用双指针试试,如:
  1. int _stdcall getTest(char* *info)
  2. {
  3.   char* str = "Test";
  4.    // TODO: str业务处理
  5.    *info = (char*) malloc(sizeof(char) * strlen(str) + 1); // 分配内存空间
  6.   char* c = *info;
  7.   strcpy(c, str);
  8.   c[strlen(str)] = 0x00;
  9.   return 0;
  10. }
        delphi这边为:
  1. var
  2.   pStr: PChar;
  3. begin
  4.   getTest(@pStr);
  5.   ShowMessage(pStr);
  6. end;
        咦,还真可以了。Ok,跟厂家协定好,就这么做。双方很高兴的完成了接口的联调工作。
        可是,我在仔细阅读接口文档一边又一边时,给自己提出了一个问题,将如,明年厂家更换了,更换的这个厂家如果用Delphi写这个DLL,我又不想修改现在的调用程序,那么这个DLL怎么实现?左思又询中,想到了用PPChar来代替char**, 就写出了如下的函数:
  1. function getTest(info: PPChar): Integer;
  2. var
  3.   str: PChar;
  4. begin
  5.   Result := -1;  // 返回错误代码
  6.   try
  7.     str := 'Test';
  8.     // TODO: str业务处理
  9.     Info^ := strAlloc(Length(str) * SizeOf(Char) + 1); // 分配内存空间
  10.     StrCopy(Info^, PChar(str));
  11.     Result := 0;
  12.   except
  13.   end;
  14. end;
        经多次测试,发现这样写非常的成功。我终于安心的关闭了接口文档,宣布接口联调结束。
        可能大家还有疑问,如:为什么分配内存空间时VC和Delphi都要加1了?那是因为需要存储字符串结束符"/0"(其实在上面也找得到答案,见"c[strlen(str)] = 0x00;"这句代码)。
        发现我们做开发的真正做进去了,冠冕堂皇的叫做"举一反三",从工作效率上讲,这叫"没事找事"。得出个名言:"世上本无事,找的人多了,也就有了事"。

0 0

相关博文

我的热门文章

img
取 消
img