Pisałem dlaczego. Kopia nie pomija WaitForSingleObject, tylko funkcja ta nie ma na co czekać, wszak pierwsza instancja aplikacji stworzyła muteks, ale nie jest jego właścicielem.
Przeczytaj mój ostatni post. Nie o to chodzi.
W przypadku restartu funkcja
WaitForSingleObject ma na co czekać, gdyż jest wywoływana w kopii programu wiec jest procesem potomnym, oczekuje na zamknięcie aplikacji, która wywołała kopię i po zakończeniu oczekiwania przechodzi do dalszych instrukcji. Problem w tym, że wychodzi z warunku pomijając kod znajdujący się po tej funkcji.
To powinno być jednak na odwrót, czyli program główny powinien czekać na zakończenie działania programu potomnego, a jest odwrotnie.
W przypadku gdy kopia jest uruchamiana ręcznie (nie restart), wtedy funkcja
WaitForSingleObject nie ma na co czekać, więc od razu przechodzi do dalszych instrukcji.
Dlatego działanie jest prawidłowe i działa, niejasna jest sytuacja z tym kodem w pierwszym przypadku:
- Kod: Zaznacz cały
ShowMessage("Program jest już uruchomiony");
Application->Terminate();
Daj po wywołaniu kopi Sleep(5000), coby było wiadomo, że kopia czeka na zamknięcie aplikacji.
No i po tym, program działa jak powinien, czyli nie działa prawidłowo.
W tej sytuacji nie widzę zastosowania dla funkcji
WaitForSingleObject.
Rzecz w tym, że restart programu nie wymaga wcale takich zabiegów, wystarczy taki kod:
- Kod: Zaznacz cały
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ShellExecute(NULL,"open","restartAppMutex.exe",NULL,NULL,SW_SHOW);
Close();
}
//---------------------------------------------------------------------------
Program uruchamia swoją kopie i kończy działanie. Czego więcej potrzeba?!
Upierając się przy mutexach, można to zrobić tak:
plik nagłówkowy np. Unit1.h:
- Kod: Zaznacz cały
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TEdit *Edit1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private: // User declarations
void __fastcall WmCopyData(TWMCopyData& Message);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COPYDATA, TWMCopyData, WmCopyData)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
plik źródłowy np. Unit1.cpp:
- Kod: Zaznacz cały
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ShellExecute(NULL,"open","restartAppMutex.exe",NULL,NULL,SW_SHOW);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WmCopyData(TWMCopyData& Message)
{
AnsiString slCmdLine = (char*)Message.CopyDataStruct->lpData;
if(slCmdLine == "close") Close();
}
//---------------------------------------------------------------------------
plik źródłowy projektu, np. Project1.cpp:
- Kod: Zaznacz cały
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, 0, "twoja_aplikacja.exe_restart");
if(!hMutex) hMutex = CreateMutex(0, 0, "twoja_aplikacja.exe_restart");
else
{
HWND hWnd = FindWindow("TForm1", NULL);
if(hWnd)
{
char cmdLine[] = "close";
COPYDATASTRUCT cds;
cds.cbData = strlen(cmdLine) + 1;
cds.lpData = cmdLine;
SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cds);
}
}
Application->Initialize();
SetApplicationMainFormOnTaskBar(Application, true);
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
ReleaseMutex(hMutex);
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------
Ten kod oczywiście w przypadku, gdy zostanie uruchomiona ręcznie kopia programu spowoduje zamknięcie istniejącego programu i uruchomienie kopii, ale można by to dopracować, np. poprzez wywołanie restartu programu z przekazaniem argumentu z linii komend, potem kopia pobiera ten argument i przekazuje go do działającego programu, który odbiera ten argument i kończy działanie. Uruchomiona ręcznie kopia programu nie zawierała by argumentu, więc pierwszy program nie otrzymując niezbędnego argumentu nie kończył by działania, kopia programu nie mając argumentu sama kończyła by działanie. Do tego wszystkiego chyba wogóle nie potrzebny byłby mutex. To wszystko jednak niepotrzebnie skomplikowałoby program, więc Twój sposób jest lepszy.