Solved

Help Required Converting Two Small C++ Functions To Delphi

Posted on 2003-11-03
45
508 Views
Last Modified: 2010-04-05
I'm writing a Delphi 5 app which calls an external exe file. This bit works fine.

The author of the external exe has supplied me with a couple of functions to get info back from his exe, such as progress and error messages etc. but unfortunately they are C++ functions - something I have no understanding of whatsoever.

These two functions are quite small - only a couple of dozen lines or so each, but they mean nothing to me. I need someone experienced with C++ as well as Delphi who can give me some assistance in getting these two functions into my Delphi app.

I don't have permission to post his code on here, but I'm happy to e-mail it to anyone who thinks they can help. Just let me know where to mail it to.

I don't think the task is particularly difficult for anyone who programs with Delphi and C++ but I would appreciate getting this done as soon as possible so I'm offering 500 points. (I would offer more if it wasn't the maximum allowed).

Thanks in advance...

TDK_Man
0
Comment
Question by:tdk_man
  • 19
  • 15
  • 4
  • +2
45 Comments
 

Expert Comment

by:IamNewbie
ID: 9676788
Hello. Can u post these functions here, or send me by mail? <e-mail removed for user privacy> . I'll try.
0
 
LVL 5

Expert Comment

by:DeerBear
ID: 9677096
Hi,

Mail to:<e-mail removed for user privacy> and I'll try to help.

HTH,

Andrew
0
 
LVL 5

Expert Comment

by:snehanshu
ID: 9677597
tdk_man,
  Can you try to obtain permission for posting your code here? What's the point in having some unknown ppl viewing your code, but not posting it at ex-ex? See membership guidelines.
http://www.experts-exchange.com/help/mistakes.jsp
...Shu
0
 
LVL 5

Expert Comment

by:DeerBear
ID: 9677806
Sorry ma'am :-)

Won't do it again, I'm a good boy <g>

Cheers,

Andrew
0
 

Expert Comment

by:IamNewbie
ID: 9677830
sorry, can anyone view my e-mail address here???
if not, how can I comunicate?
I think this is only my thing, post my address here, or not to post... sorry, if I'm wrong
0
 

Expert Comment

by:IamNewbie
ID: 9678862
Soory, u right :-) This is forum, seems I forgot it :-)
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9680820
Looks like I owe an apology here - it's my fault that other members have had to be reprimanded by the mods when all they did was respond to one of my posts.

Please accept my apologies - I wasn't aware that I couldn't do what I did and it won't happen again.

I am currently awaiting permission to post the C++ code (or a link to it) and will do so when it is granted.

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9691127
I've decided to post the C++ code here as I am now at the stage where I need it and that it will initiate a speedy response. Thanks in advance for any help.

//
// Message Monitor (dummy editor)
//
#include "windows.h"

// Progress String
char pProgressString[1024];

// Windows Proc
LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 HDC hdc;
 PAINTSTRUCT ps;

 switch( message )
    {
  case WM_USER+0:
  {
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
   MessageBox(hWnd, (LPSTR)lpVoid, "WM_USER MESSAGE DETECTED", MB_OK | MB_TOPMOST);
   UnmapViewOfFile(lpVoid);
   CloseHandle(hFileMap);
   return TRUE;
  }

  case WM_PAINT:
   hdc=BeginPaint(hWnd, &ps);
   if(hdc)
   {
    Rectangle(hdc, 0, 0, 1024,28+22);
    TextOut(hdc, 0, 1, pProgressString, strlen(pProgressString));
    EndPaint(hWnd, &ps);
   }
   return TRUE;

  case WM_CLOSE:
   PostQuitMessage(0);
   return TRUE;

  case WM_DESTROY:
   PostQuitMessage(0);
   break;
    }

 // Default Action
    return DefWindowProc(hWnd, message, wParam, lParam);
}

// Windows Main
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
 // Vars
 MSG msg;
 WNDCLASS wc;

 // Register window
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = NULL;
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "TDBPROEDITOR";
    RegisterClass( &wc );

 HWND hWnd = CreateWindow( "TDBPROEDITOR",
        "DBPro Editor",
        WS_OVERLAPPEDWINDOW,
        0,0,1024,28+22,
        NULL,
        NULL,
        hInstance,
        NULL);

 ShowWindow(hWnd, SW_SHOW);

 // Initialise Global Vars
 strcpy(pProgressString, "");

 // Message Pump
 while(TRUE)
 {
  if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  {
   if(msg.message!=WM_QUIT)
   {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
   else
    break;
  }
  else
  {
   // Constand progress monitor
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   if ( hFileMap )
   {
    LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
    if ( lpVoid )
    {
     wsprintf(pProgressString, "Value:%d  String:%s", *(DWORD*)lpVoid, (LPSTR)lpVoid+4 );
     InvalidateRect(hWnd, NULL, TRUE);
     UnmapViewOfFile(lpVoid);
    }
    CloseHandle(hFileMap);
   }

   // Processor Friendly
   Sleep(100);
  }
 }

 return 0;
}

TDK_Man
0
 
LVL 5

Expert Comment

by:DeerBear
ID: 9692570
Hi,

Use this code as example:

program RAP;

uses
  SysUtils, Windows, Messages;

var MainWnd : THandle;
    Mesg : tagMSG;
    WndClass : tagWndClass;
    BtnWnd : THandle;
    EditWnd : THandle;
//    StaticWnd1,
    StaticWnd1 : THandle;
    MenuWnd : HMenu;

const MENU_ITEM = WM_USER+100;

function WndProc( hwnd : HWND;mesg : UINT;wparam : WPARAM;lparam : LPARAM ) : LongInt;stdcall;
var FuncR : LongInt;
//    GDC : HDC;
//    Rect : TRect;
    TstNum,
    TstNum2 : PChar;
