22. december 2002 - 00:34Der er
30 kommentarer og 1 løsning
Hvis program er åben send paramenter der åbner fil og luk sig sel
Ja, emnet siger jo næsten sig selv.
Jeg er som så mange andre ved at kode en web-editor. Og det jeg ønsker er i min mainforms oncreate event skal der chekkes for om programmet er åbn en gang i forvejen. Er det det så skal der sendes en paramenter til programmet som åbner den fil man forsøgte at åbne (altså, kun hvis man da forsøgte at åbne det) laver "SetForegroundWindow(hwnd) og lukker sig selv. Indtil videre er jeg ikke nået længere end noget alla det her:
var Hwnd: integer; CaptionName: string; begin CaptionName := 'Smart Edit'; Hwnd := FindWindow(nil, PChar(CaptionName)); If Hwnd > 0 then begin SetForegroundWindow(Hwnd); Close; end; end;
Så det jeg ønsker er altså at sende paramenter til mit program og behandle dem, jeg har forsøgt mig lidt med SendMessage og Så lave en Application.OnMessage event i min mainform, nogen der har en løsning?
procedure TfrmDinMainForm.WMCopyData(var msg: TWMCopyData); var s:string; begin s := PChar(msg.CopyDataStruct.lpData); Application.BringToFront; showmessage('Besked modtaget:'+s); end;
//I din project fil (DPR)
uses Windows, messages;
var handle: THandle; cds: TCopyDataStruct; fMutex: THandle; s:string; i:integer; begin // Ser om dit program kører vedhjælp af mutex
fMutex := CreateMutex(nil,false,'DitUnikeMutexNavn'); // <-- Skift den til noget langt og unikt :) if ( GetLastError() = ERROR_ALREADY_EXISTS ) or ( WaitForSingleObject(fMutex,100) = WAIT_TIMEOUT ) or ( fMutex = 0 ) then begin // Fandt et kørende program... handle := FindWindow('TfrmDinMainForm','Program title'); // <-- Det er nok med classen hvis du er sikker på at der ikke er andre programmer der har den samme
if handle <> 0 then begin //Laver en stor paramstr s := ''; for i:= 1 to ParamCount do s:=s+ParamStr(i)+#$0d;
with cds do begin dwData := 0; cbData := length(s); lpData := PChar(s); end; // Sender besked og stopper dette program SendMessage(handle,WM_COPYDATA,Application.Handle,integer(@cds)); exit; end; end;
Application.Initialize; // ... autocreate og hvad du ellers har Application.Run; end.
Egentlig virker det meget godt, men hvordan "afkoder" jeg den der s streng til noget brugbart, der står noget med "besked modtaget: araber/kineser tegn", det kommer jo fra den der showmessage, det er jeg med på, men hvordan afkoder jeg de andre tegn så det bliver til noget jeg kan bruge til evt. at åbne nogle filer.
Lyder rart, sidder nemlig og venter på at kan få det her løst så jeg kan udgive en ny udgave af min editor :-D, bare sig til hvis der skal flere point til, jeg vil gøre (næsten) alt.
Jeg har nu fået det til at virke (næsten) af en eller anden mystisk grund så VIL det kun virke hvis jeg ikke allerede har et MDI vindue åben (editoren kan findes her: www.smartware.dk/software/download/smartedit/), derfor vil jeg gerne høre om du har nogle forslag, når jeg får det sidste her løst skal du nok få dine velfortjente point.
Ok som sagt, jeg har næsten fået det til at virke, men det virker ikke hvis et MDI vindue allerede er åbn, der modtager min MainForm, simpelthen ikke messagen som den ny åbnet (og lukket) application sender til den. Her er mine koder som de ser ud nu:
procedure TMainForm.WMCopyData(var msg: TWMCopyData); var s:string; r: TRegExpr; Params: TStringList; FileName: string; I: integer; begin s := PChar(msg.CopyDataStruct.lpData); r := TRegExpr.Create; Params := TStringList.Create; r.Expression := ' '; r.Split(s, Params); FileName := ''; For I := 0 to Params.Count - 2 do begin FileName := FileName + ' ' + Params.Strings[I]; end; Delete(FileName, 1, 1); ShowMessage('"' + FileName + '"'); If FileExists(FileName) then begin NumsOpen := NumsOpen + 1; CreateMDIChild(FileName); TChildWin(ActiveMDIChild).SynMemo.Lines.LoadFromFile(FileName); end; ShowWinNoAnimate(Application.Handle, SW_MINIMIZE); ShowWinNoAnimate(Application.Handle, SW_RESTORE);
end;
Og:
var IniFile: TIniFile; handle: THandle; cds: TCopyDataStruct; fMutex: THandle; s:string; i:integer; begin fMutex := CreateMutex(nil,false,'MinsupersmarteSmartEditunikkemutextsomderikkeerandrederhar'); // <-- Skift den til noget langt og unikt :) if ( GetLastError() = ERROR_ALREADY_EXISTS ) or ( WaitForSingleObject(fMutex,100) = WAIT_TIMEOUT ) or ( fMutex = 0 ) then begin // Fandt et kørende program... handle := FindWindow('TMainForm',PChar('Smart Edit')); // <-- Det er nok med classen hvis du er sikker på at der ikke er andre programmer der har den samme
if handle <> 0 then begin //Laver en stor paramstr s := ''; for i:= 1 to ParamCount do s:=s+ParamStr(i)+ ' '; ShowMessage(s + ' ' + BoolToStr(FileExists(s), True)); if FileExists(s) = False then s := '';
with cds do begin dwData := 0; cbData := length(s); lpData := PChar(s); end; // Sender besked og stopper dette program SendMessage(handle,WM_COPYDATA,Application.Handle,longint(@cds)); exit; end; end;
Og ud fra de showmessages som der skal vises kan jeg se at den ikke modtager nogen besked når et MDI vindue allerede er åben, jeg håber at du er der til at hjælpe mig med mit sidste spørgsmål dkn, så skal jeg nok give dig dine point, plus lidt exstra ;-).
Nu hvor jeg kiggede det hele igennem tror jeg jeg ved hvorfor fejlen opstår. FindWindow('TMainForm',PChar('Smart Edit')) Her ligger skidtet, når man åbner et mdi vindue bliver dens caption jo også tilføjet, derfor holder den ikke helt. Er der ikke andre måder jeg kan finde mit vindue på?
function EnumWindowsProc(Wnd: HWnd; Form: TForm1): Boolean; export; {$IFDEF Win32} stdcall; {$ENDIF} var Buffer: array[0..99] of char; begin GetWindowText(Wnd, Buffer, 100); if StrLen(Buffer) <> 0 then Proglist.Add(Buffer); Result := True; end;
procedure TForm1.Button1Click(Sender: TObject); var handle: THandle; cds: TCopyDataStruct; s: string; i: integer; begin Proglist := TStringlist.Create; EnumWindows(@EnumWindowsProc, LongInt(Self));
handle := 0; for I := 0 to Proglist.Count - 1 do if pos('Smart Edit', Proglist.Strings[I]) <> 0 then handle := findwindow(nil, Pchar(Proglist.Strings[I]));
if handle <> 0 then begin s := 'Test String'; with cds do begin dwData := 0; cbData := length(s); lpData := PChar(s); end; SendMessage(handle, WM_COPYDATA, Application.Handle, longint(@cds)); exit; end else showmessage('debug: fandt ikke prog'); end;
Ok ser ud til at virke nu, efter at mdi er blevet maximeret. Måske ikke den smarteste måde, men jeg desvære ikke lige komme på andet :)
Hader når folk selv stiller det her spørgsmål, men du vil ikke lige være venlig at lave et eksempel som jeg næsten selv kan bruge, ligesom det første du oprettede?
function EnumWindowsProc(Wnd: HWnd): Boolean; export; {$IFDEF Win32} stdcall; {$ENDIF} var Buffer: array[0..99] of char; begin GetWindowText(Wnd, Buffer, 100); if StrLen(Buffer) <> 0 then Proglist.Add(Buffer); Result := True; end;
begin Proglist := TStringlist.Create; EnumWindows(@EnumWindowsProc, 0);
handle := 0; for I := 0 to Proglist.Count - 1 do if pos('Smart Edit', Proglist.Strings[I]) <> 0 then handle := findwindow(nil, Pchar(Proglist.Strings[I]));
if handle <> 0 then begin s := 'Test String'; with cds do begin dwData := 0; cbData := length(s); lpData := PChar(s); end; SendMessage(handle, WM_COPYDATA, Application.Handle, longint(@cds)); exit; end;
Nej jeg kan ikke få det til at virke. Mit program lukker uformelt ned. Jeg prøvede dog at lave nogle ændringer. 1. handle gik jeg ud fra blev til application.handle, derfor skiftede jeg det til hwnd, dernæst fik jeg atvide at HWnd (i funktionen) ikke var en type, så jeg skiftede den ud med cardinal, men det hjalp heller ikke, har du nogen idee'er?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.