2012-12-10 15 views
12

मेरे जीयूआई ऐप में मैं कंसोल ऐप चलाता हूं और इसकी खिड़की के हैंडल की आवश्यकता होती है। मैंने EnumWindows() के साथ प्रयास किया, नीचे कोड देखें, लेकिन यह काम नहीं करता है। सूची में मेरा कोई कंसोल ऐप नहीं है।मेरे जीयूआई एप्लिकेशन से लॉन्च कंसोल विंडो के हैंडल कैसे प्राप्त करें?

type 
    TEnumWindowsData = record 
    ProcessId: Cardinal; 
    WinHandle: THandle; 
    List: TStrings;     // For test only 
    end; 
    PEnumWindowsData = ^TEnumWindowsData; 

function FindWindow(hWnd: THandle; lParam: LPARAM): BOOL; stdcall; 
var 
    ParamData: TEnumWindowsData; 
    ProcessId: Cardinal; 
    WinTitle: array[0..200] of Char; // For test only 
begin 
    ParamData := PEnumWindowsData(lParam)^; 
    GetWindowThreadProcessId(hWnd, ProcessId); 
    if ProcessId <> ParamData.ProcessId then 
    Result := True 
    else begin 
    ParamData.WinHandle := hWnd; 
    Result := False; 
    end; 
    // For test only 
    GetWindowText(hWnd, WinTitle, Length(WinTitle) - 1); 
    ParamData.List.Add(IntToStr(ProcessId) + ' ' + IntToStr(hWnd) + ' ' + WinTitle); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 

    function RunApp(const AProgram: string): Cardinal; 
    var 
    StartupInfo: TStartupInfo; 
    ProcessInformation: TProcessInformation; 
    begin 
    Result := 0; 
    ... 
    if CreateProcess(nil, PChar(AProgram), nil, nil, False, 
      NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation) 
    then 
     Result := ProcessInformation.dwProcessId; 
    ... 
    end; 

var 
    ParamData: TEnumWindowsData; 
begin 
    ParamData.ProcessId := RunApp('cmd.exe /C D:\TMP\TEST.exe'); 
    ParamData.WinHandle := 0; 
    ParamData.List := Memo1.Lines; 
    EnumWindows(@FindWindow, THandle(@ParamData)); 

    FWindowHandle := ParamData.WinHandle; 
end; 
+0

@Tlama - धन्यवाद, उत्कृष्ट! यह 'CreateProcess' के बाद' स्लीप (50) 'के साथ मेरे लिए काम करता है। – Branko

+0

ब्रैंको, यही वह है जो मुझे पसंद नहीं है। मैं कुछ और विश्वसनीय खोजने की कोशिश करूंगा और परिणाम यहां पोस्ट करूंगा। – TLama

+0

@TLama - मैं आपसे पूछना चाहता हूं कि आपने क्यों हटाया है, मेरे लिए अच्छा समाधान ('अटैचकंसोल (पीआईडी), GetConsoleWindow, FreeConsole')। आप कुछ एमएस के लिए 'नींद() 'के बारे में चिंता क्यों करते हैं? – Branko

उत्तर

10

निम्न कोड केवल प्रक्रिया (कंसोल आवेदन) बनाता है, AttachConsole समारोह से और कहा कि संलग्न कंसोल विंडो GetConsoleWindow समारोह का उपयोग कर संभाल लेता से नव निर्मित कंसोल के लिए अपनी प्रक्रिया जुड़ जाता है।

निम्न कोड की सबसे बड़ी कमजोरी यह है कि CreateProcess फ़ंक्शन तुरंत उस समय लौटाता है, जब कंसोल अभी तक पूरी तरह से प्रारंभ नहीं होता है और जब आप तुरंत कंसोल को संलग्न करने का प्रयास करते हैं, तो आप असफल हो जाएंगे। दुर्भाग्यवश, WaitForInputIdle फ़ंक्शन for console applications फ़ंक्शन नहीं है, इसलिए एक संभावित कामकाज के रूप में मैं कंसोल को कुछ सीमित लूप गणना में संलग्न करने का प्रयास चुनता हूं और एक बार यह सफल होने के बाद, हैंडल प्राप्त करें और कंसोल को अलग करें।

