Solved

WriteFile() from mem outputs garbage... HELP

Posted on 1999-01-20
5
731 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
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…
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

751 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