begin
  FuncR := -1;
  case mesg of
    WM_CREATE : begin
                  FuncR := 0;
                end;
    WM_DESTROY : begin
                   PostQuitMessage( 0 );
                   FuncR := 0;
                 end;
    {WM_LBUTTONDOWN : begin
                      MessageBox( hwnd,'Mouse down','Application',MB_OK );
                    end;}
    WM_COMMAND : begin
                   if hwnd = BtnWnd then
                     MessageBox( hwnd,'Button click','Application',MB_OK );
                   if HiWord( WParam ) = 0 then
                   begin
                     GetMem( TstNum,255 );
                     TstNum2 := StrPCopy( TstNum, IntToStr( LoWord( WParam ) ) );
                     MessageBox( hwnd,TstNum2,'WParam',MB_OK );
                     FreeMem( TstNum );
                     GetMem( TstNum,255 );
                     StrPCopy( TstNum, IntToStr( MENU_ITEM ) );
                     MessageBox( hwnd,TstNum,'Application',MB_OK );
                     FreeMem( TstNum );
                     GetMem( TstNum,255 );
                     StrPCopy( TstNum, IntToStr( LParam ) );
                     MessageBox( hwnd,TstNum,'Application',MB_OK );
                     FreeMem( TstNum );
                   end;
                 end;
    {WM_PAINT : begin
                 if GetUpdateRect( MainWnd,Rect,True ) then
                 begin
                   GDC := CreateCompatibleDC( GetDC( MainWnd ) );

                 end;
               end;}
    WM_MENUCOMMAND : begin
                       GetMem( TstNum,255 );
                       StrPCopy( TstNum, IntToStr( LoWord( WParam ) ) );
                       MessageBox( hwnd,TstNum,'WParam',MB_OK );
                       FreeMem( TstNum );
                     end;
  else
    FuncR := DefWindowProc( hwnd,mesg,wparam,lparam );
  end;
  Result := FuncR;
end;

var SaveBtnProc : LongInt;
    BtnDown : Boolean;

function BtnWndProc( hwnd : HWND;mesg : UINT;wparam : WPARAM;lparam : LPARAM ) : LongInt;stdcall;
var EditTxt : PChar;
    TxtLen : Word;
begin
  Result := 0;
  case Mesg of
    WM_LBUTTONDOWN : begin
                       BtnDown := True;
                     end;
    WM_LBUTTONUP : begin
                     if BtnDown then
                     begin
                       GetMem( EditTxt,255 );
                       FillChar( EditTxt^,255,32 );
                       TxtLen := 50;
                       Move( TxtLen,EditTxt^,SizeOf( TxtLen ) );
                       SendMessage( EditWnd,EM_GETLINE,0,LongInt( EditTxt ) );
                       MessageBox( hwnd,EditTxt,'Button',MB_OK );
                       FreeMem( EditTxt );
                     end;
                   end;
    WM_COMMAND : begin
                 end;
  else begin
         Result := CallWindowProc( Pointer( SaveBtnProc ),hwnd,mesg,wparam,lparam );
       end;
  end;
end;

//var ItemInfo : TMenuItemInfo;

begin
  WndClass.lpfnWndProc := @WndProc;
  WndClass.style := CS_HREDRAW or CS_VREDRAW;
  WndClass.cbClsExtra := 0;
  WndClass.cbWndExtra := 0;
  WndClass.hInstance := hInstance;
  WndClass.hIcon := LoadIcon(0,IDI_APPLICATION);
  WndClass.hCursor := LoadCursor(0,IDC_ARROW);
  WndClass.hbrBackground := GetStockObject(WHITE_BRUSH);
  WndClass.lpszMenuName := Nil;
  WndClass.lpszClassName := 'TestApp';
  RegisterClass( WndClass );
  MainWnd := CreateWindow( 'TestApp','Test',WS_TILEDWINDOW + WS_VISIBLE,100,100,200,200,0,0,HInstance,nil );
  StaticWnd1 := CreateWindow( 'STATIC','Static text',WS_CHILD or WS_VISIBLE or SS_LEFT,10,10,100,30,MainWnd,0,hinstance,nil );
  EditWnd := CreateWindow( 'EDIT','',WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL,10,50,100,30,MainWnd,0,hinstance,nil );
  BtnWnd := CreateWindow( 'BUTTON','Test',WS_CHILD or WS_BORDER or WS_VISIBLE or BS_PUSHBUTTON or BS_TEXT,10,100,50,30,MainWnd,0,hinstance,nil );
  MenuWnd := CreateMenu;
  InsertMenu( MenuWnd,MENU_ITEM,MF_BYCOMMAND or MF_ENABLED or MF_STRING,0,'Test ITEM' );
  SetMenu( MainWnd,MenuWnd );
  SaveBtnProc := GetWindowLong( BtnWnd,GWL_WNDPROC );
  SetWindowLong( BtnWnd,GWL_WNDPROC,LongInt( @BtnWndProc ) );
  ShowWindow( MainWnd,CmdShow );
  UpdateWindow( MainWnd );
  while GetMessage( Mesg,0,0,0 ) do
  begin
    TranslateMessage( Mesg );
    DispatchMessage( Mesg );
  end;
end.

HTH,

Andrew
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9693479
Great thanks!

Will check it out and report back later. :)

Regards...

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9696407
I've had a good look at it and it's way above my standard of Delphi programming! To be honest I don't understand more than I do understand! :)

Anyway, I got it running and then used my app to call the compiler program. Nothing happened at all, so obviously modifications are required - after all I realise that you did say "use this code as an example".

The following is an excerpt from the info I was given:

"The compiler uses the file map as described above to send a message.  The first DWORD of the message stores the line number, and the characters after this DWORD stores the string that contains the compiler error text."

I need to incorporate this into my existing Delphi code so I can monitor the compiler's progress and receive error messages back from it.

I assume that the code above is more of a 'this is how you go about it' piece of code rather than code which is translated from the C++ code I posted right? If so, then I'm afraid I don't understand enough of it to convert it myself.

TDK_Man
0
 
LVL 5

Expert Comment

by:DeerBear
ID: 9699672
Hi,

That's because you didn't "study" the code I gave you <g>.
Anyway, I'll help you out.

> LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )

This is the Window Proc. In my program you find its declaration

>  HDC hdc;

var DeviceContext : HDC; // Defined in Windows.pas
var PS : PaintStruct;// Defined in Windows.pas

>  switch( message )

This is a "case of" and translates:

case Message of

>  case WM_USER+0:

The items prefixed by "case" are the values, just ripp off the word "case".
All the messages are defined in the "Messages" unit.

>   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");

You can, in C, declare variables where you want, in Delphi you can't, so you have to
declare all of them before the "begin".
Thus you'll write there:

var HFileMap : THandle;
var Buffer : PChar;// LPVOID is a C macro translated into "void *", which is an untyped pointer.

>   LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);

I translated lpVoid into "Buffer" for better readability.
Now we've declared it, let's use it like this:

