RTad Studio - TrayIcon + Mehrfachstart der exe



  • Hi,

    hab ein Problem mit dem Rad Studio XE5 welches unter dem alten "C++Builder 6" nicht auftrat. Aus diesem Grund kann ich bestimmte Anwendungen nicht mit dem Rad Studio schreiben und muss auf den alten "C++Builder 6" zurückgreifen.

    Das Problem entsteht genau dann wenn ich mein Programm minimiert bzw. versteckt im Tray starte und das Hauptfenster nicht sichtbar ist (mit Icon im Tray). Starte ich dann die Exe nochmals wird das Hauptfenster in den Vordergrund gebracht und es wirkt wie abgeschaltet, man sieht nur das Fenster ohne Komponenten. Das Problem hab ich nun leider erst mit dem Rad Studio.

    hier mal der Code welcher so knapp wie möglich gehalten wurde um das Problem zu demonstrieren.

    unit1.cpp

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
    	TTrayIcon *Tray = new TTrayIcon(this);
    	Tray ->Visible = true;
    
    	TEdit *E = new TEdit(this);
    	E->Parent = this;
    	E->Text = "test";
    	E->Left = 10;
    	E->Top = 30;
    
    	Application->ShowMainForm = false;
    }
    

    Project1.cpp

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    #include <tchar.h>
    //---------------------------------------------------------------------------
    USEFORM("Unit1.cpp", Form1);
    //---------------------------------------------------------------------------
    int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
    {
    	try
    	{
    		const wchar_t *Pname = L"Form1";
    		//*********** Eingfügen ***** mehrmals start verhindern *****************
    
    		HANDLE hMutex=OpenMutex(MUTEX_ALL_ACCESS, 0, Pname);
    		if(!hMutex)
    		{
    			hMutex=CreateMutex(0, 0, Pname);
    		}
    		else
    		{
    			HWND hWnd=FindWindow(0, Pname);
    			if(hWnd)
    			{
    				 ShowWindow(hWnd, SW_RESTORE);
    				 SetForegroundWindow(hWnd);
    				 SetActiveWindow(hWnd);
    				 SetFocus(hWnd);
    			}
    
    			CloseHandle(hMutex);
    			return 0;
    		}
    
    		Application->Initialize();
    		Application->MainFormOnTaskBar = true;
    		Application->CreateForm(__classid(TForm1), &Form1);
    		Application->Run();
    	}
    	catch (Exception &exception)
    	{
    		Application->ShowException(&exception);
    	}
    	catch (...)
    	{
    		try
    		{
    			throw Exception("");
    		}
    		catch (Exception &exception)
    		{
    			Application->ShowException(&exception);
    		}
    	}
    	return 0;
    }
    


  • Das Problem ist, dass das Application->Handle der Anwendung von FindWindow nicht mehr gefunden wird (liefert immer 0).
    Ich habe das auf eine andere Art gelöst:

    Mit RegisterwindowMessage wird eine eigene Message registriert.

    Wird die App nun ein zweites Mal gestartet, prüft sie wie bisher, ob es diesen Mutex schon gibt. Wenn ja, sendet sie mit PostMessage(HWND_BROADCAST...) diese Message ab und beendet sich.
    Die bereits laufende Instanz reagiert auf diese Message und bringt die Applikation wieder in den Vordergrund.



  • Hi,

    erstmal Danke Dir für die Info mit der RegisterwindowMessage, hab mir mit etwas lesen und im Netz was zusammengebastelt aber ich glaube da fehlt noch was weil mein Programm nicht in den Vordergrund geht, aber der Mehrfachstart wird schonmal erkannt. Habe auch erstmal das TrayIcon weggelassen dazu komm ich dann später. Hier erstmal der Code, aber wie mach ich weiter ? das es in den Vordergrund geht ?

    Project1.cpp

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    #include <tchar.h>
    //---------------------------------------------------------------------------
    USEFORM("Unit1.cpp", Form1);
    //---------------------------------------------------------------------------
    HANDLE Mutex;
    //---------------------------------------------------------------------------
    int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
    {
    	try
    	{
    		bool Is_Running;
    		unsigned int MutexMsg = RegisterWindowMessage(L"911 was an inside job");
    		Mutex = CreateMutex (NULL, True, L"911 was an inside job");
    
    		Is_Running = (GetLastError() == ERROR_ALREADY_EXISTS) || (Mutex == 0);
    
    		if(Is_Running)
    		{
    			ShowMessage("läuft schon");
    			SendMessage(HWND_BROADCAST, MutexMsg, 0, 0);
    
    			CloseHandle(Mutex);
    			return 0;
    		}
    
    		Application->Initialize();
    		Application->MainFormOnTaskBar = true;
    		Application->ShowMainForm = true;
    		Application->CreateForm(__classid(TForm1), &Form1);
    		Application->Run();
    
    		if (Mutex != 0)
    			CloseHandle(Mutex);
    	}
    	catch (Exception &exception)
    	{
    		Application->ShowException(&exception);
    	}
    	catch (...)
    	{
    		try
    		{
    			throw Exception("");
    		}
    		catch (Exception &exception)
    		{
    			Application->ShowException(&exception);
    		}
    	}
    	return 0;
    

    unit1.cpp

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
         //TTrayIcon *Tray = new TTrayIcon(this);
         //Tray ->Visible = true;
    
    	TEdit *E = new TEdit(this);
    	E->Parent = this;
    	E->Text = "test";
    	E->Left = 10;
    	E->Top = 30;}
    


  • So fang jetzt die Message ab aber irgendwie bin ich zu blöde bekomm das nicht nicht hin, bei erneuten start der exe blinkt das Programm nur in der Taskleiste umher.

    Project.cpp

    #pragma hdrstop
    #include <tchar.h>
    //---------------------------------------------------------------------------
    USEFORM("Unit1.cpp", Form1);
    //---------------------------------------------------------------------------
    HANDLE Mutex;
    //---------------------------------------------------------------------------
    int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
    {
    	try
    	{
    		bool Is_Running;
    		unsigned int MutexMsg = RegisterWindowMessage(L"911 was an inside job");
    		Mutex = CreateMutex (NULL, True, L"911 was an inside job");
    
    		Is_Running = (GetLastError() == ERROR_ALREADY_EXISTS) || (Mutex == 0);
    
    		if(Is_Running)
    		{
    			const WM_TEST_MSG = 'A';
    			SendMessage(HWND_BROADCAST, WM_TEST_MSG, 0, 0);
    
    			CloseHandle(Mutex);
    			return 0;
    		}
    
    		Application->Initialize();
    		Application->MainFormOnTaskBar = true;
    		Application->ShowMainForm = true;
    		Application->CreateForm(__classid(TForm1), &Form1);
    		Application->Run();
    
    		if (Mutex != 0)
    			CloseHandle(Mutex);
    	}
    	catch (Exception &exception)
    	{
    		Application->ShowException(&exception);
    	}
    	catch (...)
    	{
    		try
    		{
    			throw Exception("");
    		}
    		catch (Exception &exception)
    		{
    			Application->ShowException(&exception);
    		}
    	}
    	return 0;
    }
    //---------------------------------------------------------------------------
    

    unit1.cpp

    void __fastcall TForm1::ShowMyWindow(TMessage &Msg)
    {
    	TForm::Dispatch(&Msg);
    
    	Show();
    	Application->BringToFront();
    	Application->Restore();
    
    	//ShowMessage( (char) Msg.Msg );
    }
    

    unit1.h

    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Vcl.Controls.hpp>
    #include <Vcl.StdCtrls.hpp>
    #include <Vcl.Forms.hpp>
    //---------------------------------------------------------------------------
    
    const WM_TEST_MSG = 'A';
    
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    
    private:	// Benutzer-Deklarationen
    	void __fastcall ShowMyWindow(TMessage & Msg);
    public:		// Benutzer-Deklarationen
    	__fastcall TForm1(TComponent* Owner);
    
    		BEGIN_MESSAGE_MAP
    			VCL_MESSAGE_HANDLER(WM_TEST_MSG, TMessage, ShowMyWindow)
    		END_MESSAGE_MAP(TForm)
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    


  • So hab nochmals den Code etwas überarbeitet, nur bleibt das Problem das die Applikation bei mehrfachstart nur in der Taskleiste herumblinkt und nicht in den Vordergrund kommt.

    unit1.cpp

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    
    extern MutexMsg;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::WndProc(TMessage &Msg)
    {
    	if(	Msg.Msg == MutexMsg)
    	{
    		Show();
    		Application->BringToFront();
    		SetForegroundWindow(this->Handle);
    		BringWindowToTop(this->Handle);
    
    		//PostMessage(this->Handle , WM_SYSCOMMAND, SC_RESTORE, 0 );
    		//ShowMessage(MutexMsg);
    
    		static int round = 0;
    		Caption = round;
    		round ++;
    
    		return;
    	}
    
    	inherited::WndProc( Msg);
    }
    
    void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    		Application->Restore();
    		Application->RestoreTopMosts();
    		Update();
    }
    

    unit1.h

    //---------------------------------------------------------------------------
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Vcl.Controls.hpp>
    #include <Vcl.StdCtrls.hpp>
    #include <Vcl.Forms.hpp>
    //---------------------------------------------------------------------------
    
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    	void __fastcall FormPaint(TObject *Sender);
    private:	// Benutzer-Deklarationen
    	void __fastcall ShowMyWindow(TMessage & Msg);
    public:		// Benutzer-Deklarationen
    	__fastcall TForm1(TComponent* Owner);
    		void __fastcall WndProc(TMessage &Message);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    
    #include <vcl.h>
    #pragma hdrstop
    #include <tchar.h>
    //---------------------------------------------------------------------------
    USEFORM("Unit1.cpp", Form1);
    //---------------------------------------------------------------------------
    HANDLE Mutex;
    unsigned int MutexMsg;
    //---------------------------------------------------------------------------
    int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
    {
    	try
    	{
    		bool Is_Running;
    		MutexMsg = RegisterWindowMessage(L"911 was an inside job");
    		Mutex = CreateMutex (NULL, True, L"911 was an inside job");
    		Is_Running = (GetLastError() == ERROR_ALREADY_EXISTS) || (Mutex == 0);
    
    		if(Is_Running)
    		{
    			SendMessage(HWND_BROADCAST, MutexMsg, 0, 0);
    
    			CloseHandle(Mutex);
    			return 0;
    		}
    
    		Application->Initialize();
    		Application->MainFormOnTaskBar = true;
    		Application->ShowMainForm = true;
    		Application->CreateForm(__classid(TForm1), &Form1);
    		Application->Run();
    
    		if (Mutex != 0)
    			CloseHandle(Mutex);
    	}
    	catch (Exception &exception)
    	{
    		Application->ShowException(&exception);
    	}
    	catch (...)
    	{
    		try
    		{
    			throw Exception("");
    		}
    		catch (Exception &exception)
    		{
    			Application->ShowException(&exception);
    		}
    	}
    	return 0;
    }
    //---------------------------------------------------------------------------
    


  • http://www.swissdelphicenter.com/de/showcode.php?id=261

    Dort findest du eine Funktion, die ein Fenster in den Vordergrund "zwingt", musst du halt nach C++ umsetzen. Da kannst du dann auch das Handle deiner Applikation übergeben. 😉



  • hi Burkhi,

    ich kan das nicht glauben das es so kompliziert sein soll ?

    Wieso blinkt denn meine Applikation nur umher bzw. bleibt im Hintergrund, da hat ich ja beim alten compiler weniger Probleme, muss doch irgendwie machbar sein.

    Hab ja auch zum Test in der Form nen Counter drin der zählt wie oft die exe gestartet wurde, wird auch in der Form caption angezeigt und erhöht sich jedesmal um 1, aber die Form bleibt im Hintergrund, muss doch irgendwie leichter gehn ?

    Klar ich versuch mal den Code dort von der Seite auf C++ umzusetzen bei Gelegenheit. Nur eigentlich woll ich das ja mit dem TrayIcon noch gebacken kriegen, das kann ja alles noch lustig werden.



  • Hi,
    Microsoft hat das Verhalten seit (glaube ich zumindest) Windows 2000 dahingehend verändert, das ein Applikationsfenster nicht automatisch nach vorne kommt, wenn die Applikation grade den Eingabefokus nicht hat, sondern halt nur in der Taskleiste aufblinkt. Ist ja eigentlich auch besser so, damit sich eine Applikation nicht einfach "vordrängeln" kann, wenn der Benutzer in einer anderen Applikation grade etwas eingibt.

    Dafür ist dann eben AttachThreadInput nötig. 😉

    BTW: Hier ist das ganze auch in C++:
    http://www.c-plusplus.net/forum/231249-full



  • @Burkhi

    DER OBERHAMMER !!!

    Ich hab die Sache ausprobiert und als Handle einfach das Handle der Form1 übergeben. Funktioniert auch soweit wunderbar mit Einschränkung bei minimierten Start meiner Applikation wird das Fenster zwar angezeigt (nach Mehrfachstart) aber man sieht nur ein leeres Fenster ohne Inhalt, hab durch nen Zufall das Problem aber beheben können. Ich hatte das Problem übrigens auch schon im Eingangsthread geschildert das ich ein Fenster sehe welches wie abgeschaltet wirkt (nach Mehrfachstart) sobald die Applikation versteckt gestartet wird.

    Hab einfach noch nachträglich den "Show();" Befehl hinterher geballert und das Fenster wirkt auch bei minimierten Start völlig normal.

    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
    	this->WindowState = wsMinimized;
    }
    
    void __fastcall TForm1::WndProc(TMessage &Msg)
    {
    	if(	Msg.Msg == MutexMsg)
    	{
    		SetToForeground(this->Handle); //http://www.c-plusplus.net/forum/231249-full
    		Show();		//bei minimierten Programmstart
    
    		static int round = 0;
    		Caption = round;
    		round ++;
    
    		return;
    	}
    
    	inherited::WndProc( Msg);
    }
    

    Wenn ich nun Glück habe kann ich eventuell endlich auch mal bestimmte Programme mit dem Rad Studio schreiben.

    Wie soll ich sagen: Burkhi du bist der Beste, Danke. 🙂



  • hab mir mal den Code in der Project.cpp nochmals angesehn, irgendwie werd ich das Gefühl nicht los das die Zeile keinen Sinn ergibt:

    Is_Running = (GetLastError() == ERROR_ALREADY_EXISTS) || (Mutex == 0);
    

    Wenn nur eines dert Beiden true ist dann ist IS_Running = true
    Selbst wenn (Mutex == 0) wäre dann wäre diese Auusage ja true und somit steht Is_Running auf true

    Ist das so nicht viel sinvoller ?

    Is_Running = (GetLastError() == ERROR_ALREADY_EXISTS) && (Mutex != 0);
    

    Wenn beide true sind dann ist IS_Running = true

    oder hab ich nen Denkfehler ?



  • Emil_2014 schrieb:

    ...
    Wie soll ich sagen: Burkhi du bist der Beste, Danke. 🙂

    Gerne geschehen 🙂 😉


Anmelden zum Antworten