Solved

WriteFile() from mem outputs garbage... HELP

Posted on 1999-01-20
5
728 Views
Last Modified: 2010-04-04
Could someone please tell me why the WriteFile() in the following code
 outputs garbage.  See notes in code for more details in the section
 marked "DEFECTIVE PART".

//===============================================================
//=================== Code Starts ===============================
//===============================================================
 unit MainUnit;

 interface

 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
   StdCtrls, Buttons;

 type
   TMem2FileForm = class(TForm)
     Memo: TMemo;
     BitBtn1: TBitBtn;
     procedure BitBtn1Click(Sender: TObject);
     procedure FormCreate(Sender: TObject);
   private
     { Private declarations }
   public
     { Public declarations }
     procedure SaveMessageTooFile;
   end;

 var
   Mem2FileForm : TMem2FileForm;
   nMsgCnt      : CARDINAL;

 implementation

 {$R *.DFM}

 procedure TMem2FileForm.FormCreate(Sender: TObject);
 begin
   nMsgCnt := 0;
 end;


 procedure TMem2FileForm.BitBtn1Click(Sender: TObject);
 begin
   SaveMessageTooFile;
 end;

 //-------------------------------------------------------------------
 // Procedure to put data in mem and then write it to memory.
 // WriteFile () is not working properly.
 // No compile errors in D4.
 //-------------------------------------------------------------------
 procedure TMem2FileForm.SaveMessageTooFile;

 const
   CRLF = #13 + #10;

 var
    S                : string;
    szWaveFile       : array[0..254] of Char;
    szTestStr1       : array[0..64] of Char;
    szTestStr2       : array[0..64] of Char;
    bErrMsg          : Boolean;
    nBytesWritten    : DWORD;

    hFile            : THANDLE;
    hData            : CARDINAL;
    pData            : LPSTR;

 begin

 //---------------------------------------------------------------------
   S := '';
   S := ExtractFilePath(Application.exename);     // get path
   S := S + 'msg' + IntToStr(Integer(nMsgCnt))  + '.tst';
   StrPCopy(szWaveFile,S);

     hFile := CreateFile(                   // create file & get handle
            @szWaveFile,                    // pointer to file name
            GENERIC_READ or GENERIC_WRITE,  // access options
            0,                              // file sharing
            NIL,                            // security
            CREATE_ALWAYS,                  // Overwrites EXISTING
            FILE_ATTRIBUTE_NORMAL,          // No attribs
            0);                             // Misc flags (ex. overlapping)

     if hFile = THANDLE(NIL)
     then begin
       Mem2FileForm.Memo.Lines.Add('CreateFile ERROR');
       exit;
     end else begin
       Mem2FileForm.Memo.Lines.Add('CreateFile OK');
     end;

 //---------------------------------------------------------------------
 // Set up the memory (Seems to work.)
 //---------------------------------------------------------------------

 //  szTestStr1 := 'Keiths memory test string  xxxxxxxxx ';
     szTestStr1 := 'TTTTTTTTTTTTTTTTTTTTTTTTT  xxxxxxxxx ';

    hData  := GlobalAlloc (GPTR, 254);
    pData  := GlobalLock (hData);


     if (hData = 0) AND (pData = Nil)
      then begin
       Mem2FileForm.Memo.Lines.Add('GetMem for hData ERROR!!!!.');
      end else begin
       Mem2FileForm.Memo.Lines.Add('GetMem for hData OK.');
      end;

 //---------------------------------------------------------------------
 // The following works: szTestStr1 shows correctly in the memo.
 //---------------------------------------------------------------------

 try

     CopyMemory(pData,@szTestStr1,38);
     CopyMemory(@szTestStr2,pData,38);
     Mem2FileForm.Memo.Lines.Add(szTestStr2);

 //---------------------------------------------------------------------
 //
 //                      DEFECTIVE PART
 //
 // The following does NOT WORK:  I get identical garbage in the file,
 // no matter what I put into szTestStr1 above.
 //---------------------------------------------------------------------

    bErrMsg := WriteFile (
              hFile,
              pData,           // what is LPCVOID ?? Delphi does not support
              38,
              nBytesWritten,
              NIL);

   if bErrMsg = FALSE
   then begin
     Mem2FileForm.Memo.Lines.Add('WriteFileLast ERROR**');
     S := S + 'nBytesWritten = ' + IntToStr(Int64(nBytesWritten)) + CRLF;
     S := S + 'pData = ' + IntToStr(Int64(pData)) + CRLF;
     Mem2FileForm.Memo.Lines.Add(S);
     exit;
   end else begin
     Mem2FileForm.Memo.Lines.Add('WriteFileLast OK');
     S := 'nBytesWritten = ' + IntToStr(Int64(nBytesWritten)) + CRLF;
     S := S + 'MEM TO pData = ' + IntToStr(Int64(pData));
     Mem2FileForm.Memo.Lines.Add(S);
   end;

 //---------------------------------------------------------------------

 finally
     CloseHandle  (hFile);   // close message file
     GlobalUnLock (hData);   // free the mem
     GlobalFree   (hData);
 end;

 end;

 end.


//===============================================================
//=================== Code Ends   ===============================
//===============================================================

 Robert Keith Elias  (Quebec, Qc, Canada)   Address: kelias@CLIC.NET
0
Comment
Question by:broccoli
  • 2
  • 2
5 Comments
 
LVL 7

Expert Comment

by:BlackMan
ID: 1362503
Have you tried to add a ^ after pData ? Like this:

    bErrMsg := WriteFile (
              hFile,
              pData^,           // what is LPCVOID ?? Delphi does not support
              38,
              nBytesWritten,
              NIL
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1362504
BlackMan, you're right. It is declared in Delphi as "const buf;". That means you must not give in a pointer, but a pointer^.

Regards, Madshi.
0
 

Author Comment

by:broccoli
ID: 1362505
BlackMan;

Put in a dummy response and come and collect your points.
Sorry Madshi, maybe you'll be faster next time.

If you have any thoughts on:
1) why delphi defines "nBytesWritten"  as a DWORD (or cardinal or whatever) while win32 defines it as an LPDWORD and the value is correctly returned in "nBytesWritten" in Delphi, I would like to hear them.

2) Is "const buf" delphi's equivalent of LPCVOID?

Thanks.
0
 
LVL 7

Accepted Solution

by:
BlackMan earned 100 total points
ID: 1362506
1) nBytesWritten is defined as VAR in the header and a VAR parameter is actually just a pointer to a variable, that's why it's working..

2) No idea.

Have you tried to add a ^ after pData ? Like this:

    bErrMsg := WriteFile (
              hFile,
              pData^,           // what is LPCVOID ?? Delphi does not support
              38,
              nBytesWritten,
              NIL



0
 
LVL 20

Expert Comment

by:Madshi
ID: 1362507
Robert Keith,

in C(++) there's nothing like "var" or "const" in Pascal/Delphi. If you want to return something into a parameter variable, in C you have to give in a pointer to that variable. That's why you often see somethings like lppppppppppppppppppppointer (which is a pointer to a pointer to a pointer to ...).
In Pascal/Delphi you simply write "var/const", this saves the pointer nonsense.
I'm not sure about LPCVOID. I guess it is only an undefines pointer type. In Pascal/Delphi you can write "pointer" for that - or you write "var/const" without a type definition - and that's what Inprise used in your example. In the latter case you have to write "pointer^" instead of "pointer".

Regards, Madshi.
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

832 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question