Buffer := Pointer( MapViewOfFile( hFileMap,FILE_MAP_READ,0,0,256 );

Memory Map Files are an InterProcess Communication technique( IPC ).
They're used to share memory among modules.

>   MessageBox(hWnd, (LPSTR)lpVoid, "WM_USER MESSAGE DETECTED", MB_OK | MB_TOPMOST);

This is an API messagebox. YOu can see a cast to LPSTR of the buffer, thus I update the
buffer to a PChar, since LPSTR in C is defined as "char *".

>   UnmapViewOfFile(lpVoid);

Here you simply unmap the memory. Copy the code as it is.

>   CloseHandle(hFileMap);

Since you opened a handle, now you've got to close it.
WinAPIs are a bit nasty about this, always close the handles you
open.

>    return TRUE;

As you understood, it was a function.

>  case WM_PAINT:

>   hdc=BeginPaint(hWnd, &ps);

Here you see painting start:
BeginPaint is defined in Windows.pas

>   if(hdc)

This means : if Hdc > 0, when you program in C False is 0 and True is > 0.

 >    Rectangle(hdc, 0, 0, 1024,28+22);
 >   TextOut(hdc, 0, 1, pProgressString, strlen(pProgressString));
 >   EndPaint(hWnd, &ps);

Some API calls, all defined in Windows.pas I think. Didn't check though.

>  case WM_CLOSE:
>   PostQuitMessage(0);
>   return TRUE;

This is to close the window.
PostQuitMessage allows the window to quit the message loop.


>  case WM_DESTROY:
 >  PostQuitMessage(0);
 >  break;
 >   }

Same as above.


Wow, this was the end of the WindowProcedure, I hope I gave you enough hints to do by yourself.
Please, DO learn some API programming, test things, try, otherwise you'll always need help.

HTH,

Andrew
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9704409
hello tdk_man, to me it seems that you are NOT getting what you need for understanding what you need to do for this, as you have said, that Long C- code you have posted has little to to with what you need,
First, I'll say what my "Guess" is as to what this app is, From the code you posted, this creates an appication 1024 wide and 50 pixels High, which will be at the top of screen work area, This app then reads a Memory mapped file 10 times a second with Sleep(100) and puts a number and some text on the face of the app like a TLabel,
I guess this is for some type of Progress since the text variable name is pProgressString, , Also there is a WM_USER message that seems to be some sort of "Notification" message or something? ? who can tell?


You are not needing all of the code, Delphi will do most of it for you when it creats a Program, So, The important part is the line

"The compiler uses the file map as described above to send a message",
so the ONLY part of all of that code you need to use is the -

 else
  {
   // Constand progress monitor
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   if ( hFileMap )
   {
    LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
    if ( lpVoid )
    {
     wsprintf(pProgressString, "Value:%d  String:%s", *(DWORD*)lpVoid, (LPSTR)lpVoid+4 );
     InvalidateRect(hWnd, NULL, TRUE);
     UnmapViewOfFile(lpVoid);
    }
    CloseHandle(hFileMap);
   }

   // Processor Friendly
   Sleep(100);
  }

   And The -

case WM_USER+0:
  {
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
   MessageBox(hWnd, (LPSTR)lpVoid, "WM_USER MESSAGE DETECTED", MB_OK | MB_TOPMOST);
   UnmapViewOfFile(lpVoid);
   CloseHandle(hFileMap);
   return TRUE;
  }

which opens the Mapped file and gets the PChar pointer lpvoid from the memory of this mapped file - - - - - -
here is the Pascal Code for what I think you need -

Create a Delphi Program and make your Form1 1024 pixels wide (probally Screen Width would be better) and about 60 pixels high give or take. Then Place a Single TLabel on the Form1 on the extream Left side of the form, it should be auto size. Now Place a TTimer on your form and set the interval to 200 (they use 100, but it seems to fast to me), Im not to sure about wheater or not to have it start as Enabled, but set it To Enabled.

here is some code for that unit -


  private
    { Private declarations }
    // You will need to get the WM_USER message
    procedure WMUser0(var Msg: TMessage); message WM_USER;


implementation

{$R *.DFM}

procedure TForm1.WMUser0(var Msg : TMessage);
{type
  PMapRec = ^TMapRec;
  TMapRec = record
    Line: Cardinal;
    Position: Cardinal;
    end;}

var
hFileMap: Cardinal;
//PEMessage: PMapRec;
{the variable above can be used IF there is a DWORD in front of the text}

PEMessage: PChar;
begin
Msg.Result := 0;
hFileMap := OpenFileMapping(FILE_MAP_READ,False,'DBPROEDITORMESSAGE');
{To me this seems like a BAD codding pratice to read Both the Progress AND
this WM_USER notification message from the same DBPROEDITORMESSAGE File Map}

if hFileMap = 0 then
  begin
  ShowMessage('ERROR - File Mapping is NOT availible');
  Exit;
  end;
try
  PEMessage := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 256);
  if (PEMessage = nil) then
    begin
    ShowMessage('ERROR - Map Memory is NOT availible');
    Exit;
    end;

{I also think that this is BAD Coding, to have this as all Characters in this Map File
WM_USER message, and as a DWORD number and then Text in the progress message}
  //Label1.Caption := IntToStr(PEMessage.Line)+'  '+PChar(@PEMessage.Position);
{above is the code for a Label if the first 4 bytes are a DWord}

  MessageBox(Handle, PEMessage, "WM_USER Message Detected", MB_OK or MB_TOPMOST or MB_ICONINFORMATION);
  Msg.Result := 1;
  finally
  UnmapViewOfFile(PEMessage);
  CloseHandle(hFileMap);
  end;
end;

/////////////////////////


procedure TForm1.Timer1Timer(Sender: TObject);
type
  PMapRec = ^TMapRec;
  TMapRec = record
    Line: Cardinal;
    Position: Cardinal;
    end;
// The above Record is to get the DWORD progress number and the Text
// which will be at the Position, but you will need to typecast it's Mem Addy as a PChar

var
hFileMap: Integer;
PEMessage: PMapRec;
begin
{this timer event will read the Map File 5 times a second and write the progress number
and the Text to Label1}
hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');
if hFileMap > 0 then
  try
  PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
  if PEMessage <> nil then
  Label1.Caption := IntToStr(PEMessage.Line)+'  '+PChar(@PEMessage.Position);
  finally
  UnmapViewOfFile(PEMessage);
  CloseHandle(hFileMap);
  end; {else
  Timer1.Enabled := False;}

{from all I can tell their Progress text retrival runs THE ENTIRE TIME THE PROGRAM EXISTS}
end;


 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

you will need to make SURE that the "sending" application is using your Forms "Handle" to send the message to, , ,
you do not say how the sending program (or DLL) gets the Handle to send this WM_USER message.
Also, I guess this Form is created when the Progression begins and is destroyed when the progression ends, if not you may want to add methods to start and end the timer. .

you really do not need to create an API program with the translated C-Code to do this, However if you are interested in API programming for Delphi you can visit my site at -