कोड में जो इस तरह दिख सकता है। RunApp फ़ंक्शन को कंसोल विंडो के हैंडल को वापस करना चाहिए (मान लीजिए कि आप केवल कंसोल एप्लिकेशन चलाएंगे), और लगभग प्रतीक्षा करनी चाहिए। कंसोल एप्लिकेशन के लिए 1 सेकंड आप अनुलग्नक होना शुरू कर दिया है। आप Attempt वैरिएबल के प्रारंभिक मान को बदलकर और/या Sleep अंतराल को बदलकर इस मान को संशोधित कर सकते हैं।

function GetConsoleWindow: HWND; stdcall; 
    external kernel32 name 'GetConsoleWindow'; 
function AttachConsole(dwProcessId: DWORD): BOOL; stdcall; 
    external kernel32 name 'AttachConsole'; 

function RunApp(const ACmdLine: string): HWND; 
var 
    CmdLine: string; 
    Attempt: Integer; 
    StartupInfo: TStartupInfo; 
    ProcessInfo: TProcessInformation; 
begin 
    Result := 0; 
    FillChar(StartupInfo, SizeOf(TStartupInfo), 0); 
    FillChar(ProcessInfo, SizeOf(TProcessInformation), 0); 
    StartupInfo.cb := SizeOf(TStartupInfo); 
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW; 
    StartupInfo.wShowWindow := SW_SHOWNORMAL; 
    CmdLine := ACmdLine; 
    UniqueString(CmdLine); 
    if CreateProcess(nil, PChar(CmdLine), nil, nil, False, 
    CREATE_NEW_CONSOLE, nil, nil, StartupInfo, ProcessInfo) then 
    begin 
    Attempt := 100; 
    while (Attempt > 0) do 
    begin 
     if AttachConsole(ProcessInfo.dwProcessId) then 
     begin 
     Result := GetConsoleWindow; 
     FreeConsole; 
     Break; 
     end; 
     Sleep(10); 
     Dec(Attempt); 
    end; 
    CloseHandle(ProcessInfo.hThread); 
    CloseHandle(ProcessInfo.hProcess); 
    end; 
end; 

फिर आप उदा।

procedure TForm1.Button1Click(Sender: TObject); 
var 
    S: string; 
    ConsoleHandle: HWND; 
begin 
    ConsoleHandle := RunApp('cmd.exe'); 
    if ConsoleHandle <> 0 then 
    begin 
    S := 'Hello! I''m your console, how can I serve ?'; 
    SendTextMessage(ConsoleHandle, WM_SETTEXT, 0, S); 
    end; 
end; 
+0

धन्यवाद, दुर्भाग्य से मैं स्वीकार किए गए दो उत्तरों को चिह्नित नहीं कर सकता। और मेरे प्रश्न को बेहतर, अधिक स्पष्ट रूप से तैयार करने के लिए भी धन्यवाद। बुरी अंग्रेजी के साथ यह हमारी समस्या है। – Branko

+0

मुझे आपका उत्तर स्वीकार करना होगा क्योंकि यह मुझे अप्रत्यक्ष रूप से समझाता है कि मेरा कोड क्यों काम नहीं करता था। मैंने 'CreateProcess' के तुरंत बाद विंडोज़ की गणना की थी - लेकिन बटन क्लिक करने के बाद बाद में बुम्मी, और यही कारण है कि उसका कोड हमेशा काम करता है। अगर मैं 'CreateProcess' के बाद' स्लीप (50) 'डालता हूं तो मेरा कोड भी काम करता है :) – Branko

+1

' ProcessInfo.hProcess' और 'ProcessInfo.hTread 'बंद हो सकता है शायद? –

