dll调用的怪现象,关于pchar和string(比较有难度) ( 积分: 200 )

  • 主题发起人 主题发起人 staven
  • 开始时间 开始时间
S

staven

Unregistered / Unconfirmed
GUEST, unregistred user!
最近写了一个dll,调用windowsApi中的dll,出现了几个怪现象。望大家帮忙解答一下。
windows api中的函数原形:
function SCardListReaders(
const hContext: SCARDCONTEXT
//SCARDCONTEXT实际上是ulong类型
mszGroups: PChar

mszReaders: LPSTR
//LPSTR实际上是pchar类型
pcchReaders: LPDWORD): Longint
stdcall
//LPDWORD也就是pDword类型
我编写的dll中声明了一个函数,供外部调用,该函数调用了上面的windows api函数。该函数的源码如下:
function SCListReaders(Readers: pchar): longint;stdcall;
var
m_ReaderBuff: pchar
// } array[0..255] of char
[red]//注意,这里我声明了2种类型[/red]
dwRetCode: longint;
m_ReaderBuffLen: DWORD;
nPtr: integer;
myReaders: string;
begin
result := E_success;
//读卡器初始化
if not readersInited then
begin
result := SCinitReaders;
if result <> E_success then exit;
end;

//读读卡器列表
m_ReaderBuff := AllocMem(256);
try
dwRetCode := SCardListReaders(m_Context,
nil,
m_ReaderBuff, //}@m_ReaderBuff[0], [red] //这里是注意点,有2种方式[/red]
@m_ReaderBuffLen);
if (dwRetCode <> SCARD_S_SUCCESS) then begin
result := E_ReadersListFailed;
exit;
end;
setlength(myReaders, m_ReaderBuffLen - 1);
move(m_ReaderBuff^, myReaders[1], m_ReaderBuffLen - 1)

finally
FreeMem(m_ReaderBuff, 256)

end;
StrPCopy(readers, myReaders);
end;
问题出在对m_ReaderBuff的使用上,出现了下面几个问题:
1、把m_ReaderBuff定义成array[0..255] of char的时候,经常会出现调用不成功的情况(传的是@m_ReaderBuff[0],或者m_ReaderBuff),后来就一次也没成功了。按理来说没有什么问题啊。但是把m_ReaderBuff放到函数体外,又可以了。不知道怎么回事?
dwRetCode := SCardListReaders(m_Context, nil, @m_ReaderBuff[0], m_ReaderBuffLen);
2、把m_ReaderBuff定义成pchar的时候,一般会调用成功,就如现在的代码。当然内存是申请过了。但是发现传出来的值都是空值,很奇怪。
dwRetCode := SCardListReaders(m_Context, nil, m_ReaderBuff, m_ReaderBuffLen);

3、最后来,我把m_ReaderBuff定义成pointer,发现可以调用成功,值也正确读出来了。
dwRetCode := SCardListReaders(m_Context, nil, m_ReaderBuff, m_ReaderBuffLen);

4、我也试过把m_ReaderBuff定义成string类型,可以调用成功,但是传出来的值也都是空值。奇怪!(不要怀疑没有申请内存)。
dwRetCode := SCardListReaders(m_Context, nil, @m_ReaderBuff[1], m_ReaderBuffLen);
5、最后,随着程序的进行,我把代码删掉了几行,就又发现取出来的值不对了,但是可以成功调用。

上面的现象真是奇怪,不知道大家是否碰到过。
从现象来看,感觉是内存分配,读取地址出现了什么问题,好像string和pchar互相转化之间出现了混乱。后来我试过,变了一个可执行程序,引用该代码单元,不管采用什么类型声明,这些代码都没有问题。难道dll编写这样的代码,有什么需要注意的地方么?
希望大家不吝赐教!(分数多的是)
 