http://www.angelfire.com/hi5/delphizeus/index.html

ask questions if you need more info
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9705326
Slick812:

Thanks for that. You seem to have more of a handle on what I am trying to do.

Many thanks to DeerBear, but I am a novice Delphi programmer and I do not want to write another program, nor do I need to learn using the API - for the moment at least, though I do intend to later. Your explanation was excellent and concise, but if I understood it all, I wouldn't be posting for help on here! :)  But I repeat, I am grateful for your attempts to assist.

My program is very basic (like my Delphi programming incidentally).  It is a simple text editor in which you type source code. You then hit the compile button and my app sends information to a stand-alone compiler which compiles the code you have entered.

The compiler's author sent me the C++ code to demonstrate how information (like compilation progress) is received from a mapped file generated by the compile while it is working. Unfortunately, he didn't know I knew absolutely nothing about C++ and he's never touched Delphi.

The C++ code I posted is actually the source for a stand-alone program which as Slick812 correctly says puts a window on the screen containing the information passed back from the compiler - purely for demonstration purposes.

As I said in my first post, I want to get this information *in my existing Delphi application* - not create another program. I don't need the Delphi functions to put anything on the screen - just make the info available to my program ("The first DWORD of the message stores the line number, and the characters after this DWORD stores the string that contains the compiler error text."). Therefore, I assume that the function(s) I am after would simply make available the line number as an integer and the message as a string.

The C++ code I posted, I assume simply compiles 'as-is' into an exe which can be executed. If you had the compiler it would display info when the compiler was in use, so I guess the C++ routines (if you understand them) tell you all you need to know to produce a Delphi equivalent.  I'm not trying to re-write that C++ program in Delphi.

I realise that the skills required to do this are way above my current abilities and that some kind person is going to have to 'babysit' me through the process to get it to work. But I'm paying well you might say! :)

I'd quite gladly pay 3000 points to get this done - if there was a way to do it.

Thanks...

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9706016
???????
I have read your posts here, and you DO NOT give very much info about the techincal stuff about this Mem Mapped File (which I can only guess is the foundation of all of your question)  and the WM_USER message, like why is it posted, why is it described as having a DWORD header and yet the code you showed just typecast it as a LPSTR (a PChar more or less) and trys to show it in a message box? ? ? Does not make any sense to me at all.

 LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
   MessageBox(hWnd, (LPSTR)lpVoid, "WM_USER MESSAGE DETECTED", MB_OK | MB_TOPMOST);

seems like it should be
   MessageBox(hWnd, (LPSTR)lpVoid+4, "WM_USER MESSAGE DETECTED", MB_OK | MB_TOPMOST);
? ? ?

also, his method of getting the progress information from the Mem Mapped File seems kind of Wacky to me, the whole

 while(TRUE)
 {
  if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  {
   if(msg.message!=WM_QUIT)
   {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
   else
    break;
  }
  else
  {
   // Constand progress monitor
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   if ( hFileMap )
   {
    LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
    if ( lpVoid )
    {
     wsprintf(pProgressString, "Value:%d  String:%s", *(DWORD*)lpVoid, (LPSTR)lpVoid+4 );
     InvalidateRect(hWnd, NULL, TRUE);
     UnmapViewOfFile(lpVoid);
    }
    CloseHandle(hFileMap);
   }

   // Processor Friendly
   Sleep(100);
  }
 }

seems like a bad way to do this, , but there is probally a whole LOT that I do not know. . . Like why why why would you need to query the mem map file 10 times a second? This must be one fast progress mover, I would have used a WM_USER message with the progress in that message, so the progress display would only be changed if the progress was changed.

This is just a guess, but from looking at the C-Code, It looks like a very Quick code write from memory, that was not really run to test it,  but I have almost no knowledge of what is going on

So

I wonder if you understand the Delphi code that I gave you? ? Did you try that code, does it get anything from the mem mapped file?
this whole thing seems (??? what do I know?) to be getting you to be able to read a mem mapped file. . . Do you know what a mem mappped file is?, , Here is a description from the API help -

File mapping is the association of a file's contents with a portion of the virtual address space of a process. The operating system creates a file-mapping object to maintain this association. A file view is the portion of virtual address space that the process uses to access the file's contents. Processes read from and write to the file view using pointers, just as they would with dynamically allocated memory.. . . When multiple processes use the same file-mapping object to create views for a local file, the data is coherent.. . .File mapping provides two major advantages:

·      Shared memory
·      Faster and easier file access

File mapping allows two or more applications to share memory. Win32-based applications cannot share memory by any other means.
 - - - - - - - -  - - - - -

So, In the code I gave you, FIRST you need to Open a previously Created Memory File Map named  DBPROEDITORMESSAGE -
hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');

Once you got the mapped file handle you can get its Pointer addy with -
aPointer := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 256);

now you have the mem addy in aPointer, And I am guessing you do not have a clue about reading data from a mem addy (Pointer)

First, you absolutely HAVE to know what the Data structure and arangement is in the memory block, according to the very little info you gave it consists of a DWORD (pascal Cardinal), followed by a null (#0) terminated array of characters

so you could read it by Typecasting the aPointer to a  PDword
MyCard := PDword(aPointer)^;

OR do as my code and do a Pointer to a Record, the Caracter array can be type cast as a PChar, but you will need to move the Pointer past the DWORD memory block, in C-Code you can just add 4
(LPSTR)lpVoid+4

but in delphi you will need to typecast and do pointer arithmatic

PChar(Cardinal(aPointer)+4)

I hope this is enough to get you started
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9706087
Just a Guess

Have a Progress TLabel on your "Text Editor", lets call it LabelProg and when you click the button or menu Iten to start compiling in the separate compiler (which I guess is reading some code text files) , the right after you call the compiler, with ShellExecute or whatever, Then set your timer interval to about 500 mseconds, which should be fast enough, then Start your timer
Timer1.Enabled := True;

and use the timer event

procedure TForm1.Timer1Timer(Sender: TObject);
var
hFileMap: Integer;
PLine: PDword;
begin
hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');
if hFileMap > 0 then
  try
  PLine := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
  if PLine <> nil then
  LabelProg.Caption := IntToStr(PLine^);
  finally
  UnmapViewOfFile(PEMessage);
  CloseHandle(hFileMap);
  end;
end;

You will need to know when the compiler is finished and then set
Timer1.Enabled := False;
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9706106
I've just spent a couple of hours comparing the C++ code with the code that Slick812 posted. It runs, but doesn't work yet, but I've been experimenting and making changes to the code. I have learnt something about File Mapping in the process too!

The code looks to be correct, but doesn't work. I've been running it with the exe version of the C++ code and when I click on the compile button in my program, the compiled C++ exe shows the compiler message fine - so at least I know that the compiler is actually sending messages.

When it's run, it doesn't produce any messages to say that file mapping is not available, but it doesn't say that it's detected any messages from the compiler either.

Also, I notice that the code in the timer event section is the same as in the WMUser0 procedure. Is the WMUser0 procedure required - where is it called?

I won't give up on it though, I'd prefer to sort it out from the supplied info if I can! :)

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9706145
As a quick reply to your last but one message (before I read the rest), I have supplied you with all the information I have. Honest!!!

