views:

199

answers:

4

Hi.

I want to call a dll function in Delphi 2010. This function take a string and write it to a printer with USB interface. I do not know in which language the dll is developed with. According to the documentation the syntax of the function is:

int WriteUSB(PBYTE pBuffer,DWORD nNumberOfBytesToWrite);

How can I declare and use my function in Delphi?

I declare the function like this:

...

var
function WriteUSB(myP:pByte;n:DWORD): integer ; external 'my.dll';

Should I use stdcall or cdecl in the declaration?

I call the dll function like this:

procedure myProc;
var 
   str : string:
begin
     str := 'AAAAAAAAAAAAAAAAAAAAA';
     WriteUSB(str,DWORD(length(tmp)));
end;

But this code give me exception all the time. I know that the problem is that "String" is Unicode and each charcter > 1 byte. I tried to convert to different string types (Ansichar and Short string) but I failed.

How is the correct way to do this?

BR Delphi user

A: 

Try casting it with pchar in your call:

  WriteUSB(pchar(str),DWORD(length(tmp))); 
M Schenkel
This won't work. The OP is using D2010, which means that String and PChar are Unicode and may be more than 1 byte per char. The DLL is looking for a pointer to BYTE, and there's no indication that the DLL function is Unicode aware.
Ken White
+10  A: 

A couple things. First off, if this is a C interface, which it looks like it is, then you need to declare the import like this:

function WriteUSB(myP:pAnsiChar; n:DWORD): integer; cdecl; external 'my.dll';

Then to call the function, you need to use an Ansi string, and convert it to a PAnsiChar, like so:

procedure myProc;
var 
   str : AnsiString;
begin
     str := 'AAAAAAAAAAAAAAAAAAAAA';
     WriteUSB(PAnsiChar(str), length(str));
end;

(The cast to DWORD is unnecessary.) If you do it like this, it should work without giving you any trouble.

Mason Wheeler
+2  A: 

You could convert the string to AnsiString (as already mentioned) if you're only going to use Ansi characters but if you want to use unicode strings AND the DLL/printer will accept them you could try something along the lines of (untested but I think it's generally corrext):

procedure myProc;
var
  str: string;
  buff: TBytes;
begin
  str := 'blahblahblah'; // plus additional unicode stuff
  buff := TEncoding.Default.GetBytes(str); // of TEncoding.UTF8 or... etc
  WriteUSB(@buff[0], Length(buff));
end;

Don't know whether this will work with this particular DLL but it is a more general way of coping with the shift to unicode strings rather than having to assume (and cast to) AnsiString everywhere.

shunty
Using `TEncoding.Default` is functionally the same as assigning a (Unicode)String to an AnsiString, ie: `var str: AnsiString; str := 'blah'; WriteUSB(PByte(PAnsiChar(str)), Length(str));`
Remy Lebeau - TeamB
Ok, I wasn't entirely sure about that. But, also, I think that chucking around TBytes is just nicer than casting back and forward and reduces the risk of confusion between different versions of Delphi and PChar/PAnsiChar. Plus I would normally use TEncoding.UTF8 rather than .Default but for some reason thought it better to use .Default in the example. Dunno why.
shunty
Whoops... And yes I realise TEncoding is new so would require ifdef everywhere with previous versions but I still think TBytes helps clear up confusion.
shunty
A: 

Hi.

Thanks a lot for all the feedbacks. I make it work by combining your feedbacks. The solution is:

Declaration (I add cdecl):

function WriteUSB( pc:pByte;n:DWORD): integer ; cdecl; external 'my.dll';

And the call:

Procedure myProc;
Var
    str : string;
    buff : TBytes;
begin
    str := 'My string";
    buff := TEncoding.Default.GetBytes(str); // of TEncoding.UTF8 or... etc
            WriteUSB(pByte(@buff[0]), Length(buff))

...
End;

I do have some problems with Swedish characters but I will solve it. Now I know that the DLL call is correct.

Thanks again for all feedback. This is a great forum.

BR Delphi User

amin