wqclatre
asked on
Is there a way to solve this problem.
I making a program that use a com object (I create it remote) to do some stuff.. I have no control over this comobject so I can not modify it.
When I send my call to the com-object I just return a value (Tru) That means that it has started to process my request. That's all that I get back from the com-object.
When the comobject is finnished it writes a file on the disk on the server that the comobject is installed. This file has the name "time when job is completed.txt" contains a id number that I need to get back to my client software that I create. Does anoyne have any idea of a way to solve this. I was thinking of creating another comobject on the server that I can call but I can't see any way to match my first request with the file that is generated. (if 2 clients sends different requests that takes different time to complete there is impossible to se on the file name which one that contains the number I need"
Does anyone have any good idea how to solve this=?
When I send my call to the com-object I just return a value (Tru) That means that it has started to process my request. That's all that I get back from the com-object.
When the comobject is finnished it writes a file on the disk on the server that the comobject is installed. This file has the name "time when job is completed.txt" contains a id number that I need to get back to my client software that I create. Does anoyne have any idea of a way to solve this. I was thinking of creating another comobject on the server that I can call but I can't see any way to match my first request with the file that is generated. (if 2 clients sends different requests that takes different time to complete there is impossible to se on the file name which one that contains the number I need"
Does anyone have any good idea how to solve this=?
hello wgclatre, it seems from your description that this "com-object" would be very easy to get mixed up with which request the created file is for. . . . I've used the API WaitForMultipleObjects( ) in a sepatate thread, to monitor a folder for the creation (or modification) of a file. When the file is created my app is notified and I can do something with the file, like move it or rename it or get info from it. Is this something that would help you? I'll post some code if it is. I'm not to clear on what your problem is. . . Except you should use another com object that works better.
ASKER
Slick812 Your code might help me out I guess.
What do I know to check when this file is created? Do I have to know the filename or can it tell me when a new file is created in this folder? (with any name)
Use another com object is not possible. THis com object is done by a company that seems to always mess things up. (and their software costs awful lot of money.) Unfortanly I'm stucked to use it because I don't know what happens behind. (I guess this com object is just a fontend to 496 other com objects that is installed together with this... )
What do I know to check when this file is created? Do I have to know the filename or can it tell me when a new file is created in this folder? (with any name)
Use another com object is not possible. THis com object is done by a company that seems to always mess things up. (and their software costs awful lot of money.) Unfortanly I'm stucked to use it because I don't know what happens behind. (I guess this com object is just a fontend to 496 other com objects that is installed together with this... )
this code uses an API FindFirstChangeNotificatio n( ) function to have the windows system monitor a Folder for any file name changes using the FILE_NOTIFY_CHANGE_FILE_NA ME flag. Using this flag will monitor the Folder for any filename change and cause a WaitForMultipleObjects( ) to return. Changes include renaming, creating, or deleting a filename. You can monitor other changes with different flags like FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WR ITE. The WaitForMultipleObjects( ) freezes the thread it's in, so another thread is created to monitor the folder.
This form has 2 buttons and a TLabel, label5.
private
{ Private declarations }
procedure GetFirstLine(FileName: String);
var
Form1: TForm1;
hThrd: THandle;
HndAry1: Array[0..2] of Cardinal;
DirPath: String;
procedure TForm1.GetFirstLine(FileNa me: String);
var
File1: TextFile;
Line1: String;
begin
{this is a procedure to use the new file
remember that this is run in another thread and is
NOT syncronized with your main thread}
AssignFile(File1, FileName);
Reset(File1);
Readln(File1, Line1);
CloseFile(File1);
{do something here with the file}
{This Code is in a different thread than your main form
if you want to notifiy the main forms thread to do something
then you could use
SendMessage(Form1.Handle, WM_USER+432,0,0); and start the code
when it get's that message}
end;
function ThrdFunc(Parameter: Pointer): Integer; stdcall;
var
Return1: Cardinal;
AryNum: Integer;
begin
{this is the new Thread's function where you do anything
that you want to happen in this thread}
Result := 0;
{Result isn't used here}
try
HndAry1[0] := CreateEvent(nil, false, false, nil);
{you need to create an Event so you can easily Exit this thread,
the Thread is in a wait state so you need an Event to Activate the thread
from the Wait state of WaitForMultipleObjects, CloseHandle(hThrd)
will not end the thread in a wait state}
HndAry1[1] := FindFirstChangeNotificatio n(PChar(Di rPath), False, FILE_NOTIFY_CHANGE_FILE_NA ME);
{FindFirstChangeNotificati on with the FILE_NOTIFY_CHANGE_FILE_NA ME prameter will
monitor the file names in the specified Folder, you need to give the Handle returned to
the WaitForMultipleObjects( ) in the HndAry1 Array}
if (HndAry1[0] < 2) or (HndAry1[1] < 2) then
begin
MessageBox(Form1.Handle, 'FindFirst Change Notification Failed, could not monitor Folder',
'Change Notification Failed', MB_OK or MB_ICONERROR);
Exit;
{Exit will allow the finally section to execute and End this thread}
end;
Form1.Label5.Caption := 'Thread is RUNNING';
{I added this label just to let you know when the thread is running}
while true do
begin // a
Return1 := WaitForMultipleObjects(2, @HndAry1, False, INFINITE);
{WaitForMultipleObjects suspendes (freezes) this thread until it gets an Object
Handle event then it will resume the thread}
if Return1 = WAIT_FAILED then
begin // 1
MessageBox(Form1.Handle, 'WaitForMultipleObjects Failed, stopped monitoring Folder',
'Wait Failed', MB_OK or MB_ICONERROR);
{Break will stop the while loop and the finally section will execute to
end this thread}
Break;
end; // 1
AryNum := Return1 - WAIT_OBJECT_0;
{the Return1 - WAIT_OBJECT_0 value is the index number of the AryHandle Array
which fired the WaitForMultipleObjects( ) to resume the thread}
if AryNum = 0 then
begin // 3
{the AryNum = 0 means that the "Event" has been Set,
which is only used to End this thread}
Break;
end; // 3
if AryNum = 1 then
begin // 4
{test for the file name you want to monitor with If FileExists.
you can do other tests like for changes in existing file names}
If FileExists(DirPath+'\File to watch For.txt') then
begin
{add code here to get info from the new file and use that info}
Form1.GetFirstLine(DirPath +'\File to watch For.txt');
MessageBox(Form1.Handle, PChar('The File "File to watch For.txt" Has Been Created in '+ DirPath),
'NEW FILE in folder', MB_OK or MB_ICONERROR);
Break;
end;
{if the file does not exist, then the FindNextChangeNotification is called}
end; // 4
{the FindNextChangeNotification starts the folder monitoring again}
if not FindNextChangeNotification (HndAry1[1 ]) then
begin
MessageBox(Form1.Handle, 'Find Next Change Notification Failed, stopped monitoring Folder',
'Next Change Notification Failed', MB_OK or MB_ICONERROR);
Break;
end;
end; // a
finally
{MAKE SURE you close all the handles}
CloseHandle(AryHandle[0]);
FindCloseChangeNotificatio n(AryHandl e[1]);
CloseHandle(AryHandle[1]);
Form1.Label5.Caption := 'NO Thread';
EndThread(Result);
end;
end;
procedure TForm1.button_GetAddFileCl ick(Sender : TObject);
var
ThreadID: Cardinal;
begin
DirPath := 'C:\Stuff';
{put the Folder Path that you want to monitor for the
text file in DirPath variable}
SetEvent(HndAry1[0]);
{SetEvent(HndAry1[0]); is used to end the thread see the ThrdFunc for
"if AryNum = 0 then" which Exits the Thread}
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, INFINITE,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, INFINITE);
CloseHandle(hThrd);
{the lines above make sure the thread is Dead, but you could disable this
button and not have them}
hThrd := BeginThread(nil, 0, @ThrdFunc, nil, 0, ThreadId);
{start a New Thread with BeginThread. All the Wait functions like
WaitForMultipleObjects suspend the Thread until it gets an Event}
if hThrd > 0 then
begin
//SetThreadPriority(hThrd, THREAD_PRIORITY_BELOW_NORM AL);
sbut_EndFileAdd.Enabled := True;
end else
Memo1.Text := 'Could not Create Thread';
end;
procedure TForm1.button_EndFileAddCl ick(Sender : TObject);
var
Msg1: TMsg;
begin
if hThrd = 0 then Exit;
SetEvent(HndAry1[0]);
{using SetEvent will cause the event to fire and the new thread
to drop out of it's wait state and end the thread. Since its in
another thread, you need to wait for that thread to end before you
set the hThrd to 0. }
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, INFINITE,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, INFINITE);
CloseHandle(hThrd);
hThrd := 0;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
Msg1: TMsg;
begin
{make sure you close the handles before you exit the program to
avoid memory leaks}
if hThrd > 0 then
begin
SetEvent(HndAry1[0]);
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, 600,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, 600);
CloseHandle(hThrd);
end;
end;
- - - - - - - - - - - - - - - - - - - - - - - - - - -
if you haven't used threads much this may seem less than easy, ask questions if you need more info
This form has 2 buttons and a TLabel, label5.
private
{ Private declarations }
procedure GetFirstLine(FileName: String);
var
Form1: TForm1;
hThrd: THandle;
HndAry1: Array[0..2] of Cardinal;
DirPath: String;
procedure TForm1.GetFirstLine(FileNa
var
File1: TextFile;
Line1: String;
begin
{this is a procedure to use the new file
remember that this is run in another thread and is
NOT syncronized with your main thread}
AssignFile(File1, FileName);
Reset(File1);
Readln(File1, Line1);
CloseFile(File1);
{do something here with the file}
{This Code is in a different thread than your main form
if you want to notifiy the main forms thread to do something
then you could use
SendMessage(Form1.Handle, WM_USER+432,0,0); and start the code
when it get's that message}
end;
function ThrdFunc(Parameter: Pointer): Integer; stdcall;
var
Return1: Cardinal;
AryNum: Integer;
begin
{this is the new Thread's function where you do anything
that you want to happen in this thread}
Result := 0;
{Result isn't used here}
try
HndAry1[0] := CreateEvent(nil, false, false, nil);
{you need to create an Event so you can easily Exit this thread,
the Thread is in a wait state so you need an Event to Activate the thread
from the Wait state of WaitForMultipleObjects, CloseHandle(hThrd)
will not end the thread in a wait state}
HndAry1[1] := FindFirstChangeNotificatio
{FindFirstChangeNotificati
monitor the file names in the specified Folder, you need to give the Handle returned to
the WaitForMultipleObjects( ) in the HndAry1 Array}
if (HndAry1[0] < 2) or (HndAry1[1] < 2) then
begin
MessageBox(Form1.Handle, 'FindFirst Change Notification Failed, could not monitor Folder',
'Change Notification Failed', MB_OK or MB_ICONERROR);
Exit;
{Exit will allow the finally section to execute and End this thread}
end;
Form1.Label5.Caption := 'Thread is RUNNING';
{I added this label just to let you know when the thread is running}
while true do
begin // a
Return1 := WaitForMultipleObjects(2, @HndAry1, False, INFINITE);
{WaitForMultipleObjects suspendes (freezes) this thread until it gets an Object
Handle event then it will resume the thread}
if Return1 = WAIT_FAILED then
begin // 1
MessageBox(Form1.Handle, 'WaitForMultipleObjects Failed, stopped monitoring Folder',
'Wait Failed', MB_OK or MB_ICONERROR);
{Break will stop the while loop and the finally section will execute to
end this thread}
Break;
end; // 1
AryNum := Return1 - WAIT_OBJECT_0;
{the Return1 - WAIT_OBJECT_0 value is the index number of the AryHandle Array
which fired the WaitForMultipleObjects( ) to resume the thread}
if AryNum = 0 then
begin // 3
{the AryNum = 0 means that the "Event" has been Set,
which is only used to End this thread}
Break;
end; // 3
if AryNum = 1 then
begin // 4
{test for the file name you want to monitor with If FileExists.
you can do other tests like for changes in existing file names}
If FileExists(DirPath+'\File to watch For.txt') then
begin
{add code here to get info from the new file and use that info}
Form1.GetFirstLine(DirPath
MessageBox(Form1.Handle, PChar('The File "File to watch For.txt" Has Been Created in '+ DirPath),
'NEW FILE in folder', MB_OK or MB_ICONERROR);
Break;
end;
{if the file does not exist, then the FindNextChangeNotification
end; // 4
{the FindNextChangeNotification
if not FindNextChangeNotification
begin
MessageBox(Form1.Handle, 'Find Next Change Notification Failed, stopped monitoring Folder',
'Next Change Notification Failed', MB_OK or MB_ICONERROR);
Break;
end;
end; // a
finally
{MAKE SURE you close all the handles}
CloseHandle(AryHandle[0]);
FindCloseChangeNotificatio
CloseHandle(AryHandle[1]);
Form1.Label5.Caption := 'NO Thread';
EndThread(Result);
end;
end;
procedure TForm1.button_GetAddFileCl
var
ThreadID: Cardinal;
begin
DirPath := 'C:\Stuff';
{put the Folder Path that you want to monitor for the
text file in DirPath variable}
SetEvent(HndAry1[0]);
{SetEvent(HndAry1[0]); is used to end the thread see the ThrdFunc for
"if AryNum = 0 then" which Exits the Thread}
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
{the lines above make sure the thread is Dead, but you could disable this
button and not have them}
hThrd := BeginThread(nil, 0, @ThrdFunc, nil, 0, ThreadId);
{start a New Thread with BeginThread. All the Wait functions like
WaitForMultipleObjects suspend the Thread until it gets an Event}
if hThrd > 0 then
begin
//SetThreadPriority(hThrd,
sbut_EndFileAdd.Enabled := True;
end else
Memo1.Text := 'Could not Create Thread';
end;
procedure TForm1.button_EndFileAddCl
var
Msg1: TMsg;
begin
if hThrd = 0 then Exit;
SetEvent(HndAry1[0]);
{using SetEvent will cause the event to fire and the new thread
to drop out of it's wait state and end the thread. Since its in
another thread, you need to wait for that thread to end before you
set the hThrd to 0. }
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
hThrd := 0;
end;
procedure TForm1.FormDestroy(Sender:
var
Msg1: TMsg;
begin
{make sure you close the handles before you exit the program to
avoid memory leaks}
if hThrd > 0 then
begin
SetEvent(HndAry1[0]);
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
end;
end;
- - - - - - - - - - - - - - - - - - - - - - - - - - -
if you haven't used threads much this may seem less than easy, ask questions if you need more info
ASKER
I have never used threads. I will read about it so I know how to ask a good question that I will understand the answer for.. It might take me some time....
ASKER
One question Slick.
If you look at my old question at:
https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=delphi&qid=20320178
Do you think this method here will make my service (in the old question) to not take so much cpu time?
If you look at my old question at:
https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=delphi&qid=20320178
Do you think this method here will make my service (in the old question) to not take so much cpu time?
ASKER
How can I use the abowe in a simple test application that just do a ShowMessage('File is modified'); when c:\test\testfile.txt is changed?
ASKER
Btw I can't compile the abowe code.... the AryHandle in the finaly statement is not declared.
the AryHandle should be HndAry1, I copied this witout changing it. Sorry
as I said in the Intro to the code You can change the flag in FindFirstChangeNotificatio n( ) to watch for other things, there are several file aspects it can monitor. You can set it to monitor if files are written-to or change there size.
if you change the
HndAry1[1] := FindFirstChangeNotificatio n(PChar(Di rPath), False, FILE_NOTIFY_CHANGE_FILE_NA ME)
to
HndAry1[1] := FindFirstChangeNotificatio n(PChar(Di rPath), False, FILE_NOTIFY_CHANGE_LAST_WR ITE)
it will monitor any files that are written to, but you will still have to check the individual files you are interested in to see if they have changed.
Also if you want to keep monitoring you need to remove the "Break" from the
if AryNum = 1 then
begin
if you change the
HndAry1[1] := FindFirstChangeNotificatio
to
HndAry1[1] := FindFirstChangeNotificatio
it will monitor any files that are written to, but you will still have to check the individual files you are interested in to see if they have changed.
Also if you want to keep monitoring you need to remove the "Break" from the
if AryNum = 1 then
begin
ASKER
When I push the "stop button"
I get an acess violation.
Here is what I try:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
procedure GetFirstLine(FileName: String);
public
{ Public declarations }
end;
var
Form1: TForm1;
hThrd: THandle;
HndAry1: Array[0..2] of Cardinal;
DirPath: String;
implementation
{$R *.dfm}
procedure TForm1.GetFirstLine(FileNa me: String);
var
File1: TextFile;
Line1: String;
begin
{this is a procedure to use the new file
remember that this is run in another thread and is
NOT syncronized with your main thread}
AssignFile(File1, FileName);
Reset(File1);
Readln(File1, Line1);
CloseFile(File1);
{do something here with the file}
{This Code is in a different thread than your main form
if you want to notifiy the main forms thread to do something
then you could use
SendMessage(Form1.Handle, WM_USER+432,0,0); and start the code
when it get's that message}
end;
function ThrdFunc(Parameter: Pointer): Integer; stdcall;
var
Return1: Cardinal;
AryNum: Integer;
begin
{this is the new Thread's function where you do anything
that you want to happen in this thread}
Result := 0;
{Result isn't used here}
try
HndAry1[0] := CreateEvent(nil, false, false, nil);
{you need to create an Event so you can easily Exit this thread,
the Thread is in a wait state so you need an Event to Activate the thread
from the Wait state of WaitForMultipleObjects, CloseHandle(hThrd)
will not end the thread in a wait state}
HndAry1[1] := FindFirstChangeNotificatio n(PChar(Di rPath), False, FILE_NOTIFY_CHANGE_FILE_NA ME);
{FindFirstChangeNotificati on with the FILE_NOTIFY_CHANGE_FILE_NA ME prameter will
monitor the file names in the specified Folder, you need to give the Handle returned to
the WaitForMultipleObjects( ) in the HndAry1 Array}
if (HndAry1[0] < 2) or (HndAry1[1] < 2) then
begin
MessageBox(Form1.Handle, 'FindFirst Change Notification Failed, could not monitor Folder',
'Change Notification Failed', MB_OK or MB_ICONERROR);
Exit;
{Exit will allow the finally section to execute and End this thread}
end;
Form1.Label1.Caption := 'Thread is RUNNING';
{I added this label just to let you know when the thread is running}
while true do
begin // a
Return1 := WaitForMultipleObjects(2, @HndAry1, False, INFINITE);
{WaitForMultipleObjects suspendes (freezes) this thread until it gets an Object
Handle event then it will resume the thread}
if Return1 = WAIT_FAILED then
begin // 1
MessageBox(Form1.Handle, 'WaitForMultipleObjects Failed, stopped monitoring Folder',
'Wait Failed', MB_OK or MB_ICONERROR);
{Break will stop the while loop and the finally section will execute to
end this thread}
Break;
end; // 1
AryNum := Return1 - WAIT_OBJECT_0;
{the Return1 - WAIT_OBJECT_0 value is the index number of the AryHandle Array
which fired the WaitForMultipleObjects( ) to resume the thread}
if AryNum = 0 then
begin // 3
{the AryNum = 0 means that the "Event" has been Set,
which is only used to End this thread}
Break;
end; // 3
if AryNum = 1 then
begin // 4
{test for the file name you want to monitor with If FileExists.
you can do other tests like for changes in existing file names}
If FileExists(DirPath+'\File to watch For.txt') then
begin
{add code here to get info from the new file and use that info}
Form1.GetFirstLine(DirPath +'\File to watch For.txt');
MessageBox(Form1.Handle, PChar('The File "File to watch For.txt" Has Been Created in '+ DirPath),
'NEW FILE in folder', MB_OK or MB_ICONERROR);
Break;
end;
{if the file does not exist, then the FindNextChangeNotification is called}
end; // 4
{the FindNextChangeNotification starts the folder monitoring again}
if not FindNextChangeNotification (HndAry1[1 ]) then
begin
MessageBox(Form1.Handle, 'Find Next Change Notification Failed, stopped monitoring Folder',
'Next Change Notification Failed', MB_OK or MB_ICONERROR);
Break;
end;
end; // a
finally
{MAKE SURE you close all the handles}
CloseHandle(HndAry1[0]);
FindCloseChangeNotificatio n(HndAry1[ 1]);
CloseHandle(HndAry1[1]);
Form1.Label1.Caption := 'NO Thread';
EndThread(Result);
end;
end;
procedure TForm1.Button1Click(Sender : TObject);
var
ThreadID: Cardinal;
Msg1 : TMsg;
begin
DirPath := 'd:\sparas';
{put the Folder Path that you want to monitor for the
text file in DirPath variable}
SetEvent(HndAry1[0]);
{SetEvent(HndAry1[0]); is used to end the thread see the ThrdFunc for
"if AryNum = 0 then" which Exits the Thread}
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, INFINITE,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, INFINITE);
CloseHandle(hThrd);
{the lines above make sure the thread is Dead, but you could disable this
button and not have them}
hThrd := BeginThread(nil, 0, @ThrdFunc, nil, 0, ThreadId);
{start a New Thread with BeginThread. All the Wait functions like
WaitForMultipleObjects suspend the Thread until it gets an Event}
if hThrd > 0 then
begin
//SetThreadPriority(hThrd, THREAD_PRIORITY_BELOW_NORM AL);
Button2.Enabled := True;
end else
Memo1.Text := 'Could not Create Thread';
end;
procedure TForm1.Button2Click(Sender : TObject);
var
Msg1: TMsg;
begin
if hThrd = 0 then Exit;
SetEvent(HndAry1[0]);
{using SetEvent will cause the event to fire and the new thread
to drop out of it's wait state and end the thread. Since its in
another thread, you need to wait for that thread to end before you
set the hThrd to 0. }
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, INFINITE,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, INFINITE);
CloseHandle(hThrd);
hThrd := 0;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
Msg1: TMsg;
begin
{make sure you close the handles before you exit the program to
avoid memory leaks}
if hThrd > 0 then
begin
SetEvent(HndAry1[0]);
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects( 1, hThrd, False, 600,
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd, 600);
CloseHandle(hThrd);
end;
end;
end.
I get an acess violation.
Here is what I try:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
procedure GetFirstLine(FileName: String);
public
{ Public declarations }
end;
var
Form1: TForm1;
hThrd: THandle;
HndAry1: Array[0..2] of Cardinal;
DirPath: String;
implementation
{$R *.dfm}
procedure TForm1.GetFirstLine(FileNa
var
File1: TextFile;
Line1: String;
begin
{this is a procedure to use the new file
remember that this is run in another thread and is
NOT syncronized with your main thread}
AssignFile(File1, FileName);
Reset(File1);
Readln(File1, Line1);
CloseFile(File1);
{do something here with the file}
{This Code is in a different thread than your main form
if you want to notifiy the main forms thread to do something
then you could use
SendMessage(Form1.Handle, WM_USER+432,0,0); and start the code
when it get's that message}
end;
function ThrdFunc(Parameter: Pointer): Integer; stdcall;
var
Return1: Cardinal;
AryNum: Integer;
begin
{this is the new Thread's function where you do anything
that you want to happen in this thread}
Result := 0;
{Result isn't used here}
try
HndAry1[0] := CreateEvent(nil, false, false, nil);
{you need to create an Event so you can easily Exit this thread,
the Thread is in a wait state so you need an Event to Activate the thread
from the Wait state of WaitForMultipleObjects, CloseHandle(hThrd)
will not end the thread in a wait state}
HndAry1[1] := FindFirstChangeNotificatio
{FindFirstChangeNotificati
monitor the file names in the specified Folder, you need to give the Handle returned to
the WaitForMultipleObjects( ) in the HndAry1 Array}
if (HndAry1[0] < 2) or (HndAry1[1] < 2) then
begin
MessageBox(Form1.Handle, 'FindFirst Change Notification Failed, could not monitor Folder',
'Change Notification Failed', MB_OK or MB_ICONERROR);
Exit;
{Exit will allow the finally section to execute and End this thread}
end;
Form1.Label1.Caption := 'Thread is RUNNING';
{I added this label just to let you know when the thread is running}
while true do
begin // a
Return1 := WaitForMultipleObjects(2, @HndAry1, False, INFINITE);
{WaitForMultipleObjects suspendes (freezes) this thread until it gets an Object
Handle event then it will resume the thread}
if Return1 = WAIT_FAILED then
begin // 1
MessageBox(Form1.Handle, 'WaitForMultipleObjects Failed, stopped monitoring Folder',
'Wait Failed', MB_OK or MB_ICONERROR);
{Break will stop the while loop and the finally section will execute to
end this thread}
Break;
end; // 1
AryNum := Return1 - WAIT_OBJECT_0;
{the Return1 - WAIT_OBJECT_0 value is the index number of the AryHandle Array
which fired the WaitForMultipleObjects( ) to resume the thread}
if AryNum = 0 then
begin // 3
{the AryNum = 0 means that the "Event" has been Set,
which is only used to End this thread}
Break;
end; // 3
if AryNum = 1 then
begin // 4
{test for the file name you want to monitor with If FileExists.
you can do other tests like for changes in existing file names}
If FileExists(DirPath+'\File to watch For.txt') then
begin
{add code here to get info from the new file and use that info}
Form1.GetFirstLine(DirPath
MessageBox(Form1.Handle, PChar('The File "File to watch For.txt" Has Been Created in '+ DirPath),
'NEW FILE in folder', MB_OK or MB_ICONERROR);
Break;
end;
{if the file does not exist, then the FindNextChangeNotification
end; // 4
{the FindNextChangeNotification
if not FindNextChangeNotification
begin
MessageBox(Form1.Handle, 'Find Next Change Notification Failed, stopped monitoring Folder',
'Next Change Notification Failed', MB_OK or MB_ICONERROR);
Break;
end;
end; // a
finally
{MAKE SURE you close all the handles}
CloseHandle(HndAry1[0]);
FindCloseChangeNotificatio
CloseHandle(HndAry1[1]);
Form1.Label1.Caption := 'NO Thread';
EndThread(Result);
end;
end;
procedure TForm1.Button1Click(Sender
var
ThreadID: Cardinal;
Msg1 : TMsg;
begin
DirPath := 'd:\sparas';
{put the Folder Path that you want to monitor for the
text file in DirPath variable}
SetEvent(HndAry1[0]);
{SetEvent(HndAry1[0]); is used to end the thread see the ThrdFunc for
"if AryNum = 0 then" which Exits the Thread}
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
{the lines above make sure the thread is Dead, but you could disable this
button and not have them}
hThrd := BeginThread(nil, 0, @ThrdFunc, nil, 0, ThreadId);
{start a New Thread with BeginThread. All the Wait functions like
WaitForMultipleObjects suspend the Thread until it gets an Event}
if hThrd > 0 then
begin
//SetThreadPriority(hThrd,
Button2.Enabled := True;
end else
Memo1.Text := 'Could not Create Thread';
end;
procedure TForm1.Button2Click(Sender
var
Msg1: TMsg;
begin
if hThrd = 0 then Exit;
SetEvent(HndAry1[0]);
{using SetEvent will cause the event to fire and the new thread
to drop out of it's wait state and end the thread. Since its in
another thread, you need to wait for that thread to end before you
set the hThrd to 0. }
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
hThrd := 0;
end;
procedure TForm1.FormDestroy(Sender:
var
Msg1: TMsg;
begin
{make sure you close the handles before you exit the program to
avoid memory leaks}
if hThrd > 0 then
begin
SetEvent(HndAry1[0]);
if GetCurrentThreadID = MainThreadID then
while MsgWaitForMultipleObjects(
QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg1, 0, 0, 0, PM_NOREMOVE)
else WaitForSingleObject(hThrd,
CloseHandle(hThrd);
end;
end;
end.
ASKER
Ahh it was only the exceptions from delphi.
Cound you just give me one hint how I can modify this if I want to check for a file change on a specific file (ie if I like to monitor a file instead of a folder)
Cound you just give me one hint how I can modify this if I want to check for a file change on a specific file (ie if I like to monitor a file instead of a folder)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for your help!
1. Is this a COM object you created or a third party COM object? If you created it then there are about a dozen ways to handle the problem. If third party, then you may be in some trouble, depending on what's in the files and how you need to notify people.
2. You can write a file monitor thread. Have it wake up every so often and check the server for files. Depending on other factors there are about a dozen ways of getting the files back to their respective owners.
3. Is the owner's destination represented or representable in the produced file?