最近写了一个dll,调用windowsApi中的dll,出现了几个怪现象。望大家帮忙解答一下。
windows api中的函数原形:
function SCardListReaders(
const hContext: SCARDCONTEXT
//SCARDCONTEXT实际上是ulong类型
mszGroups: PChar

mszReaders: LPSTR
//LPSTR实际上是pchar类型
pcchReaders: LPDWORD): Longint
stdcall
//LPDWORD也就是pDword类型
我编写的dll中声明了一个函数,供外部调用,该函数调用了上面的windows api函数。该函数的源码如下:
function SCListReaders(Readers: pchar): longint;stdcall;
var
m_ReaderBuff: pchar
// } array[0..255] of char
[red]//注意,这里我声明了2种类型[/red]
dwRetCode: longint;
m_ReaderBuffLen: DWORD;
nPtr: integer;
myReaders: string;
begin
result := E_success;
//读卡器初始化
if not readersInited then
begin
result := SCinitReaders;
if result <> E_success then exit;
end;

//读读卡器列表
m_ReaderBuff := AllocMem(256);
try
dwRetCode := SCardListReaders(m_Context,
nil,
m_ReaderBuff, //}@m_ReaderBuff[0], [red] //这里是注意点,有2种方式[/red]
@m_ReaderBuffLen);
if (dwRetCode <> SCARD_S_SUCCESS) then begin
result := E_ReadersListFailed;
exit;
end;
setlength(myReaders, m_ReaderBuffLen - 1);
move(m_ReaderBuff^, myReaders[1], m_ReaderBuffLen - 1)

finally
FreeMem(m_ReaderBuff, 256)

end;
StrPCopy(readers, myReaders);
end;
问题出在对m_ReaderBuff的使用上,出现了下面几个问题:
1、把m_ReaderBuff定义成array[0..255] of char的时候,经常会出现调用不成功的情况(传的是@m_ReaderBuff[0],或者m_ReaderBuff),后来就一次也没成功了。按理来说没有什么问题啊。但是把m_ReaderBuff放到函数体外,又可以了。不知道怎么回事?
dwRetCode := SCardListReaders(m_Context, nil, @m_ReaderBuff[0], m_ReaderBuffLen);
2、把m_ReaderBuff定义成pchar的时候,一般会调用成功,就如现在的代码。当然内存是申请过了。但是发现传出来的值都是空值,很奇怪。
dwRetCode := SCardListReaders(m_Context, nil, m_ReaderBuff, m_ReaderBuffLen);

3、最后来,我把m_ReaderBuff定义成pointer,发现可以调用成功,值也正确读出来了。
dwRetCode := SCardListReaders(m_Context, nil, m_ReaderBuff, m_ReaderBuffLen);

4、我也试过把m_ReaderBuff定义成string类型,可以调用成功,但是传出来的值也都是空值。奇怪!(不要怀疑没有申请内存)。
dwRetCode := SCardListReaders(m_Context, nil, @m_ReaderBuff[1], m_ReaderBuffLen);
5、最后,随着程序的进行,我把代码删掉了几行,就又发现取出来的值不对了,但是可以成功调用。

上面的现象真是奇怪,不知道大家是否碰到过。
从现象来看,感觉是内存分配,读取地址出现了什么问题,好像string和pchar互相转化之间出现了混乱。后来我试过,变了一个可执行程序,引用该代码单元,不管采用什么类型声明,这些代码都没有问题。难道dll编写这样的代码,有什么需要注意的地方么?
希望大家不吝赐教!(分数多的是)
 
[red]该问题苦恼了我好多天,一直在查代码的问题,可就是找不出问题所在。有时候,把变量声明挪了个位置,就好了,比如移到函数体外。[/red]
 
该问题引起也可能和调用windows api函数有关。原来编写dll代码从来没有碰到这些问题!
 
最后来,我把m_ReaderBuff定义成pointer,发现可以调用成功,值也正确读出来了。
dwRetCode := SCardListReaders(m_Context, nil, m_ReaderBuff, m_ReaderBuffLen);
即然这要好使,就这么用下去不中吗?
 
delphi调用C写的dll经常会出现你说的“把变量声明挪了个位置,就好了,比如移到函数体外。”,也即是把变量定义为全局变量可以解决该问题。之前也曾跟过汇编代码,但也找不出问题所在。这可能是Delphi本身的Bug。
 
to app2001,要找出问题所在啊,讲出道理啊。不然都不知道是怎么回事?你说呢。
希望大家指出问题所在。
 
