关于Delphi中调用C语言动态链接库的问题

dandycheung 2000-08-23 10:39:00
用 C 编写了一个动态链接库,其中输出了一个要用 char * 作为参数的函数,在 delphi 中调用时采用如下形式:

fxn(PChar('Some chars'));

当 PChar 中强制转换的字符串仅包含一个字符时(如:'a')调用失败,而只要多于一个字符则正常,敢问是什么原因?

题外话:我觉得 delphi 本是个不错的东西,但 Borland 把它做得太糙了,在细微的地方经常出毛病,这一点不如 VC++。
...全文
714 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
JGTM2000 2000-09-05
  • 打赏
  • 举报
回复
而且这句话:“相反的,我不动我的DLL,把delphi中对我DLL的输出函数原型中的参数类型由PChar改为Integer,调用的时候用Integer(@StrBuffer)的形式传入到DLL中,执行结果完全正常”。稍微明白一点Delphi的同志都应该能看出来前后是没有任何差别的,计算机执行程序是不知道什么PChar还是Integer的,总之这是一个32bit DWORD,类型无非编译器的概念。所以为什么结果忽对忽错,我虽然还是不能确认,但总不宜就说是开发环境的错误吧。
JGTM2000 2000-09-04
  • 打赏
  • 举报
回复
请注意前例中'Test'在需要接受PChar类型参数处的直接使用。
JGTM2000 2000-09-04
  • 打赏
  • 举报
回复
我C是不好,不过汇编不错。我不明白的是你说的这句话:"delphi中传入的参数原封不动的传入到MessageBox函数里,结果照样出错。您知道,MessageBox函数是必然会将该值作为字符缓冲区的首址"。怎么我编同样的程序就没有任何错误,我想只可能是您有粗心的错误。另外,fxn(PChar(String('a constant string')))和直接写fxn('a constant string')是没有区别的,如果有一个常量const s = 'a constant string',或者const s:PChar = 'a constant string',或者const s: array [0..255] of char = 'a constant string',则fxn(s)都是正确的。只有当s的类型为显式的string({$H+}时等同于AnsiString),需要用PChar(s)的形式强制转换(注:改转换的目的仅是为了骗过编译器,因为s作为指针时其目标地址的布局和PChar是完全兼容的)。

为了进一步说明问题不在Delphi,我们找一个C写成的Win32 API来测试一下:

implementation

const
sConst = 'a';
pcConst : PChar = 'a';
caConst0: array [0..0] of char = 'a'; // !!
caConst1: array [0..1] of char = 'a';
strConst: string = 'a';
cConst: char = 'a';
nullChar: char = #0;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
// asm int 3; end; // comment/uncomment this line to trigger breakpoint here
Windows.MessageBox(Handle,sConst,'Test',MB_OK);
Windows.MessageBox(Handle,pcConst,'Test',MB_OK);
Windows.MessageBox(Handle,caConst0,'Test',MB_OK); // cause incorrect tail
Windows.MessageBox(Handle,caConst1,'Test',MB_OK);
Windows.MessageBox(Handle,PChar(strConst),'Test',MB_OK);
Windows.MessageBox(Handle,@cConst,'Test',MB_OK); // cause incorrect tail
Windows.MessageBox(Handle,@nullChar,'Test',MB_OK);
Windows.MessageBox(Handle,nil,'Test',MB_OK);
end;

什么情况编译和结果都正确,为什么那两句结果不正确,希望大家好好体会一下(最好在CPU窗口中研究一下内存布局,相信体会更深)。BTW, 评论一件产品(或一个人)的时候,最好先确保自己完全理解他,否则坏了人家的名声多冤呀。哈哈

dandycheung 2000-08-28
  • 打赏
  • 举报
回复
各位好,请原谅我的粗心,kxy 是对的,应该以fxn(PChar(String('Some chars')));这样的形式来调用,我原来试的时候把代码改了一下没有编译就执行了(并且还不在集成环境中)。昨天又试才发现。JGTM2000 朋友非常热心,但可能由于对 C 语言了解不够,所以未能找到问题要害。
顺便再问一下,为什么在 Delphi 的集成环境中不能调试对 Oracle 数据有操作的程序?无论是使用 ADO 还是其他控件我都能遇见这个问题。
JGTM2000 2000-08-26
  • 打赏
  • 举报
