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}
|