Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

WriteFile outputs junk

Status
Not open for further replies.

erac

Programmer
Nov 1, 2002
3
GB
I'm updating a 16 bit Delphi1 program, that uses the serial ports, to run on Delphi5/Win2000 but I'm having trouble with WriteFile.

If I use huge strings ($H+) string literals are output correctly but a string variable comes out as junk (I guess that Windows is getting the wrong buffer address). If I use short strings ($H-) both literals and variables work (sort of) but the initial length byte is included in the output and (hence) the last character is not output.

This is basic stuff so what am I doing wrong? Also in the code insight parameters for WriteFile what is const Buffer; - it's not a normal Pascal declaration of the form:- name : type; and I what's a type named Buffer!

WriteFile(hFile: Cardinal; const Buffer; nNumberOfBytesToWrite: Cardinal; var lpNumberOfBytesWritten: Cardinal; lpOverlapped: POverlapped)


>>>>>>>>>>>>>>>>>>>>> Sample program <<<<<<<<<<<<<<<<<<<<<
For simplicity it assumes that the mode of the serial port is already set up.

program console;
{$APPTYPE CONSOLE}
uses
WinProcs,
SysUtils;

var
handle: cardinal;
written: cardinal;
output: string;
begin
handle := CreateFile('COM1', GENERIC_WRITE, 0, nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if handle = INVALID_HANDLE_VALUE then
RaiseLastWin32Error;

if not WriteFile(handle,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
52, written, nil) then
RaiseLastWin32Error;

output := 'the quick brown fox jumped over the lazy dogs';
if not WriteFile(handle, output, Length(output),
written, nil) then
RaiseLastWin32Error;

CloseHandle(handle);
end.


>>>>>>>>>>>>>>>>>>>>> Output with $H+ <<<<<<<<<<<<<<<<<<<<<
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ¹

>>>>>>>>>>>>>>>>>>>>> Output with $H- <<<<<<<<<<<<<<<<<<<<<
4abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY-the quick brown fox jumped over the lazy dog

Note:
* ord('4') is 52 - the length of the literal,
* ord('-') is 45 - the length of the variable string.
 
The problem is not with WriteFile--it's working fine. The problem is with your understanding of strings. Strings, both small and large, are complex data types. The compiler normally takes care of the details for you but when you pass them as an untyped parameter the compiler can't help you.

A short string is a byte containing the length followed by the data. A long string is a pointer to the actual data, the length stored at a negative offset to the data. Thus if you pass a short string you get the length code included. Pass a long string and you get the pointer and the whatever follows in memory--total garbage as far as you are concerned.

Try writing output[1] instead of just output, you should get the results you expect, whatever string type you use.
 
Loren

Thanks for the help using WriteFile.

Using output[1] does work as does 'abc'[1] for literals. I find this counter-intuitive (at least for me ;-)), I would expect output[1] to be a single character and hence not a buffer at all - I guess it's my C/C++/Java background.

Richard
 
I come across this problem pretty much every other program I write because I always forget, if you define the length of a string (so you can write it to a file) it keeps anything that isn't overwritten.

eg.
Blob:String[15];

Blob := 'I'm saying hi';
Blob := 'Hi';
then write it to a file, would output 'Him saying hi'.

I use something like For i := 1 to 15 do Blob := ' ';
 
Erac:
What's misleading you is that you are considering it as a data type. However, WriteFile takes an *UNTYPED* parameter--which is really a pointer to the parameter you do supply. It would work exactly the same way in C or C++, I don't know Java to comment. However, in C or C++ it would have been declared as a pointer rather than an untyped parameter. You would explicitly make it a pointer and you would see what was going on.

Ragnafar:
If you write the length code along with the string you don't have that problem. If you don't want length codes in the file my preference is to write it as an array of characters instead.
 
Better you use char-array instead of String.

var
...
Output:Array [1..255] of char;
Buffer:pChar;
...
begin
Buffer:=@Output;
...
{do something which copy the datas you want to send
into the memory range begin with Buffer}
...
if (not WriteFile (PortHandle, Buffer[0], BytesWantWrite, dwWritten, PosWrite)) then
...



Maybe this will helps.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top