Solved

WriteFile() from mem outputs garbage... HELP

Posted on 1999-01-20
5
729 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

Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

Question has a verified solution.

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

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

830 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