To staven:
老兄,你写了大半页纸也没说这个 “SCardListReaders”在你的程序中是怎么声明的,不过这也不是重点。
m_ReaderBuff: array[0..255] of Char;
可以这样声明,不过这鬼东西不能像你那么用,array 实际是个指针,你骗过编译器就行了。
dwRetCode := SCardListReaders(m_Context, nil, Pointer(m_ReaderBuff), m_ReaderBuffLen);
@m_ReaderBuff[0] 按理说应该等于 Pointer(m_ReaderBuff),不过谁知道在 256 长度的躯干前面存了些什么呢。
 
to vvyang:
SCardListReaders的声明不是写了么?
代码:
function SCListReaders(Readers: pchar): longint;stdcall;
还有顺便纠正你一个问题:
既然声明成了m_ReaderBuff: array[0..255] of Char;
那么在m_ReaderBuff前加上Pointer(m_ReaderBuff), 是没有必要的,因为ReaderBuff本省就是指针了。
[red]不过最重要的是你没有说到重点上,但还是谢谢你的参与[/red]
 
[red]晕,那个 API 原形你是怎么声名的,怎么翻译的![/red]
帮你回答问题还弄出毛病来了,啊?
 
那我再贴一遍:
c语言中原形:
代码:
extern WINSCARDAPI LONG WINAPI
SCardListReadersA(
    IN      SCARDCONTEXT hContext,
    IN      LPCSTR mszGroups,
    OUT     LPSTR mszReaders,
    IN OUT  LPDWORD pcchReaders);
extern WINSCARDAPI LONG WINAPI
SCardListReadersW(
    IN      SCARDCONTEXT hContext,
    IN      LPCWSTR mszGroups,
    OUT     LPWSTR mszReaders,
    IN OUT  LPDWORD pcchReaders);
#ifdef UNICODE
#define SCardListReaders  SCardListReadersW
#else
#define SCardListReaders  SCardListReadersA
#endif // !UNICODE
其中 SCARDCONTEXT
typedef ULONG_PTR SCARDCONTEXT;

我在delphi中的翻译:
代码:
function SCardListReaders(
  const hContext: SCARDCONTEXT;
  mszGroups: PChar;
  mszReaders: LPSTR;
  pcchReaders: LPDWORD): Longint
stdcall;
其中SCARDCONTEXT的翻译:
PSCARDCONTEXT = ^TSCARDCONTEXT;
TSCARDCONTEXT = ULONG;
SCARDCONTEXT = TSCARDCONTEXT;
 
你这个是调用某家读写设备的接口吧,我最近也在编一个调用明华设备的接口的东西,我更倾向于用Pointer,在书上说其是无类型指针,这样适用性更广些吧.具体的道道我也说不上来
 
你试试把 m_ReaderBuff 定义成 string,array[0..255] of char 是否用 #0 结尾了。
var
m_ReaderBuff: string;
begin
SetLength(m_ReaderBuff, 256);
SCardListReaders(m_Context, nil, PChar(m_ReaderBuff), m_ReaderBuffLen);
...
end;
看你的程序没什么问题,没有 dll 调试。
 
没有正确的解释么?
 
[red]请大家继续关注该问题,给出正确解答![/red]
 
应用程序调用 function SCListReaders(Readers: pchar): longint;stdcall;
函数时,Readers参数分配内存了吗?
 
分配过内存了,没有分配内存,程序不就报错了么。我可没说过报错之类的。
 
我原来使用过混合语言编程,用delphi编写dll,然后PB调用,也碰到类似问题;
总结经验:在dll传递参数最好使用pointer类型,比如:
aa:array [0..255] of char;
在传递时使用:call(@aa)
接受函数定义:
function call(bb:pointer):integer;
var
xx:^string;
begin
xx:=bb;
xx^:='返回值';
result:=0;
end;
这样调用一般是不会出错的,但如果是混合语言编程使用二维数组,一定要注意数据存储方式
 
看看这个,对你有没有帮助:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3181462
 
最关键的是能够解决这个现象,
“把变量声明挪了个位置,就好了,比如移到函数体外。”,也即是把变量定义为全局变量可以解决该问题。
今天我又出现了该现象,但是有几个函数,把变量都移到外面(定义为全局变量),爱是出现了问题。到现在我也不知道变量是定量在函数里,还是定义在外面好了。
痛苦中。。。。。
 
后退
顶部