All I have been given is the C++ code I posted at the beginning, along with the compiled exe of the code and a text file which I have also quoted in this thread.

I don't know what else I can provide you with. I have explained what my Delphi program is, what it does and how it interacts with a compiler exe. My editor creates the source and the compiler compiles it. The compile/run side is working perfectly.

The only bit that isn't is the compiler progress side of things. I'd like to be able to put a progress bar on the screen to show the progress while the compiler is grinding away. As some compiles only take a second to happen, the polling rate for the timer has to be pretty sharpish.

Look, I'm not trying to hold back any info here - I'm just after help doing something I can't do myself without help.

The C++ 'monitor' code is compiled and run. While it is running, if I load a source file into my editor then hit Compile, messages appear in the monitor window. So, logically, everything that you need to know is within that C++ code right? Obviously you have to be able to understand C++, which I don't.

I didn't understand what File Mapping was before this evening, but I have a pretty good idea now.

Just tell me what info you think is missing and I'll ask the guy who wrote the compiler to supply it.

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9706162
OK, you posted while I was typing that last message. I'll try your last suggestion.

Thanks!

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9706207
No, nothing! :(

I changed the typo? on line:

UnmapViewOfFile(PEMessage);

to

UnmapViewOfFile(PLine);

I used Timer2 as I already have Timer1 in use. My compile button checks to see that a source window is open then uses the following code (so that I can detect when the compiler has finished compiling and disable the timer):

      Timer2.Enabled:=True;
      ParamString := SourceName[(ActiveMDIChild as TForm2).Tag];
      StartInString:=ProjPath[(ActiveMDIChild as TForm2).Tag];
      FillChar(SEInfo, SizeOf(SEInfo), 0);
      SEInfo.cbSize := SizeOf(TShellExecuteInfo);
      with SEInfo do begin
        fMask := SEE_MASK_NOCLOSEPROCESS;
        Wnd := Application.Handle;
        lpFile := PChar(CompilerExe);
        lpParameters := PChar(ParamString);
        lpDirectory := PChar(StartInString);
        nShow := SW_SHOWNORMAL;
      end;
      if ShellExecuteEx(@SEInfo) then
      begin
        repeat
          Application.ProcessMessages;
          GetExitCodeProcess(SEInfo.hProcess, ExitCode);
        until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
        Timer2.Enabled:=False;
        ShowMessage('Program Compiled');
      end
      else ShowMessage('Error Starting Compiler!');

The code in the Timer event I have entered exactly as you specified.

I've e-mailed the guy who wrote the compiler to ask him to double check that the info he has supplied me with is correct - along with as much technical info as possible.

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9707564
It does not matter so much (to me) if the C-code is correct or not since you do not seem to want to use his method (make a separate pop-up window to do just the progress). . . If you are able to ask him, then tell him that you want to run the "Progress Map Fille Read" in a WM_Timer, ask if there is any reason a WM_TIMER would not work, and ask if a 100 msecond interval is about right for the timer. You might also ask what the  the WM_USER message is suppose to notify you of?

Now just as a test to see if you are Getting ANY read of the mem map file, set your timer2 interval to 50 mseconds and use the code -

Timer2.Enabled:=True;
if ShellExecuteEx(@SEInfo) then

to start the timer and compiler just like the code you showed, add another "Test result TLabel" , then for yout timer 2 event


procedure TForm1.Timer2Timer(Sender: TObject);
var
hFileMap: Integer;
PLine: PDword;
begin
hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');
if hFileMap > 0 then
  try
  TestResultLabel.Caption := 'I Got The hFileMap!';
  PLine := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
  if PLine <> nil then
  LabelProg.Caption := IntToStr(PLine^);
  finally
  UnmapViewOfFile(PLine);
  CloseHandle(hFileMap);
  end;
end;

. . . . may be at 500 mseconds, the compiler is already finished and the Mem Map File is already gone
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 1

Author Comment

by:tdk_man
ID: 9707722
> "It does not matter so much (to me) if the C-code is correct or not since you do not seem to want to use his method (make a separate pop-up window to do just the progress). . . "

By 'his method', I assume that you mean exactly what his C++ code does. As I have said before, his ++ code is just the source for a stand-alone example monitor program which displays info from the compiler when it is working. I DO need to use the Delphi equivalent of his C++ functions to get the data into my program so I can display it.

If I can read the file map then I will create a pop-up with a progress bar on it, but I obviously need the progress value in my app to do so (along with the following error data). All I am clearly saying is that I want to keep the code within my own app rather than re-creating his C++ code (which is a stand-alone program) in Delphi.

What I meant by "the C++ code being correct" was whether the C++ code may have been altered before compiling into the exe I received, but the old C++ code was sent with it. In which case, some detail of the C++ code may not have been correct. It would appear that I do have the correct C++ code.

As it is at the moment, it looks like the mapped file is not being accessed as neither of the labels are changing when I click on the compile button using the code you supplied.

The first four bytes of the return data is the line number during the progress of the compiler and on exit from the compiler the first four bytes are the line number the error occured on and the remainder of the data is the error message.  This may or may not be 'bad coding practice', but obviously I had nothing to do with this and that's how it's been done. :)

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9707848
OK, if the TestResultLabel label was not  changed, then we got nothing. . .

my code followed by his code

hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');  // my code
 hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");  // his code

I can not see ANY difference in the parameters, I coppied them exactly, if the function OpenFileMapping returns Zero then there is NO DBPROEDITORMESSAGE file map, as far as I know. . .  I am clueless as to why the OpenFileMapping( ) does not open anything. . . However I guess we can try something else? Here is code for a button click with an Improved (at least my view) compiler execute method, your code uses a

  repeat
          Application.ProcessMessages;
          GetExitCodeProcess(SEInfo.hProcess, ExitCode);
        until (ExitCode <> STILL_ACTIVE) or Application.Terminated;

loop, which seems like it would execute more than you need -