回复
From: <dandycheung>
To: <JGTM2000>

> 您好,
> 首先为您能关注我的问题致谢。
> 您的考虑有一定的正确之处,但好像和我的问题不能吻合。
> 我为了验证这一问题,曾经专门另外做了一个DLL,输出的函数里面只有一行代码,就是将delphi中传入的参数原封不动的传入到MessageBox函数里,结果照样出错。您知道,MessageBox函数是必然会将该值作为字符缓冲区的首址。
> 相反的,我不动我的DLL,把delphi中对我DLL的输出函数原型中的参数类型由PChar改为Integer,调用的时候用Integer(@StrBuffer)的形式传入到DLL中,执行结果完全正常。
> 由此推断,错误必然发生在delphi上,而不是我的DLL。

能否将您所说的相关代码贴来?根据我的判断,PChar和Integer不是重要的,因为那是对编译器而言的概念,只要在内存中的地址和布局一致,结果一定是一样的,无论用谁来写。我想搞清楚一个问题,就是您如何能够判断传入的指针的目标内存区到底是一个字符还是一个字串?从Delphi的角度讲,无论多长的字串内存布局都是一样的,即字串本身内容+ASCIIZ(对于array [0..x] of char, PChar(AnsiString), string const)。


JGTM2000 2000-08-26
  • 打赏
  • 举报
回复
我希望能通过类比相似的例子解释这个问题的出处,您想,在Delphi中调用Win32 API不也是调用C的DLL函数吗?Win32 API中有很多的函数同样接收LPCZSTR即char*类型的参数,无论你用Delphi传入多长的字串它也不会出现错误,为什么?因为函数把char*总视为指向ASCIIZ字符串的指针,这种串占用内存空间的大小为实际字串长度+1(结尾的NULL),因此如果你传入的缓冲区大小为1,它只能代表长度为0的字串,而且这仅有的一个字节也必须为NULL。然而,如果函数把char*理解为指向一个字符的指针,则当同样大小为1的内存区域就被认为是字符,也就可以不是0。这明显的带来了歧义:长度为1的目标内存区域到底是什么内容?!

因此,这个问题的来源不一定是Delphi,而是C函数的内部实现没有处理这种明显的二异性。可以肯定的说,你用C程序以同样的内存布局去调用它,同样会出问题。所以解决方法很简单,明确定义char*的实际含义,目标内存区域是字符还是字串,如果是字串,一个字符的字串,同样按两个字节的内存占用处理,就不会出现任何问题。这也是为什么API定义中引入LPCZSTR宏的原因之一。
dandycheung 2000-08-25
  • 打赏
  • 举报
回复
再没有人回答了吗?
ckbmail 2000-08-25
  • 打赏
  • 举报
回复
我觉得delphi处理指针的能力不是太强。不知道各位意下如何?
please mailto :ckbmail@elong.com和我讨论
Sayhigh 2000-08-25
  • 打赏
  • 举报
回复
var
Buffer: PChar;
begin
GetMem(Buffer, 1024);//你的字串长度
StrCopy(Buffer, 'some chars');
fxn(Buffer);
Freemem(Buffer);
end;
应该可以的,如果不行传指针过去试一下.
dandycheung 2000-08-23
  • 打赏
  • 举报
回复
首先感谢yinfudan的精彩讲解。我是一个VC++的程序员,但也经常用到delphi。
问题是我在delphi 中调用时,该参数既可能是一个字符的字符串,也可能是多个字符的字符串。所以当前我的代码是这个样子的:

var
s: string;
...
// assigns value to s here, 'a' or 'abc'
...
// then:
fxn(PChar(s));

如何能最简单的解决这个问题?
mytulip 2000-08-23
  • 打赏
  • 举报
回复
试一下,function StrPCopy(Dest: PChar; const Source: string): PChar;吧,将string转成PChar
yinfudan 2000-08-23
  • 打赏
  • 举报
回复
同意dandycheung的题外话

