Delphi-NULL终止字符
Delphi - NULL-Terminated Character
我有一个用于POS系统的极点显示产品,我想在屏幕上显示一些数据。我有一个C代码可以做到这一点,而且它运行良好C代码:
// demo.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <time.h>
#include <iostream>
using namespace std;
#include "windows.h"
int __cdecl main(int argc, char* argv[])
{
char in;
HMODULE hm;
long (*ou)();
long (*cu)();
long (*wp)(char*,long);
long (*ps)();
time_t tm;
char ss[64];
SetLastError( 0);
hm = LoadLibrary( "usbpd.dll");
printf( " hm = %p, %lu n",hm,GetLastError());
if ( hm==NULL ) return 1;
SetLastError( 0);
ou = (long(*)()) GetProcAddress( hm,"OpenUSBpd");
printf( " ou = %p, %lu n",ou,GetLastError());
SetLastError( 0);
cu = (long(*)()) GetProcAddress( hm,"CloseUSBpd");
printf( " cu = %p, %lu n",cu,GetLastError());
SetLastError( 0);
wp = (long(*)(char*,long)) GetProcAddress( hm,"WritePD");
printf( " wp = %p, %lu n",wp,GetLastError());
SetLastError( 0);
ps = (long(*)()) GetProcAddress( hm,"PdState");
printf( " ps = %p, %lu n",ps,GetLastError());
printf( " OpenUSB = %ld n", ou());
wp("Price: 5.00 ", 20);
wp("Total: 33.00 ", 20);
//for (long i=0;i<3;++i)
// {
// printf( " ps(1) = %ld n", ps());
// time( &tm);
// sprintf( ss,"x1bx40%s",ctime( &tm));
// wp( ss, strlen( ss));
// if ( argc>1 ) for (int j=30;j<255;++j) { ss[0] = j; ss[1] = 0; wp( ss,1);}
// printf( " ps(2) = %ld n", ps());
// }
printf( " CloseUSB = %ld n", cu());
cin.get();
FreeLibrary( hm);
return 0;
}
我有一个用Borland Delphi编写的代码来做与C代码相同的事情,但在显示我的数据后,它显示了一个垃圾字符。
Delphi代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TDLLFunc = function(): Integer;
ptr = ^TChar;
TChar = array[1..20] of PChar;
TDLLWriteFunc = function(ps_Text: ptr; pi_Length: Integer): Integer;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
Button3: TButton;
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
h: THandle;
OpenUSBpd : TDLLFunc;
CloseUSBpd: TDLLFunc;
WritePD : TDLLWriteFunc;
PdState : TDLLFunc;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button3Click(Sender: TObject);
var xx: TChar;
pxx: ptr;
i: Integer;
begin
h:= LoadLibrary('D:GlassTechTaboonDevicesPD23_26UUSBPD.DLL');
if(h <> 0)then
begin
@OpenUSBpd := GetProcAddress(h, 'OpenUSBpd');
@CloseUSBpd:= GetProcAddress(h, 'CloseUSBpd');
@WritePD := GetProcAddress(h, 'WritePD');
@PdState := GetProcAddress(h, 'PdState');
OpenUSBpd;
end;
xx[1] := 'A';
xx[2] := 'B';
xx[3] := 'C';
xx[4] := 'D';
xx[5] := 'E';
xx[6] := 'F';
xx[7] := 'G';
xx[8] := 'H';
xx[9] := 'I';
xx[10]:= 'J';
xx[11]:= 'K';
xx[12]:= 'L';
xx[13]:= 'M';
xx[14]:= 'N';
xx[15]:= 'O';
xx[16]:= 'P';
xx[17]:= 'Q';
xx[18]:= 'R';
xx[19]:= 'S';
xx[20]:= 'T';
pxx:= @xx;
WritePD(pxx, 0);
CloseUSBpd;
end;
end.
请帮忙,谢谢
首先,重新定义标准类型是非常糟糕的,这几乎就是你在这里所做的:
ptr = ^TChar;
TChar = array[1..20] of PChar;
实际上,TChar
与char
太相似了,后者的指针类型是PChar
。这就像坚持"是"这个词的"否"的意思,反之亦然!此外,你可能是指
TChar = array[1..20] of Char;
并且如果c: TChar
,则指向第一个字符的指针等于@c[1]
。此外,您可能需要在数组的末尾添加一个#0
字符。无论如何,干脆跳过这种可怕的方法!相反,使用普通的Delphi字符串!它们总是以零结尾,而且,由于字符串是指向内存中实际字符数组的指针,因此您可以简单地将字符串强制转换为PChar
,以获得指向以零结尾的字符数组的指示器。
但是,我认为库需要一个Ansi(或ASCII(字符串,因此我们将使用AnsiString
(AnsiChar
(而不是string
(char
(。
进行
TDLLWriteFunc = function(ps_Text: PAnsiChar; pi_Length: Integer): Integer; stdcall;
...
var XX: AnsiString;
...
XX := 'ABCDEFGHIJKLMNOPQRST';
WritePD(PAnsiChar(XX), 0);
并且null终止符字符将自动发送到WritePD
,因为每个Delphi字符串都以null字符结束。此外,PAnsiChar(XX)
是指向字符串中第一个字符的指针还要注意,我使用了stdcall调用约定!你可能需要这个,或者,也许,cdecl
另外,你确定pi_Length
参数不应该是字符串的长度吗?如果是,进行
WritePD(PAnsiChar(XX), length(XX));
[此外,如果是h = 0
,您确定要WritePD
和CloseUSBpf
吗?]
您的pxx
是指向array[1..20] of PChar
的指针,因此pxx
指向xx
中的第一个PChar
。现在,如果您开始将pxx
视为PChar
,在wp()
调用中,它将像字符串一样处理整个指针数组,即它将"打印"指针的字节,直到遇到第一个零字节。那当然是垃圾。
您的代码包含许多错误和不一致。
你应该做的第一件事是重新定义TChar:
type
TChar = array[0..19] of Char; // NOT of PChar!
完全去除pxx
和ptr
。它们是多余的。
现在,您可以用字符填充数组(可能是用PChar
的字符填充数组,而不是用Char
的字符填充字符串,如'A'
、'B'
等(,然后执行
wp(xx, 20);
这仍然是一个糟糕的代码,但它应该可以工作。就像其他人说的那样,最好使用AnsiString
并铸造:
myAnsiString := 'ABCDEFGHIJKLMNOPQRST';
wp(PAnsiChar(myAnsiString), Length(myAnsiString));
只需去掉xx
和TChar
类型即可。
在我写的一篇文章中,更多关于字符串和PChars的内容:PChars:没有附加字符串。我想你应该读一下。
您应该像这样使用stdcall,并使用PAnsiChar:
type
TDLLFunc = function : Integer; stdcall;
TDLLWritePAnsiCharLongIntFunc = function(ps_Text: PAnsiChar; pi_Length: Integer): Integer; stdcall;
此外,Andreas是对的,写字符串部分可以简单地:
procedure WriteLetters;
var
s:String;
begin
s := 'ABCDEFGHIJKLMNOPQRST';
WritePD( PAnsiChar(s), Length(s));
end;
- 缺少终止 ' 字符
- 警告:缺少终止"字符
- 如何告诉字符串流忽略null终止字符
- 当 NUL 字符被定义为字符串的一部分时,为什么 strlen() 不计算终止 NUL 字符的字节?
- 如何用字符终止整数输入循环?
- 如何使用 WIN RPC 发送终止的字符数组(用于将图像从客户端上传到服务器)
- 终止具有特定字符的循环
- 为什么具有单独字符的字符数组不像字符串文字那样以 null 终止符结尾?
- 如何调整标准::字符串的大小以删除所有空终止符字符?
- 如何将没有终止字符和大小的返回消息一起使用提升async_read?
- 当想要以类似的字符终止时,获得无限循环在C 中
- C++ 带有终止字符的开关大小写计算器
- 如何用零终止字符纪机char阵列
- 字符星形数组参数未正确终止
- C 字符串空终止字符 0 修改
- #define 个字符数组,C++中没有空终止
- C++字符数组null终止符位置
- 使用字符数组(非null终止)c/c++写入stdout
- 基于多个终止字符从UART收集数据
- '#'或'&'字符终止C++命令行参数