procedure TForm1.button1Click(Sender: TObject);
Var
ShExInfo: TShellExecuteInfo;
hFileMap: Integer;
PLine: PDword;
begin
FillChar(ShExInfo, Sizeof(ShExInfo), 0);
with ShExInfo do
  begin
  cbSize:= Sizeof(ShExInfo);
  fMask := SEE_MASK_NOCLOSEPROCESS;
  Wnd := Handle;
  lpVerb := 'open';
  lpFile := PChar(CompilerExe);
  lpParameters := PChar(ParamString);
  lpDirectory := PChar(StartInString);
  nShow := SW_SHOWNORMAL;
  end;
if FileExists(ShExInfo.lpFile) and ShellExecuteEx(@ShExInfo) then
  begin
  while WaitForSingleObject(ShExInfo.hProcess, 100) <> WAIT_OBJECT_0 do
    begin
    Application.ProcessMessages;
    hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');
    if hFileMap <> 0 then
      try
      TestResultLabel.Caption := 'I Got The hFileMap!';
      PLine := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
      if PLine <> nil then
      LabelProg.Caption := IntToStr(PLine^);
      finally
      UnmapViewOfFile(PLine);
      CloseHandle(hFileMap);
      end;
    end;
  end else
  ShowMessage(SysErrorMessage(GetLastError));
CloseHandle(ShExInfo.HProcess);
showmessage('Compiler is finished');
end;

- - - - - - - - - - - - - - - - - - - - - - - - - - -

if the TestResultLabel.Caption does NOT change, then I can not figure why the OpenFileMapping would return zero if the file map exists
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9707852
you do NOT use a Timer with the new code
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9710678
>"if the TestResultLabel.Caption does NOT change, then I can not figure why the OpenFileMapping would return zero if the file map exists"

I agree!

Looking on the web for further info on this I found a tutorial which covered the subject, along with some code which demonstrated how to create a mapped file and send some info.

I modified this code so that it created a mapped file with the same name as the compiler supposedly does and bingo! When it is running, your code duly pops up a message saying that the message has been detected when I click on the compile button in my application.

When this program is not running, the compile button results in nothing, so I know that the detected message is from the other program - not the compiler. At least we are confirming that the problem is not down to your code and hopefully we are one small step closer to solving the problem...

I am awaiting a reply from the author of the compiler having asked him nicely if he will write a small 'dummy' program for me which when run, will permanently sit on screen transmitting the messages to the mapped file. This should allow me to rule out timing problems where I'm checking for the existance of messages after they have disappeared etc.

I've also asked him the questions you suggested in an earlier post.

TDK_Man

0
 
LVL 33

Expert Comment

by:Slick812
ID: 9711780
OK, I tested the code I originally posted for the mapped file, by creating a mem mapped file with the name of  DBPROEDITORMESSAGE and it  did work with that, So I would think that the file map name he gave you is NOT what the version of the compilier is using. . . .

the last code I posted does NOT get the text for the mem map file it only gets the DWORD for the line number, here is some code that will also get the text


type
  PMapRec = ^TMapRec;
  TMapRec = record
    Line: Cardinal;
    Text: Array[0..251] of Char;;
    end;
// The above Record is to get the DWORD progress number and the Text
// which will be at the Position, but you will need to typecast it's Mem Addy as a PChar

var
hFileMap: Integer;
PEMessage: PMapRec;
begin
hFileMap := OpenFileMapping(FILE_MAP_READ, False, 'DBPROEDITORMESSAGE');
if hFileMap <> 0 then
  try
  PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
  if PEMessage <> nil then
  Label1.Caption := IntToStr(PEMessage.Line)+'  '+ PEMessage.Text;
  finally
  UnmapViewOfFile(PEMessage);
  CloseHandle(hFileMap);
  end;

- - - - - - - - - - - - - - - - - - - - - -
I do not remember any, but I will look and see if there is a way to get the name of a mem map file, if you do not know it
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9712370
I'm another step closer to the goal. Having read a couple of web pages explaining memory mapped files, re-reading this thread from scratch has made a lot more sense.

Using the info you have posted, I've been experimenting and have had partial success. As the compiler can grind though my editor's source code at quite a rate (hundreds of lines per second), you can imagine that the couple of hundred lines long test file doesn't take long to compile - hence the high sampling rate. I could use a longer test file, but it will still need to show a progress bar - even if the compilation process only takes a fraction of a second.

The only way I can get it to work for some reason is to try to create a mapped file of the same name as I need to read with CreateFileMapping() and then check to see if GetLastError = ERROR_ALREADY_EXISTS. If it does, I scrap it and use OpenFileMapping() to hook into the one created by the compiler. (I created a constant for the mapped file name).

I then use MapViewOfFile() to get the message and print the Line number and Message to a couple of Edit boxes using your code with:

RetValEdit.Text := 'Line: '+IntToStr(PEMessage.Line);                          RetStrEdit.Text := 'Message: '+PEMessage.Text;  

Now, when I hit the compile button, 'Line: 0' and 'Message: ' appears, but nothing else.

As these two lines are only executed IF the message has been received, it at least tells me that I'm heading in the right direction. It just looks like the information isn't being placed into the record correctly.

Here's my almost working procedure so far...

procedure TMainForm.CompileClick(Sender: TObject);
type
  PMapRec = ^TMapRec;
  TMapRec = record
    Line: Cardinal;
    Text: Array[0..251] of Char;
    end;
Var
  SEInfo: TShellExecuteInfo;
  ExitCode: DWORD;
  ParamString, StartInString: string;
  Result: Integer;
  hFileMap: Integer;
  PEMessage: PMapRec;