问题解决方案:
PChar(...)可以把String型转成PChar型,具体实现方案是
建立一个Buffer,和这个String一样长,然后返回这个Buffer的首地址,首地址为32比特
例如PChar('abcde')的值可能等于$00450F03
PChar(...)可以把Integer或Char型转成PChar型,具体实现方案是
直接把这个整数或字符转成32比特的指针型
例如PChar(65535)=$0000FFFF,PChar('2')=$00000032

所以,传入参数PChar('a')当然不行了。应该改为
var
c:char;
begin
c:='a';
CFunc(@c);
end;
一定可以
dandycheung 2000-08-23
  • 打赏
  • 举报
回复
to guanxuegong:
肯定不是这种问题,LPTSTR 在非 Unicode 的版本中就等于 char *,那只不过是一个宏而已。
guanxuegong 2000-08-23
  • 打赏
  • 举报
回复
试试把c参数设为LPTSTR。
dandycheung 2000-08-23
  • 打赏
  • 举报
回复
to kxy: 我的第二次将问题提出,已经证明我曾经试过fxn(PChar(String('Some chars')));这样的形式或其下面的形式。一样行不通。如果你有兴趣的话,可以自己试一下。顺便说一下,我用的是Delphi 5 + UP1。也多谢kxy。
dandycheung 2000-08-23
  • 打赏
  • 举报
回复
错误是读写非法内存。各位,我已经相信yinfudan的讲解了,也请大家看清楚他的讲解,如果对于一个字符PChar就直接把它的十六进制值转换为指针类型的话,出现读写非法内存几乎是肯定的。问题是如何让delphi把一个字符时的串能够和多个字符时的串同等对待起来。多谢各位捧场。
kxy 2000-08-23
  • 打赏
  • 举报
回复
pascal中'a',可以是char类型,也可能是string
你可以这样
fxn(PChar(String('Some chars')));
如果你先申明一个string的变量,
s:string;
s:='Some chars';
fxn(PChar(s));也可以。

我不同意题外话:)
用C,C++,你更要注意不要让编译器产生歧义
kxy 2000-08-23
  • 打赏
  • 举报
回复
调用失败?,错误信息是什么?
dandycheung 2000-08-23
  • 打赏
  • 举报
回复
to goodman1999:
当然加了,要不然怎么能其他的长度就正常。
~~~
goodman1999 2000-08-23
  • 打赏
  • 举报
