Delphi - персонаж с нулевым символом - PullRequest
0 голосов
/ 24 августа 2011

У меня есть продукт с дисплеем полюсов для систем POS, я хочу вывести некоторые данные на экран.У меня есть C-код, чтобы сделать это, и он отлично работает. C-Code:

// 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,"\x1b\x40%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-Code, но после показа моих данных онпоказать символы мусора.

Delphi Code:

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:\GlassTech\Taboon\Devices\PD23_26U\USBPD.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.

Пожалуйста, помогите, спасибо

Ответы [ 3 ]

2 голосов
/ 24 августа 2011

Прежде всего, очень плохо переопределять стандартные типы, и это почти то, что вы делаете здесь:

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).

Do

TDLLWriteFunc = function(ps_Text: PAnsiChar; pi_Length: Integer): Integer; stdcall;

...

var XX: AnsiString;

...

XX := 'ABCDEFGHIJKLMNOPQRST';    
WritePD(PAnsiChar(XX), 0);

и символ-терминатор nulll будет автоматически отправлен на WritePD, потому что каждая строка Delphi заканчивается нулевым символом.Кроме того, PAnsiChar(XX) - указатель на первый символ в строке. Также обратите внимание, что я использовал соглашение о вызовах stdcall!Возможно, вам это нужно, или, возможно, cdecl.

Кроме того, вы уверены, что параметр pi_Length не должен быть длиной строки?Если это так, сделайте

WritePD(PAnsiChar(XX), length(XX));

[Также вы уверены, что хотите WritePD и CloseUSBpf, если h = 0?]

1 голос
/ 25 августа 2011

Вы должны использовать stdcall, как это, и использовать PAnsiChar:

 type
      TDLLFunc = function : Integer; stdcall;
      TDLLWritePAnsiCharLongIntFunc = function(ps_Text: PAnsiChar; pi_Length: Integer): Integer; stdcall;

Кроме того, Андреас прав, запись строковой части может быть простой:

procedure WriteLetters;
var 
 s:String;
begin
     s := 'ABCDEFGHIJKLMNOPQRST';
     WritePD( PAnsiChar(s), Length(s));
end;
1 голос
/ 25 августа 2011

Ваш pxx является указателем на array[1..20] of PChar, поэтому pxx указывает на первое PChar в xx.Теперь, если вы начнете воспринимать pxx как PChar, в вызове wp() он будет обрабатывать весь массив указателей как строку, то есть он будет «печатать» байт указателей,пока он не встретит первый нулевой байт.Конечно, это мусор.

Ваш код содержит много ошибок и несоответствий.

Первое, что вы должны сделать, это переопределить TChar:

type
  TChar = array[0..19] of Char; // NOT of PChar!

Избавиться от pxx и ptr всего.Они излишни.

Теперь вы можете заполнить ваш массив символами (вы, вероятно, заполняли свой массив буквально PChar до букв строк , таких как 'A', 'B' и т. Д.и, конечно, не с Char s), а затем выполните

wp(xx, 20);

Это все еще ужасный код, но он должен работать.Как говорили другие, лучше используйте AnsiString и приведите:

myAnsiString := 'ABCDEFGHIJKLMNOPQRST';
wp(PAnsiChar(myAnsiString), Length(myAnsiString));

Просто избавьтесь от xx и типа TChar тоже.


Подробнее о строках иPChars в статье, которую я написал: PChars: без привязок .Я думаю, что вы должны прочитать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...