5

-Creating सांत्वना प्रक्रिया

-find प्रक्रिया

पाया कंसोल विंडो के सेट शीर्षक

की खिड़की: अपने lauched आवेदन की एक कंसोल विंडो का शीर्षक इस तरह से बदल

- कंसोल

unit Unit3; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    private 
    PID: DWORD; 
    public 
    { Public-Deklarationen } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    AProgram: String; 
    StartupInfo: TStartupInfoW; 
    ProcessInfo: TProcessInformation; 
begin 
    AProgram := 'cmd /K Dir C:\temp'; // using /K for keeping console alive 
    UniqueString(AProgram);    // ensure that AProgram is writeable by API 
    ZeroMemory(@StartupInfo, SizeOf(StartupInfo)); // create minimum startup info 
    StartupInfo.cb := SizeOf(StartupInfo); 
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW; 
    StartupInfo.wShowWindow := SW_SHOW; 
    if CreateProcess(nil, PChar(AProgram), nil, nil, False, // Create Consoleprocess 
    CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, 
    ProcessInfo) then 
    try 
     PID := ProcessInfo.dwProcessId; // Store ProcessId to PID 
    finally 
     // close not longer required handles 
     Showmessage(IntToStr(Integer(CloseHandle(ProcessInfo.hProcess)))); 
     Showmessage(IntToStr(Integer(CloseHandle(ProcessInfo.hThread)))); 
    end; 
end; 

type 
    PEnumInfo = ^TEnumInfo; 
    TEnumInfo = record ProcessID: DWORD; HWND: THandle; end; 

function EnumWindowsProc(Wnd: DWORD; var EI: TEnumInfo): BOOL; stdcall; 
var 
    PID: DWORD; 
begin 
    GetWindowThreadProcessID(Wnd, @PID); // get processID from WND of Enumeration 
    // continue EnumWindowsProc if found PID is not our wished, visible and enabled processID (EI.ProcessID) 
    Result := (PID <> EI.ProcessID) or (not IsWindowVisible(WND)) or 
    (not IsWindowEnabled(WND)); 
    if not Result then // WND found for EI.ProcessID 
    EI.HWND := WND; 
end; 

function FindMainWindow(PID: DWORD): DWORD; 
var 
    EI: TEnumInfo; 
begin 
    //Store our processID and invalid Windowhandle to EI 
    EI.ProcessID := PID; 
    EI.HWND := 0; 
    EnumWindows(@EnumWindowsProc, Integer(@EI)); 
    Result := EI.HWND; 
end; 

function AttachConsole(dwProcessId: DWORD): BOOL; stdcall; 
    external kernel32 name 'AttachConsole'; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    Wnd: HWND; 
    S: String; 
begin 
    if PID <> 0 then // do we have a valid ProcessID 
    begin 
    Wnd := FindMainWindow(PID); 
    if Wnd <> 0 then // did we find the window handle 
    begin 
     S := 'Test'; 
     // change caption of found window 
     SendMessage(Wnd, WM_SETTEXT, 0, LPARAM(@S[1])); 
     if AttachConsole(PID) then // are we able to attach to console of our proecess? 
     begin 
     Writeln('Here we are'); // write to attached console 
     FreeConsole; // free if not longer needed 
     end; 
    end; 
    end; 
end; 

end. 
+0

धन्यवाद, आपका कोड ठीक काम करता है !! मुझे देखना होगा कि मेरे कोड में क्या गड़बड़ है :) – Branko

+2

अगर मैं यह कर रहा हूं और यह क्यों लिखा गया है, तो इसके बारे में अधिक व्याख्यात्मक पाठ होने पर मैं इसे वोट दूंगा। सुधार के लिए –

+1

@TLama धन्यवाद। मारजन वेनेमा मैं बाद में कुछ जानकारी जोड़ूंगा। मैं अब जल्दी कर रहा हूँ, क्षमा करें ... – bummi

संबंधित मुद्दे