回复
在Delphi的函数声明中,最后加stdcall;了没有。
NiceBASIC测试版3是新型编程工具跟 VC,VB,DELPHI类似。 NiceBASIC测试版3 上传日期:2008年12月13日11:02:21 NiceBASIC文编程语言,是采用类似BASIC语法,并兼有C++的一些高级特性(比如:指针操作运算、自动化类、重载函数、重载操作符等等)集于一身的全文关键字的编程语言,简称NB。NB内置有标准BASIC函数库,和图像库(用于编写游戏),还可以使用标准C语言函数库里的函数(调用静态库形式链接),也就是说NB可以在编译时链接所有用标准C语言编写的静态库(LIB)做为函数功能扩展,并且还可以调用WIN32API的大部分函数,已经在内部定义声明,直接引用即可,就像C++的WINDOWS开发包。并且NB的编译器是永久免费的,除了可以编译自身的源码外,还可以编译RC资源脚本,合成到可执行文件,NB的编译器提供了构建完整标准应用程序的所有功能。 其独特个性化的全文式编程模式,更易于国人理解和方便学习编程,不用懂英文也可以编写自己的程序软件。变量和函数等标识符名称,也可以用文表示,方便于源码的交流和省略注释说明。 NB可以编译四种类型的可执行文件: 控制台程序。类似于DOS界面的命令行提示符,但只能运行在WIN32平台。 WINDOWS图形界面程序。调用系统的WIN32API来构建GUI窗体组件。 WIN32 DLL 动态链接库。导出函数可以为多种调用约定,比如:Stdcall(标准WINAPI)、 Cdecl(兼容C语言)、Pascal 。可供给其它语言使用。 静态链接库。供给标准的C语言调用链接。就是说NB的静态库是兼容C语言的LIB,互相通用。
目录 第1章 matlab概述. 1.1 matlab的发展历程 1.2 matlab产品组成及语言特点 1.2.1 matlab的主要产品构成 1.2.2 matlab语言的特点 1.3 matlab 7.0的新功能和新产品 1.3.1 matlab 7.0的新功能 1.3.2 matlab升级及新增的模块 1.4 小结 第2章 matlab程序设计及代码优化 2.1 matlab的表达式和变量 2.1.1 表达式 2.1.2 变量 2.2 细胞数组与结构数组 2.2.1 细胞数组 2.2.2 结构数组 2.3 类与对象 2.4 流程控制 2.4.1 for循环结构 2.4.2 while循环结构 .2.4.3 if-else-end分支结构 2.4.4 switch-case结构 2.4.5 try-catch结构 2.5 m文件编程 2.6 m文件编程规范 2.7 m文件评述器 2.8 提高m文件执行效率的技巧 2.8.1 矢量化操作 2.8.2 给数组预定义维 2.8.3 下标或者索引操作 2.8.4 尽量多使用函数文件而少使用非脚本文件 2.8.5 将循环体的内容转换为c-mex 2.8.6 内存优化 2.9 小结 第3章 matlab混合编程简介 3.1 进行混合编程的出发点 3.2 matlab应用程序接口简介 3.3 几种常见的混合编程方法简介 3.3.1 使用matlab自带的matlab compiler 3.3.2 利用matlab引擎 3.3.3 利用activex控件 3.3.4 利用mat文件 3.3.5 c-mex 3.3.6 利用mideva/matcom 3.3.7 利用matrix[lib]实现混合编程 3.3.8 利用matlab add-in 3.3.9 matlab com builder 3.3.10 matlab和excel混合编程 3.4 小结 第4章 c-mex编程 4.1 c-mex简介 4.2 mex文件系统的配置 4.3 mex文件的结构和运行 4.3.1 mex文件结构 4.3.2 mex函数的执行流程 4.3.3 mex文件的结构和使用 4.3.4 mex文件与独立应用程序的区别 4.4 c语言mex函数 4.5 c-mex混合编程 4.6 visual c++mex文件的建立和调试 4.6.1 visual c++mex程序的建立和环境设置 4.6.2 mex程序的调试 4.6.3 mex独立应用程序的发布 4.7 mex编程实例 4.8 小结 第5章 通过matlab引擎实现混合编程 5.1 matlab引擎简介 5.2 matlab引擎库函数 5.3 visual c++调用matlab引擎时的环境设置 5.4 matlab引擎类的封装 5.4.1 cmatlabeng类的定义和实现代码 5.4.2 cmatlabeng说明 5.4.3 cmatlabeng说明和使用方法 5.5 应用实例 5.6 小结 第6章 mat文件实现数据共享 6.1 mat文件简介 6.2 操作mat文件 6.2.1 mat文件格式 6.2.2 操作mat文件的matlab api 6.3 visual c++调用mat时的环境设置 6.4 实例 6.5 小结 第7章 利用mideva实现混合编程 7.1 mideva简介 7.2 mideva的安装 7.3 mideva环境下m文件到dll/exe文件的转换 7.4 visual c++环境下使用mideva混合编程 7.4.1 混合编程环境的设置 7.4.2 通过外壳函数调用 7.5 matrix[lib] 7.6 混合编程实例 7.7 小结 第8章 利用matrix[lib]实现混合编程 8.1 matrix[lib]简介 8.2 matrix[lib]与visual c++混合编程 8.2.1 matrix[lib]的安装 8.2.2 visual c++环境配置 8.2.3 初始化库 8.3 matrix[lib]函数使用参考 8.3.1 矩阵操作 8.3.2 库常量 8.3.3 访问库函数 8.3.4 矩阵i/o 8.3.5 图形函数 8.4 混合编程实例 8.5 matlab数学库 8.5.1 简介 8.5.2 visual c++工程调用matlab数学函数库的环境设置 8.6 小结.. 第9章 通过matlab add-in实现混合编程 9.1 matlab add-in简介 9.2 matlab add-in安装和在visual c++的环境设置 9.3 通过matlab add-in生成独立应用程序 9.4 matlab add-in实例 9.5 小结 第10章 matlab和delphi混合编程 10.

5,386

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