systan
asked on
How to perfect this code
This is part of my personal project, I wanna perfect the code, but I can't.
I wanna open any executable file's, but before launching the executable application, I want my application to give the approval if the application is going to be launched or not.
Here's the complete code, and the attached file, and the image structure of what my application is doing.
I wanna open any executable file's, but before launching the executable application, I want my application to give the approval if the application is going to be launched or not.
Here's the complete code, and the attached file, and the image structure of what my application is doing.
//begin DPR
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
FPipes in 'FPipes.pas';
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
//end DPR
//begin UNIT1
unit Unit1;
interface
uses Fpipes,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button2: TButton;
Button1: TButton;
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
FServer: TPipeServer;
procedure OnPipeData(Sender: TObject; aData: String; var aRespond: String);
public
{ Public declarations }
end;
var
Form1: TForm1;
//HookMsg: cardinal;
function SetHook(): Boolean; stdcall; external 'MatHook.dll';
function RemoveHook(): Boolean; stdcall; external 'MatHook.dll';
implementation
{$R *.dfm}
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Form1.Text := aData;
//showmessage(aData);
//respond //test only
aRespond := '0';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if (not RemoveHook) then ShowMessage('Couldn''t stop Hook');
FServer.Free;
Form1.Text := '';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
if (not SetHook) then ShowMessage('Couldn''t start Hook');
FServer := TPipeServer.CreatePipeServer('', 'TwinSoft', True);
FServer.OnData := OnPipeData;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if (not RemoveHook) then ShowMessage('Couldn''t stop Hook');
FServer.Free;
Form1.Text := '';
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if (not SetHook) then ShowMessage('Couldn''t start Hook');
FServer := TPipeServer.CreatePipeServer('', 'TwinSoft', True);
FServer.OnData := OnPipeData;
end;
//initialization
//HookMsg := RegisterWindowMessage('myhookdll_hookmsg');
end.
//end UNIT1
//begin unit FPIPES
unit FPipes;
interface
uses
Classes, Windows;
const
cShutDownMsg = 'shutdown';
cPipeFormat = '\\%s\pipe\%s';
type
RPIPEMessage = record
Size: DWORD;
Kind: Byte;
Count: DWORD;
Data: array[0..8095] of Char;
end;
TOnDataEvent = procedure(Sender: TObject; aData: String; var aRespond: String) of Object;
TPipeServer = class(TThread)
private
FHandle: THandle;
FPipeName: string;
FOnData: TOnDataEvent;
protected
public
constructor CreatePipeServer(aServer, aPipe: string; StartServer: Boolean);
destructor Destroy; override;
procedure StartUpServer;
procedure ShutDownServer;
procedure Execute; override;
property OnData: TOnDataEvent read FOnData write FOnData;
end;
TPipeClient = class
private
FPipeName: string;
function ProcessMsg(aMsg: RPIPEMessage): RPIPEMessage;
protected
public
constructor Create(aServer, aPipe: string);
function SendString(aStr: string): string;
end;
implementation
uses
SysUtils;
procedure CalcMsgSize(var Msg: RPIPEMessage);
begin
Msg.Size := SizeOf(Msg.Size) +
SizeOf(Msg.Kind) +
SizeOf(Msg.Count) +
Msg.Count + 3;
end;
{ TPipeServer }
constructor TPipeServer.CreatePipeServer(aServer, aPipe: string; StartServer: Boolean);
begin
if aServer = '' then
FPipeName := Format(cPipeFormat, ['.', aPipe])
else
FPipeName := Format(cPipeFormat, [aServer, aPipe]);
FHandle := INVALID_HANDLE_VALUE;
if StartServer then
StartUpServer;
Create(not StartServer);
end;
destructor TPipeServer.Destroy;
begin
if FHandle <> INVALID_HANDLE_VALUE then
ShutDownServer;
inherited Destroy;
end;
procedure TPipeServer.Execute;
var
i, w: Cardinal;
InMsg,
OutMsg: RPIPEMessage;
s, r: String;
begin
while not Terminated do
begin
if (FHandle = INVALID_HANDLE_VALUE) then
Sleep(250)
else
if ConnectNamedPipe(FHandle, nil) then
try
InMsg.Size := SizeOf(InMsg);
ReadFile(FHandle, InMsg, InMsg.Size, InMsg.Size, nil);
if not Terminated and Assigned(FOnData) then
begin
s := '';
for i := 0 to Pred(InMsg.Count) do
s := s + InMsg.Data[i];
FOnData(Self, s, r);
OutMsg.Kind := 0;
OutMsg.Count := Length(r);
StrPCopy(OutMsg.Data, r);
CalcMsgSize(OutMsg);
WriteFile(FHandle, OutMsg, OutMsg.Size, w, nil);
end;
finally
DisconnectNamedPipe(FHandle);
end;
end;
end;
procedure TPipeServer.ShutDownServer;
var
InMsg,
OutMsg: RPIPEMessage;
BytesRead: Cardinal;
begin
if FHandle <> INVALID_HANDLE_VALUE then
begin
Terminate;
OutMsg.Size := SizeOf(OutMsg);
with InMsg do
begin
Kind := 0;
Count := Length(cShutDownMsg);
StrPCopy(Data, cShutDownMsg);
end;
CalcMsgSize(InMsg);
CallNamedPipe(PChar(FPipeName), @InMsg, InMsg.Size, @OutMsg, OutMsg.Size, BytesRead, 100);
CloseHandle(FHandle);
FHandle := INVALID_HANDLE_VALUE;
end;
end;
procedure TPipeServer.StartUpServer;
begin
if WaitNamedPipe(PChar(FPipeName), 100 {ms}) then
raise Exception.Create('Requested PIPE exists already.');
FHandle := CreateNamedPipe(PChar(FPipeName), PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, SizeOf(RPIPEMessage), SizeOf(RPIPEMessage),
NMPWAIT_USE_DEFAULT_WAIT, nil);
if FHandle = INVALID_HANDLE_VALUE then
raise Exception.Create('Could not create PIPE.');
end;
{ TPipeClient }
constructor TPipeClient.Create(aServer, aPipe: string);
begin
inherited Create;
if aServer = '' then
FPipeName := Format(cPipeFormat, ['.', aPipe])
else
FPipeName := Format(cPipeFormat, [aServer, aPipe]);
end;
function TPipeClient.ProcessMsg(aMsg: RPIPEMessage): RPIPEMessage;
begin
CalcMsgSize(aMsg);
Result.Size := SizeOf(Result);
if WaitNamedPipe(PChar(FPipeName), 10) then
if not CallNamedPipe(PChar(FPipeName), @aMsg, aMsg.Size, @Result, Result.Size, Result.Size, 500) then
raise Exception.Create('PIPE did not respond.')
else
else
raise Exception.Create('PIPE does not exist.');
end;
function TPipeClient.SendString(aStr: string): string;
var
Msg: RPIPEMessage;
begin
Msg.Kind := 1;
Msg.Count := Length(aStr);
StrPCopy(Msg.Data, aStr);
Msg := ProcessMsg(Msg);
Result := Copy(Msg.Data, 1, Msg.Count);
end;
end.
//end unit FPIPES
//begin DLL
library MatHook;
uses
Windows,
Messages,
Fpipes;
type
THookRec = record
hMatHook: HHOOK;
hMatWnd: HWND;
oldProc: Integer;
end;
var
map: DWord;
buf: ^THookRec;
// new window proc - runs in context of target process
function MatWndProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LongInt; stdcall;
var aResult:string;
begin
try
case Msg of
WM_CREATE:
begin
//MessageBox(0, GetCommandLine, 'Command Line parameter(s)', MB_OK);
with TPipeClient.Create('', 'TwinSoft') do
try
aResult := SendString(GetCommandLine);
finally
Free;
end;
if aResult = '1' then
begin
Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
MessageBox(0, GetCommandLine, 'THIS WILL CONTINUE LAUNCHING', MB_OK);
end
else
begin
result := 1;
MessageBox(0, GetCommandLine, 'THIS WILL NOT CONTINUE TO OPEN', MB_OK);
end;
end;
// user definied message to stop subclassing
// (RegisterWindowMessage would be a better choice instead of WM_USER message!)
WM_USER + 1:
begin
MessageBox(0, 'GetCommandLine', 'USER', MB_OK);
// delete custom menu entries (quick'n'dirty)
SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, buf^.oldProc);
end;
end;
Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
//Result := DefWindowProc(hWnd,Msg,wParam,lParam);
except
Result := 0;
end;
//result := DefWindowProc(Handle,Msg,wP,lP);
end;
// hook proc - waits for target window to be created
function MatHookProc(nCode: Integer; wp: wParam; lp: lParam): LongInt; stdcall;
var
hTemp: hWnd;
szClass: array[0..255] of Char;
begin
try
if (nCode >= HC_ACTION) then
begin
Case nCode of
HCBT_CREATEWND:
begin
if EnumThreadWindows(GetCurrentThreadId, @hTemp, 0) then
begin
hTemp := HWND(wp);
FillChar(szClass, SizeOf(szClass), 0);
ZeroMemory(@szClass, SizeOf(szClass));
GetWindowText(hTemp, szClass, SizeOf(szClass));
GetClassName(hTemp, szClass, SizeOf(szClass));
buf^.hMatWnd := htemp;
buf^.oldProc := GetWindowLong(buf^.hMatWnd, GWL_WNDPROC);
SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, Integer(@MatWndProc));
end;
end;
HCBT_DESTROYWND:
begin
{//useless code
hTemp := HWND(wp);
FillChar(szClass, 256, 0);
GetClassName(hTemp, szClass, 256);
if (szClass = 'Notepad') then
}
SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, buf^.OldProc);
end;
end;
end;
Result := CallNextHookEx(buf^.hMatHook, nCode, wp, lp);
except
Result := 0;
end;
end;
// sets up hook
function SetHook: Boolean; stdcall; export;
begin
try
Result := false;
if (not assigned(buf)) then
begin
map := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(THookRec), 'HookRecMemBlock');
buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
buf^.hMatHook := SetWindowsHookEx(WH_CBT, @MatHookProc, hInstance, 0);
Result := true;
end;
except
Result := false;
end;
end;
// removes hook
function RemoveHook: Boolean; stdcall; export;
begin
Result := false;
if (assigned(buf)) then
begin
// tell our new wnd proc to stop subclassing
// (has to be done in context of target process)
SendMessage(buf^.hMatWnd, wm_User + 1, 1, 0);
if (buf^.hMatHook <> 0) then UnhookWindowsHookEx(buf^.hMatHook);
buf^.hMatHook := 0;
UnmapViewOfFile(buf);
buf := nil;
Result := true;
end;
end;
// DLL entry point
procedure DllEntry(dwReason: DWord);
begin
Case dwReason of
DLL_PROCESS_ATTACH:
begin
if (not assigned(buf)) then
begin
map := OpenFileMapping(FILE_MAP_ALL_ACCESS, false, 'HookRecMemBlock');
buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
CloseHandle(map);
map := 0;
end;
end;
DLL_PROCESS_DETACH:
begin
UnmapViewOfFile(buf);
buf := nil;
end;
end;
end;
exports
SetHook,
RemoveHook;
// main
begin
DisableThreadLibraryCalls(hInstance);
DllProc := @DLLEntry;
DllEntry(DLL_PROCESS_ATTACH);
end.
//end DLL
ASKER
the image structure of what my application is doing.
eqimage2.JPG
eqimage2.JPG
perfect code ?
* by renaming units/projects/components with a relevant name
* indenting code
* adding comments to the code
* don't use form1 inside TForm1 (alternative = self.)
* by renaming units/projects/components with a relevant name
* indenting code
* adding comments to the code
* don't use form1 inside TForm1 (alternative = self.)
guess it is correct!
ASKER
Geert;
I'm not sure about the point of your comment, I doubt.
I'm just asking if someone could check the code or edit the code to make it run better.
I've test it, and it run's Ok, but when I open other some applications, it will hang my application.
eq.;
calc.exe - when openning this, no problem
dotnetapp.exe - when openning it delays to open
somedelphiapp - when opened is Ok
some other application's cause error, explorer error.
I'm not sure about the point of your comment, I doubt.
I'm just asking if someone could check the code or edit the code to make it run better.
I've test it, and it run's Ok, but when I open other some applications, it will hang my application.
eq.;
calc.exe - when openning this, no problem
dotnetapp.exe - when openning it delays to open
somedelphiapp - when opened is Ok
some other application's cause error, explorer error.
ASKER
@abilash94;
Welcome to experts-exchange, your e-e birth is today.
Welcome to experts-exchange, your e-e birth is today.
ow sorry, i thought you wanted recommendations about the code formatting too
i would change the use of Form1
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Form1.Text := aData;
>>change to
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Self.Text := aData;
it will avoid any needless actions when renaming TForm1 to TfrmAppStartResponse
I would change some things (like (very meaningfull names)
figuring out button2 is for stop and button1 is for start, face it, it's just wasting time isn't it ?
you are programming in delphi which is top-down logic
and you aren't following that all the way
type
TForm1 = class(TForm)
...
private
procedure OnPipeData(Sender: TObject; aData: String; var aRespond: String);
protected
procedure StartPipe; virtual;
procedure StopPipe; virtual;
end;
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Self.Text := Copy(aData, 1, 100); // don't let it get too long
//showmessage(aData);
//respond //test only
aRespond := '0';
end;
procedure TForm1.btnStopPipeClick(Se nder: TObject);
begin
StopPipe;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StartPipe;
end;
procedure TForm1.FormCloseQuery(Send er: TObject; var CanClose: Boolean);
begin
StopPipe;
CanClose := True;
end;
procedure TForm1.btnStartPipe(Sender : TObject);
begin
StartPipe;
end;
procedure TForm1.StartPipe;
begin
if not Assigned(fServer) then
begin
if SetHook then
begin
FServer := TPipeServer.CreatePipeServ er('', 'TwinSoft', True);
FServer.OnData := OnPipeData;
end;
end;
end;
procedure TForm1.StopPipe;
begin
if Assigned(fServer) then
RemoveHook;
FreeAndNil(fServer);
end;
i would change the use of Form1
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Form1.Text := aData;
>>change to
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Self.Text := aData;
it will avoid any needless actions when renaming TForm1 to TfrmAppStartResponse
I would change some things (like (very meaningfull names)
figuring out button2 is for stop and button1 is for start, face it, it's just wasting time isn't it ?
you are programming in delphi which is top-down logic
and you aren't following that all the way
type
TForm1 = class(TForm)
...
private
procedure OnPipeData(Sender: TObject; aData: String; var aRespond: String);
protected
procedure StartPipe; virtual;
procedure StopPipe; virtual;
end;
procedure TForm1.OnPipeData(Sender: TObject; aData: String; var aRespond: String);
begin
Self.Text := Copy(aData, 1, 100); // don't let it get too long
//showmessage(aData);
//respond //test only
aRespond := '0';
end;
procedure TForm1.btnStopPipeClick(Se
begin
StopPipe;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StartPipe;
end;
procedure TForm1.FormCloseQuery(Send
begin
StopPipe;
CanClose := True;
end;
procedure TForm1.btnStartPipe(Sender
begin
StartPipe;
end;
procedure TForm1.StartPipe;
begin
if not Assigned(fServer) then
begin
if SetHook then
begin
FServer := TPipeServer.CreatePipeServ
FServer.OnData := OnPipeData;
end;
end;
end;
procedure TForm1.StopPipe;
begin
if Assigned(fServer) then
RemoveHook;
FreeAndNil(fServer);
end;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Geert;
I will gladly change some of code by your recommendations on FPipes and to the Unit1 Pas.
But the realy problem of the code is when I openned an application. (other application)
Like openning an application from any .net compiled application.
Like openning My Documents, My Computer, it errors and hangs up the computer in a minute.
Like openning some applications and delays long or does not continue to open.
That's the hardiest part.
I think the problem is on the DLL part.
Here's the part of the code snippet that actually do the approval if the application will be openned or not;
I will gladly change some of code by your recommendations on FPipes and to the Unit1 Pas.
But the realy problem of the code is when I openned an application. (other application)
Like openning an application from any .net compiled application.
Like openning My Documents, My Computer, it errors and hangs up the computer in a minute.
Like openning some applications and delays long or does not continue to open.
That's the hardiest part.
I think the problem is on the DLL part.
Here's the part of the code snippet that actually do the approval if the application will be openned or not;
// new window proc - runs in context of target process
function MatWndProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LongInt; stdcall;
var aResult:string;
begin
try
case Msg of
WM_CREATE:
begin
//MessageBox(0, GetCommandLine, 'Command Line parameter(s)', MB_OK);
with TPipeClient.Create('', 'TwinSoft') do
try
aResult := SendString(GetCommandLine);
finally
Free;
end;
//I THINK the problem is here or down or the whole
if aResult = '1' then
begin
Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
MessageBox(0, GetCommandLine, 'THIS WILL CONTINUE LAUNCHING', MB_OK);
end
else
begin
result := 1;
MessageBox(0, GetCommandLine, 'THIS WILL NOT CONTINUE TO OPEN', MB_OK);
end;
end;
// user definied message to stop subclassing
// (RegisterWindowMessage would be a better choice instead of WM_USER message!)
WM_USER + 1:
begin
MessageBox(0, 'GetCommandLine', 'USER', MB_OK);
// delete custom menu entries (quick'n'dirty)
SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, buf^.oldProc);
end;
end;
Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
//Result := DefWindowProc(hWnd,Msg,wParam,lParam);
except
Result := 0;
end;
//result := DefWindowProc(Handle,Msg,wP,lP);
end;
ASKER
It's sad to say that I asked this question many times here in experts-exchange.
https://www.experts-exchange.com/questions/25616319/For-Mahdi78-and-Twinsoft-Changing-messages-from-delphi-DLL-to-delphi-Form-Vice-Versa.html
https://www.experts-exchange.com/questions/20798061/Detecting-application-launches.html
But, no one could perfect the code, and I can't, it's too hard to think whats the next line to write.
Anyway, I have to wait for the code saviour, if there is? there is one, but I don't know why didn't comment.
Hmp, all experts-exchange active member are code saviour's, sharing idea's and accept's a warm points, infact even it's midnight to dawn they are not tired to help.
https://www.experts-exchange.com/questions/25616319/For-Mahdi78-and-Twinsoft-Changing-messages-from-delphi-DLL-to-delphi-Form-Vice-Versa.html
https://www.experts-exchange.com/questions/20798061/Detecting-application-launches.html
But, no one could perfect the code, and I can't, it's too hard to think whats the next line to write.
Anyway, I have to wait for the code saviour, if there is? there is one, but I don't know why didn't comment.
Hmp, all experts-exchange active member are code saviour's, sharing idea's and accept's a warm points, infact even it's midnight to dawn they are not tired to help.
?midnight to dawn?
depends where you sit, remember ...site is worldwide
your midnight, could be my afternoon
have you tried with a fixed yes or no
--> no user interaction with messageboxes
just a plain if notepad.exe then 0 else 1
test that logic first with .net
if that don't work, you may have to post in matthias's forum to get help
depends where you sit, remember ...site is worldwide
your midnight, could be my afternoon
have you tried with a fixed yes or no
--> no user interaction with messageboxes
just a plain if notepad.exe then 0 else 1
test that logic first with .net
if that don't work, you may have to post in matthias's forum to get help
ASKER
Thank you for the reply;
Yes, site is worldwide
I've tried removing the messageboxes.
just a plain notepad.exe is Ok to run, but others don't
In .Net applications, yes it run's but some other .net apps also does not show.
Oh, test in .net, I'm not sure with the code
Ok, where is matthia's forum? can you post the link, please.
Yes, site is worldwide
I've tried removing the messageboxes.
just a plain notepad.exe is Ok to run, but others don't
In .Net applications, yes it run's but some other .net apps also does not show.
Oh, test in .net, I'm not sure with the code
Ok, where is matthia's forum? can you post the link, please.
just look on madshi's profile
currently overal top N°7 in Delphi
currently overal top N°7 in Delphi
ASKER
Thanks, I'll try to look for that;
I'm wodering if "WaitForSingleObject" can be applied for that application
I'm wodering if "WaitForSingleObject" can be applied for that application
ASKER
I Think no one is listening aside from Geert;
ASKER
I don't believe this; all are listening...
ASKER
I guess I have to open this question again soon
Thanks Geert; for some tweaks
Thanks Geert; for some tweaks
ASKER
file.zip