begin
  // Compile Button Clicked
  // Note FileMapName is a defined constant: 'DBPROEDITORMESSAGE'
  If MDIChildCount>0 then  // Check to see if a source file is loaded
    Begin
      ParamString := SourceName[(ActiveMDIChild as TForm2).Tag];  
      StartInString:=ProjPath[(ActiveMDIChild as TForm2).Tag];
      FillChar(SEInfo, SizeOf(SEInfo), 0);
      SEInfo.cbSize := SizeOf(TShellExecuteInfo);
      with SEInfo do begin
        fMask := SEE_MASK_NOCLOSEPROCESS;
        Wnd := Application.Handle;
        lpFile := PChar(CompilerExe);  
        lpParameters := PChar(ParamString);
        lpDirectory := PChar(StartInString);
        nShow := SW_SHOWNORMAL;
      end;
      if ShellExecuteEx(@SEInfo) then
        begin
          // Start the compilation loop...
          Repeat
          // Try to create a filemapped file and check for errors...
          Result := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,1024,FileMapName);
          if Result <> 0 then // A valid handle was returned so check GetLastError
            Begin
              if GetLastError = ERROR_ALREADY_EXISTS then // Mapped file was already there
                begin
                  CloseHandle(Result); // So we close new one and open existing mapped file
                  hFileMap := OpenFileMapping(FILE_MAP_READ,False,FileMapName);
                  try
                    PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
                    if PEMessage <> nil then  // The message must have been received!
                      Begin
                        RetValEdit.Text := 'Line: '+IntToStr(PEMessage.Line); // Line Number edit box
                        RetStrEdit.Text := 'Message: '+PEMessage.Text;        // Message edit box
                      End;
                  finally
                    UnmapViewOfFile(PEMessage);
                    CloseHandle(hFileMap); // Possibly not required here??
                  end;
                end;
            End;
            Application.ProcessMessages;
            GetExitCodeProcess(SEInfo.hProcess, ExitCode);
          until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
          ShowMessage('Program Compiled');  // Shown on compilation end
        end
      else
        ShowMessage('Error Starting Compiler!');
    End;
end;

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9712542
Amazing... and baffling!

I just had the idea of running the exe version of that C++ code at the same time as my program just to confirm that messages were being sent from the compiler and guess what - the code in my program (posted above) works 100% perfectly - right down to the reported line number and error message!! :)

http://www.matedit.com/messages.jpg

But, when the compiled C++ exe is not running, my program does absolutely nothing! :(

So, it's obvious that C++ code is doing something that my program is not doing to initialise some process to receive the messages. When it's running I can receive the messages from the compiler, but otherwise zilch.

It also confirms that the mapped file name is correct in the C++ code, so what on earth am I missing?

Strange or what?

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9716974
???
I can not get any ideas from your comments about what might be going on with the success and fail of your code. . .just my opinion, I think I would use the
while WaitForSingleObject(ShExInfo.hProcess, 100) <> WAIT_OBJECT_0 do

instead of your

Repeat
 until (ExitCode <> STILL_ACTIVE) or Application.Terminated;

that repeat  loop could really soak up your processor cycyles, but I can not think that is the reason for success or fail of your code, I I do not have a way to test it, Since you seem to have some success with the
CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,256,FileMapName);
you can use that instead of the OpenFileMapping

here is some code that you might be able to get an idea of some other way to try and do this, The Application.Processmessages, is about the only facktor that I can see is much different that his code, so you might move it to after the file map stuff


if  ShellExecuteEx(@ShExInfo) then
  begin
  while WaitForSingleObject(ShExInfo.hProcess, 100) <> WAIT_OBJECT_0 do
    begin
    Application.ProcessMessages;  // try and move this to AFTER file mapping if not success
    hFileMap :=  CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,256,FileMapName);
      if hFileMap <> 0 then
        Begin
         if GetLastError = ERROR_ALREADY_EXISTS then // Mapped file was already there
                begin
  // do NOT use a try and finally here, there is nothing that should exception out and it takes time to do the try checks
               PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
               if PEMessage <> nil then  // The message must have been received!
                 Begin
                 RetValEdit.Text := 'Line: '+IntToStr(PEMessage.Line); // Line Number edit box
                 RetStrEdit.Text := 'Message: '+PEMessage.Text;        // Message edit box
                 End;

               UnmapViewOfFile(PEMessage);
               CloseHandle(hFileMap); // yes you should Always Close any file map handle
               end else
               CloseHandle(hFileMap);
    //Application.ProcessMessages; //may be this Process messages is a factor? ?
    end;
  end else
  ShowMessage(SysErrorMessage(GetLastError));


 - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - -
this is just some code to give you something else to try, I could not test it, but it may or may not help
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9717003
And if the compile process is less than 500 mseconds then you do NOT need any prgress bar, but you will need to get the line number where any compile error was if the compile is not successful
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9718541
Crikey!

Doesn't run - too many end else's - it's like unravelling a huge knot! :)

I'll work on it thanks!

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9718741
OK, I eventually sorted out that last section of code and got it to run, but it doesn't work either. Curiously, the last line (ShowMessage(SysErrorMessage(GetLastError));) pops up a message saying 'Operation Completed Successfully', but my edit boxes remain unaltered.

What's more, it gives me an external exception error if I run it at the same time as the exe monitor program.

My last posted procedure seems to be closer as it at least works while the monitor exe program is running - I've just got to figure out what's missing from my code that's present in the C++ monitor program code.

I'll experiment and if I can figure it out, I'll award you the points for all your help so far.

If anyone else can help, I'll split the points.

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9719523
I have posted this before,it is the only code (beside the WM_USER message code) the has anything to do with getting a mem map file while runing



while(TRUE)
 {
  if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))  // in a delphi program you do not have acceess to the GetMessage of the application
  {
   if(msg.message!=WM_QUIT) // this just kills the loop if there is a WM_QUIT message
   {
    TranslateMessage(&msg); // gets keyboard to WM_CHAR message
    DispatchMessage(&msg);  // get all messages to the correct window
   }
   else
    break;
  }
  else
  {
   //  you have tried this Code below and did not get the map file handle
   HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ,FALSE,"DBPROEDITORMESSAGE");
   if ( hFileMap )
   {
    LPVOID lpVoid = MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256); // get the pointer for map file memory
    if ( lpVoid )
    {
     wsprintf(pProgressString, "Value:%d  String:%s", *(DWORD*)lpVoid, (LPSTR)lpVoid+4 ); // this formats the DWORD and Text into a PChar
     InvalidateRect(hWnd, NULL, TRUE); // just refreshs the whole window
     UnmapViewOfFile(lpVoid);
    }
    CloseHandle(hFileMap);
   }

   // Processor Friendly
   Sleep(100); // waits 100 mseconds before checking for the map file again
  }
 }

so I do NOT see any thing in there that would affect the code to get it to work, that we have not tried

