Applikationen
Ein Programm ohne sichtbares Fenster und ohne Taskbareintrag starten
Wie kann ich verhindern, daß Delphi automatisch ein Fenster anzeigt? Ich möchte gerne, daß meine Anwendung unsichtbar im Hintergrund läuft.
Um ein Programm ohne sichtbares Fenster zu starten, muß man verhindern, daß das Hauptformular automatisch nach dem Programmstart gezeigt wird. Dazu macht man folgenden Eintrag im Projektquelltext nach createform:
Application.ShowMainForm:= false;Um den Taskbar-Eintrag des Programms zu verstecken, muß man das Applikationsfenster (nicht die MainForm!) unsichtbar machen:
procedure TMainForm.FormShow(Sender: TObject); var Owner : HWnd; begin Owner:=GetWindow(Handle,GW_OWNER); ShowWindow(Owner,SW_HIDE); end; |
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SysCommand; procedure TMainForm.WMSysCommand(var Message: TWMSysCommand); begin if Message.CmdType and $FFF0 = SC_MINIMIZE then Hide else inherited; end; |
function RegisterServiceProcess(dwProcessID, dwType: DWord): DWord;stdcall; function RegisterServiceProcess; external 'KERNEL32.DLL' name 'RegisterServiceProcess'; RegisterServiceProcess(0,1); //zum verstecken! RegisterServiceProcess(0,0); //zum anzeigen ! [Marco Gessinger] |
{Task-Manager disablen} SystemParametersInfo(SPI_SCREENSAVERRUNNING,1,Nil,0); {Task-Manager enablen} SystemParametersInfo(SPI_SCREENSAVERRUNNING,0,Nil,0); |
Ein TrayIcon in der Taskbar Notification Area (neben der Systemuhr) anzeigen
Wie erreicht man, daß anstelle des normalen Programm-Buttons in der Windows-Taskbar ein TrayIcon in der Taskbar Notification Area neben der Windows.Systemuhr angezeigt wird?
Dafür gibt es die API-Funktion Shell_NotifyIcon() und den Daten-Record TNotifyIconData. Und so bindet man das ganze in ein Programm ein (Beispiel von Heino Tiedemann):
uses ShellAPI; const WM_TASKABAREVENT = WM_USER+1; //Taskbar message [...] type TMainForm = class(TForm) [...] private { Private-Deklarationen } procedure TaskbarEvent(var Msg: TMessage); Message WM_TASKABAREVENT; [...] {Message-Prozedur für das TrayIcon} procedure TMainForm.TaskbarEvent(var Msg: TMessage); var Point : TPoint; begin { Die WM_TaskbarEvent-Message "Msg" gibt in Msg.LParam das genaue Ereignis an. Msg.LParam kann folgende Werte für Mausereignisse annehmen: WM_MouseMove WM_LButtonDown WM_LButtonUp WM_LButtonDblClk WM_RButtonDown WM_RButtonUp WM_RButtonDblClk } { Eventhandler-Beispiele von Robert Fischer: } case Msg.LParam of WM_LBUTTONDBLCLK: begin //Mach etwas nach einem Doppelklick... end; WM_LBUTTONUP: begin //Mach etwas nach einem Linksklick... end; WM_RBUTTONUP: begin // Rechtsklick // Diese Zeile ist wichtig, damit das PopupMenu korrekt // wieder geschlossen wird: SetForegroundWindow(Handle); // PopupMenu anzeigen: GetCursorPos(Point); PopupMenu1.Popup(Point.x, Point.y); //oder ohne Variable Point: //PopupMenu1.Popup(Mouse.CursorPos.x, Mouse.CursorPos.y); end; end; end; {TrayIcon mit dem Hauptformular erzeugen} procedure TMainForm.FormCreate(Sender: TObject); var NotifyIconData: TNotifyIconData; begin Fillchar(NotifyIconData,Sizeof(NotifyIconData),0); NotifyIconData.cbSize := Sizeof(NotifyIconData); NotifyIconData.Wnd := Handle; NotifyIconData.uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP; NotifyIconData.uCallbackMessage := WM_TASKABAREVENT; NotifyIconData.hIcon := Application.Icon.Handle; NotifyIconData.szTip := 'Hinweistext für das TrayIcon'; Shell_NotifyIcon(NIM_ADD, @NotifyIconData); end; {TrayIcon mit dem Hauptformular zerstören} procedure TMainForm.FormDestroy(Sender: TObject); var NotifyIconData: TNotifyIconData; begin FillChar(NotifyIconData,Sizeof(NotifyIconData),0); NotifyIconData.cbSize := Sizeof(NotifyIconData); NotifyIconData.Wnd := Self.Handle; NotifyIconData.uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP; NotifyIconData.uCallbackMessage := WM_TASKABAREVENT; NotifyIconData.hIcon := Application.Icon.Handle; NotifyIconData.szTip := 'Punkt'; Shell_NotifyIcon(NIM_DELETE, @NotifyIconData); end; |
Untergeordnete Programm-Fenster in der Windows-Taskbar anzeigen
Wie kann ich erreichen, daß ein untergeordnetes Fenster einer Delphi-Anwendung in der Taskbar von Win95/NT erscheint?
Mit CreateParams. Im folgenden Sourcecode wird das besagte Fenster einfach zum Kindchen des Desktopfensters gemacht:
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private procedure CreateParams(var Params : TCreateParams); override; end; var Form1 : TForm1; implementation {$R *.DFM} procedure TForm1.CreateParams(var Params : TCreateParams); begin inherited CreateParams(Params); Params.WndParent := GetDesktopWindow; Params.Caption:='Title'; end; |
procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited; Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; end; |
Üblicherweise hat die Application einen Taskbareintrag, und kein Formular hat einen. Wird nun die Application per Taskbarbutton aktiviert, dann wird eben nicht das Haupformular nach vorne gebracht, sondern das zuletzt aktive.
Abhilfe: Auch dem MainForm per obiger Methode einen Taskbarbutton verpassen. Nun ist nur noch der der Anwendung zuviel. Wie man den beseitigst, liest man im ersten Artikel dieses Themanabschnitts.
Verhindern, daß ein Programm mehrmals gestartet wird
Wie kann ich verhindern, daß mein Programm 2 mal (zur gleichen Zeit) gestartet wird ??
Unter 32Bit-Windows bedient man sich eines Mutex. Binde folgende Unit ein, du musst sie einfach nur deinem Projekt hinzufügen:
unit NichtDoppeltStarten; interface implementation uses windows,Dialogs,sysutils; var mHandle: THandle; // Mutexhandle Initialization mHandle := CreateMutex(nil,True,'xxxxx'); // 'xxxxx' Der Anwendungsname ist hier einzutragen if GetLastError = ERROR_ALREADY_EXISTS then begin // Anwendung läuft bereits {showMessage('Anwendung läuft bereits!!!!!');} // Wenn du deine Meldung willst, mach die Klammern weg Halt; end; finalization // ... und Schluß if mHandle <> 0 then CloseHandle(mHandle) end. {Dieter Hirt} |
if hPrevInst<>>0 then begin {showMessage('Anwendung läuft bereits!!!!!');} Exit; end; {Marian Aldenhövel} |
Wie man die beim Start der zweiten Instanz übergebenen Parameter an die erste (laufende) Instanz der Anwendung weiterreicht, steht in diesem Text.
Wie erreiche ich, daß mein Programm eine Pause macht?
Generell gibt es da drei Möglichkeiten.
1. Sleep
Die einfachste funktioniert aber nur in 32Bit-Programmen und legt das Programm für die angegebene Zeit komplett lahm:
const Millisekunden = 1000; Sleep(Millisekunden); |
procedure Delay(ATime:Integer); var Start : Integer begin Start:=GetTickCount; repeat Application.ProcessMessages; until GetTickCount-Start > ATime; end; |
procedure Delay(Millisekunden : integer); begin PrgPause := True; PauseTimer.Intervall := Millisekunden; PauseTimer.Enabled := True; While PrgPause Do Application.ProcessMessages; PauseTimer.Enabled := False; end; |
Eigene Cursor in Programme einbinden
Die Methode, die ich verwendet habe, ist aus einem Buch und hat prima funktioniert:
1. Als Namen fuer die Cursor in der .res-Datei werden Zahlen verwendet.
(Im Beispiel 13 und 14)
2. Ganz wichtig: Ressourcen-Datei einbinden.
3. Konstanten definieren, z.B.:
const crMyCursor = 1; crNochnCursor = 2;
4. Cursor laden:
procedure TForm1.FormCreate(Sender: TObject); begin Screen.Cursors[crMyCursor]:= LoadCursor(HInstance,makeIntResource(13)); Screen.Cursors[crNochnCursor]:= LoadCursor(HInstance,makeIntResource(14)); Screen.Cursor:=crMyCursor; end; |
[Pilif:] Ich habe das Problem folgendermassen gelöst:
1) Zwei Variablen vom Typ THCursor mit genügendem Gültigkeitsbereich (Formvariablen),
2) Cursor einschalten:
type TForm1 = class(TForm) .. private var fic, foic : THCursor; fic:=LoadCursor(hinstance, makeIntResource(1)); //Cursor laden foic:=GetCursor; //Backup SetSystemCursor(fic, OCR_NORMAL); //Cursor austauschen |
3) Cursor ausschalten:
SetSystemCursor(foic, OCR_NORMAL); |
Wie kann ich Videos, Bilder oder Texte als Resourcen in ein Programm einbinden?
Hier ein Lösungsvorschlag für eine Videodatei:
Zuerst bringen wir mal das AVI in eine RES-Datei: 1) Schnapp dir Notepad 2) Schreibe folgendes in die Datei "MeinVideo RCDATA MEINFILM.AVI" 3) Speichere das ganze als eine RC-Datei ab 4) Nun führe folgenden Befehl aus : BRC32 -r datei.rc 5) Voilà du besitzt nun eine datei.res in der sich das AVI befindet. Diese kannst du nun mit {$R datei.res} in deine EXE einbinden 6) Kleine Verschnauf/Zigarettenpause 7) Mach ein neues Projekt 8) Binde die neue RES-Datei mit ein 9) Platziere eine TAnimate-Komponente auf deinem Formular 10) Gehe nun in die Routine in der das Video abgespielt werden soll und schreibe: Aminate1.ResName := 'MeinVideo'; Animate1.Play; 11) Freuen, wenns klappt Für andere Resourcen muß folgendes in der .RC-Datei stehen: Cursor : "CursorName Cursor Dateiname.cur" Icons : "IconName Icon Dateiname.ico" Strintables : STRINGTABLE DISCARDABLE BEGIN 10001 "Explorer Fenster" [..] END
In diesem Beispielprojekt wird ausführlich beschrieben, wie man Sounds in Form zweier Wavedateien in die EXE-Datei kompiliert.
Wie man einen formatierten (RTF-)Text als Resource in ein Programm einbindet
Sören Mühlbauer hat dazu folgende Vorgehensweise aufgezeigt: Mach dir eine Datei z.b. MyRTFRes.RC. Inhalt:
MYFIRSTRTF RCDATA MYRTF1.RTF
MYSECONDRTF RCDATA MYRTF2.RTF
Nun erzeugst Du daraus mittels des Resource Compileres eine .res-Datei :
brcc32 MyRTFRes.rc
Dann nimmst Du diese mittels {$R MyRTFRes.res} in dein Programm auf. Es folgt ein Beispiel, wie Du den RTF-Text nun auliest und in einem TRichEdit-Control anzeigst:
var TempStream : TResourceStream; begin TempStream := TResourceStream.Create(hInstance, 'MyFirstRTF', RT_RCDATA); try TempStream.Position := 0; RichEdit1.Lines.LoadFromStream(TempStream); finally TempStream.Free; end; end; |
Den Ordner der Programmdatei (*.exe) ermitteln
Wie ermittle ich den Ordner, in dem sich die EXE-Datei meines Programmes auf dem jeweiligen Rechner befindet?
In der Eigenschaft "ExeName" des TApplication-Objekts ist der komplette Dateiname der Programmdatei inklusive Pfad gespeichert. Um nur den Ordner der EXE-Datei zu erhalten, kann man diesen mit ExtractFilePath isolieren:
procedure TMainForm.FormCreate(Sender: TObject); var ProgrammOrdner : string; begin ProgrammOrdner:=ExtractFilePath(Application.ExeName); end; |
Die eigene Anwendung in den Vordergrund bringen
Wie kann ich das Programmfenster meiner eigenen Anwendung in den Vordergrund bringen und ihm den Eingebafokus verpassen? Ab Windows 98 blinkt ja normalerweise nur noch der Taskbar-Eintrag, wenn ich die Methode "Application.BringToFront" aufrufe.
Man muß vor dem In-den-Vordergrund-Bringen der Anwendung den Eingabfokus auf die eigene Applikation setzen. Das geschieht in dieser Prozedur von Michael Winter mit einem Aufruf der API-Funktion "AttachThreadInput". Anschließend wird dann das Applikations-Fenster per "SetForegroundWindow" nach vorne gebracht. Sollte dies mißlingen ist die Prozedur so freundlich, den Eingabefokus wieder an das ursprüngliche Vordergrundfenster zurückzugeben:
procedure ShowMe; var Th1, Th2: Cardinal; begin Th1 := GetCurrentThreadId; Th2 := GetWindowThreadProcessId(GetForegroundWindow, nil); AttachThreadInput(Th2, Th1, true); try SetForegroundWindow(Application.Handle); finally AttachThreadInput(Th2, Th1, false); end; end; {Michael Winter} |