- - - - - - - - - - -
if I was using a Mem mapped file, I would never have it get the map file and release it 100 times a second, I would get the map file handle ONCE and the Pointer ONCE and then read the map file 10 times a second and the release the pointer ONCE and Close the handle ONCE


 if ShellExecuteEx(@SEInfo) then
        begin
{place your hFileMap := CreateFileMapping, here BEFORE the repeat loop
hFileMap := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,1024,FileMapName);
do a test to see if it allready exists, and if it does then get the pointer
 PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);}
          Repeat
          { put your test here for PEmessage
          if PEMessage <> nil then
           and if it exists, then DO NOT CREATE IT AGAIN, if it does not exist then try and create it JUST ONCE}
         
          Result := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,1024,FileMapName);
          if Result <> 0 then // A valid handle was returned so check GetLastError
            Begin
              if GetLastError = ERROR_ALREADY_EXISTS then // Mapped file was already there
                begin
                  CloseHandle(Result); // So we close new one and open existing mapped file
                  hFileMap := OpenFileMapping(FILE_MAP_READ,False,FileMapName);
                  try  // remove the try and finally
                    PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
                    if PEMessage <> nil then  // The message must have been received!
                      Begin
                      {the next two lines are the ONLY two you will need to do in every repeat loop}
                        RetValEdit.Text := 'Line: '+IntToStr(PEMessage.Line); // Line Number edit box
                        RetStrEdit.Text := 'Message: '+PEMessage.Text;        // Message edit box
                      End;
                  finally
      {move the UnmapViewofFile and CloseHandle untill AFTER the loop if finished}
                    UnmapViewOfFile(PEMessage);
                    CloseHandle(hFileMap); // Possibly not required here??
                  end;
                end;
            End;
            Application.ProcessMessages;  // do may try and comment out the Processmessages, to see if it makes any difference
            GetExitCodeProcess(SEInfo.hProcess, ExitCode);
          until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
          ShowMessage('Program Compiled');  // Shown on compilation end
        end
      else
        ShowMessage('Error Starting Compiler!');
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9743434
An update (hopefully the last before I award the 500 points):

I've tracked down what the problem is - but I'm not sure how to go about solving it.

I've been sent a modified exe version of the monitor program which writes to the mapped file. So, I created a small seperate test program and took the following code out of my main program and put it in a timer function:

  hFileMap:= OpenFileMapping(FILE_MAP_READ,False,'DBPROEDITORMESSAGE');
  If hFileMap<>0 Then
    Begin
      PEMessage := MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,256);
      Edit1.Text:=IntToStr(PEMessage.Line);
      Edit2.Text:=PEMessage.Text;
      UnmapViewOfFile(PEMessage);
      CloseHandle(hFileMap);
    End;

All the other lines don't seem to be necessary because when the new version of his monitor program is running, my test program displays the value and message correctly - with only the above lines of code. I don't actually need all the tests because I'm only accessing the mapped file when the compiler is running and I *know* that the data is there.

If I stop his monitor program from running and leave mine running while I compile with my IDE, then nothing works again. Something is missing from my program and I now know what it is...

I've been informed that the compiler is specifically looking for an application with the class name of TDBPROEDITOR.  It will only create and send data if such an application window exists to send data to. I reckon that this is the part in the C++ code which says:

 // Register window
 wc.style = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = WindowProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = NULL;
 wc.hCursor = NULL;
 wc.hbrBackground = NULL;
 wc.lpszMenuName = NULL;
 wc.lpszClassName = "TDBPROEDITOR";
 RegisterClass( &wc );

 HWND hWnd = CreateWindow("TDBPROEDITOR",
                    "DBPro Editor",
                    WS_OVERLAPPEDWINDOW,
                    0,0,1024,28+22,
                    NULL,
                    NULL,
                    hInstance,
                    NULL);

ShowWindow(hWnd, SW_SHOW);

To finally put an end to this epic, how do I set the classname of my existing app to TDBPROEDITOR or at least fool the compiler into thinking that such a thing exists so it will transmit data? As usual, I don't want to write a separate API program - just add the code to my existing application.

TDK_Man
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 500 total points
ID: 9745340
???
I'm very puzzled by the need to send data to a window with a certain class name, but like I have said many times, I got very little information to go on. . . and I know you have said all you know about it. . . . Just frustrated  LOL

Unlike the simple program code that you got and posted for your example, Delphi uses a really different way of doing things, There is the TApplication, which is the acuall "Program" running, and then there are it's children, the "Forms". . . I will just guess that if your "Form" window has a class name, then it might work. . .

In your Main Form code add a Protected section to the "Private" and 'Public' sections, and Place a CreateParams in it like this - - -


  private
  { Private declarations }
    aStr: String;
  protected
  { Protected declarations }
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
  end;

 - - - - - - -
and then add this procedure to you code


procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.WinClassName := 'TDBPROEDITOR';
end;

- - - - - - - -  - -

this will change the Class name of your Form, I do not think you have access to the TApplication Class name ,  and as far as I know you can NOT change a Class Name once it has been registered with the system

I have changed alot of forms class name with the code above, I have not ever tried to change an TApplication class name before, if the code above does not get it, then I will see if I can access the TApplication calss name
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9745348
the
aStr: String;

is useless, not nessary
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9749944
Is there a web page for information about this compilier and it's prgramming uses and parameters?
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9750015
All I can say is THANK YOU!!!!

That worked a treat - even with only the few lines of openfilemapping code I posted above.

Sorry about the seemingly vague information, but it really was all I had. Apparently, all the required information *was* in the C++ code - like the requirement to register a class name, I just didn't understand the code to figure it out myself.

However, this exercise has taught me all about mapped files - a subject I knew nothing about before, so many, many thanks for putting up with me! :)

TDK_Man
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9750373
"Is there a web page for information about this compilier and it's prgramming uses and parameters?"

No sorry - I'm writing a replacement IDE for it because the one supplied is not MDI. (I wanted to be able to open more than one source window so I could copy & paste from one to the other). The company who produce it have not deliberately made it difficult to do what I've been trying to do - it's just that they never envisaged users writing their own IDE's for it.

What info I have got, I've had to prise out of the author. :)

TDK_Man
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9752944
I can see now why your code was not finding the Mem Mapped file, it appears that the compilier looks for a Class name and does not set the mem mapped file if the class name does not exist. . .

and if you can use this code

if  ShellExecuteEx(@ShExInfo) then
  begin
  while WaitForSingleObject(ShExInfo.hProcess, 100) <> WAIT_OBJECT_0 do

instead of your
Repeat loop, if you have to use your repeat loop at least put a
Sleep( 50);  
or
Sleep(100);

 in it, otherwize it will eat up your processor cylcles with out doing any thing
0
 
LVL 33

Expert Comment

by:Slick812
ID: 9752958
Oh, and if youy get a chance, try and go to my site about API programming and learn something about HOW the windows API works, it will help you in programming so much you will not beleive it
0
 
LVL 1

Author Comment

by:tdk_man
ID: 9752975
Will do!

I have it bookmarked... :)

TDK_Man
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Simple Delphi Question 9 77
Printing problem 2 73
HTML text in the body of an email (delphi code) 12 75
LAN or WAN ? 11 66
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
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…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

747 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now