2014-09-12 2 views
0

하나의 창 인스턴스 만 실행하는 동안 문제가 발생합니다.C++ ShowWindow를 사용하여 창을 복원하면 최소화 기능이 비활성화됩니다.

구현 세부 정보 : 나는 작업 표시 줄에 아이콘으로 표시되는 C++ 응용 프로그램이 있습니다. 아이콘의 double-clik에서 ShellExecuteW 함수를 사용하여 새 델파이 창을 여는 중입니다. 이제는 사용자가 아이콘을 두 번 클릭 할 때마다 창 하나의 인스턴스 만 열어 여러 개의 창을 열지 않아도된다는 논리를 구현했습니다. 사용자가 아이콘을 두 번 클릭하고 이미 열린 창이있는 경우 창을 맨 앞에 가져 오거나 창이 최소화되면 창을 복원합니다.

///////////////////////Double Click Code starts///////////////////////// 
HWND hWnd = NULL; 
HWND hWndFirst = NULL; 
DWORD dw = FindProcessId("abc.exe"); 
if(dw == 0) 
{ 
    //Open new window 
    ShellExecuteW(0, L"open", acExePath, acParams, acFullPath, SW_SHOW); 
    hWndFirst = NULL; 
} 
else 
{ 
    //Open existing window 
    hWnd = hGetWindowHandleOfProcess(dw); 
    if(hWndFirst == NULL) hWndFirst = hWnd; 

    if(hWndFirst != hWnd) 
    { 
    //This is just a small work-around as minimizing the window was changing 
    //it's window handle. So I preserve the window handle the first time and 
    //use it whenever the window is minimized (i.e. the handle is changed) 
    SetForegroundWindow(hWndFirst); 
    ShowWindow(hWndFirst, SW_RESTORE); 
    } 
    else 
    { 
    SetForegroundWindow(hWnd); 
    ShowWindow(hWnd, SW_RESTORE); 
    } 
} 
///////////////////////Double Click Code ends/////////////////////////// 

///////////////////////Supporting functions///////////////////////// 
struct ProcessHandleData 
{ 
    unsigned long lProcessId; 
    HWND hProcessWindowHandle; 
}; 
//Finds the process id when given the process name 
DWORD FindProcessId(char* pcProcessName) 
{ 
    char* pcBegin = strrchr(pcProcessName, '\\'); 
    if(pcBegin) 
     pcProcessName = pcBegin+1; 

    PROCESSENTRY32 sProcessInfo; 
    sProcessInfo.dwSize = sizeof(sProcessInfo); 

    HANDLE sProcessesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 
    if (sProcessesSnapshot == INVALID_HANDLE_VALUE) 
     return 0; 

    Process32First(sProcessesSnapshot, &sProcessInfo); 
    if (!strcmp(pcProcessName, sProcessInfo.szExeFile)) 
    { 
     CloseHandle(sProcessesSnapshot); 
     return sProcessInfo.th32ProcessID; 
    } 

    while (Process32Next(sProcessesSnapshot, &sProcessInfo)) 
    { 
     if (!strcmp(pcProcessName, sProcessInfo.szExeFile)) 
     { 
      CloseHandle(sProcessesSnapshot); 
      return sProcessInfo.th32ProcessID; 
     } 
    } 
    CloseHandle(sProcessesSnapshot); 
    return 0; 
} 

//Search predicate for EnumWindows function  
BOOL CALLBACK bEnumWindowsSearcher(HWND handle, LPARAM lParam) 
{ 
    ProcessHandleData& sProcesshandleData = *(ProcessHandleData*)lParam; 
    unsigned long lProcessId = 0; 
    GetWindowThreadProcessId(handle, &lProcessId); 
    if (sProcesshandleData.lProcessId != lProcessId) 
     return true; 
    sProcesshandleData.hProcessWindowHandle = handle; 
    return false; 
} 

//Gets the window handle of the process (input process id) 
HWND hGetWindowHandleOfProcess(unsigned long lProcessId) 
{ 
    ProcessHandleData sProcessHandleData; 
    sProcessHandleData.lProcessId = lProcessId; 
    sProcessHandleData.hProcessWindowHandle = 0; 
    EnumWindows(bEnumWindowsSearcher, (LPARAM)&sProcessHandleData); //enumerate all windows 
    return sProcessHandleData.hProcessWindowHandle; 
} 

문제 :가 위의 코드가 제대로 작동 코드 아래

는이 아이콘을 두 번 클릭하면 트리거, 나는 위의 로직을 구현하는 방법을 보여줍니다. 하지만 내가 직면하고있는 한 가지 문제가 있습니다. 열려있는 창이 활성 상태가 아니거나 창 뒤에있는 경우 위 코드는 예상 한대로 앞으로 가져옵니다. 그러나 창을 최소화하고 아이콘을 두 번 클릭하면 창을 복원하고 앞으로 다시 가져옵니다. 그러나이 작업을 수행 한 후에는 창 오른쪽 상단의 최소화 막대를 사용하여 창을 최소화 할 수 없습니다. 무언가가 (물리적으로가 아니라) 윈도우의 최소화 막대를 비활성화합니다.

Ay 도움말은이 점에 대해 크게 감사하겠습니다. 문제와 관련하여 추가 정보가 필요한 경우 알려 주시기 바랍니다.

감사합니다.

추신 : 위의 코드는 완전히 광산이 아닙니다. 다양한 웹 사이트를 조사하여 문제의 다양한 부분에 대한 코드를 얻었습니다.

답변

2

문제의 근본 원인은 잘못된 프로세스 내에서 이전 창을 잘못된 방식으로 복원하고 있다는 것입니다. 그렇게하면 이전 창 상태가 동기화되지 않아 최소화가 작동하지 않는 이유가됩니다.

대신 새 인스턴스가 사용자 지정 창 메시지 (또는 선택한 다른 IPC 형식)를 이전 인스턴스로 보낼 수 있도록 응용 프로그램을 디자인하고 이전 인스턴스가 Application->Restore()SetForegroundWindow()을 사용할 수 있도록 해당 메시지에 대한 응답으로 제대로 복원 할 수 있습니다.

또한 전체 프로세스 열거 논리는 과도한 과장입니다.

더이 대신 같은 것을보십시오 : abc.exe의 내부 그리고

const UINT uiMyMsg = RegisterWindowMessage(TEXT("MY_RESTORE_MSG")); 
... 

if (!FindProcessId("abc.exe")) 
{ 
    //Open new window 
    ShellExecuteW(0, L"open", acExePath, acParams, acFullPath, SW_SHOW); 
} 
else 
{ 
    if (uiMyMsg != 0) 
     PostMessage(HWND_BROADCAST, uiMyMsg, 0, 0); 
} 

을, 같은 것을 할 :

const UINT uiMyMsg = RegisterWindowMessage(TEXT("MY_RESTORE_MSG")); 

__fastcall TMainForm::TMainForm(TComponent *Owner) 
    : TForm(Owner) 
{ 
    Application->HookMainWindow(&AppHook); 
} 

__fastcall TMainForm::~TMainForm() 
{ 
    Application->UnhookMainWindow(&AppHook); 
} 

bool __fastcall TMainForm::AppHook(TMessage &Message) 
{ 
    if ((Message.Msg == uiMyMsg) && (uiMyMsg != 0)) 
    { 
     ShowMe(); 
     return true; 
    } 
    return false; 
} 

void __fastcall TMainForm::WndProc(TMessage &Message) 
{ 
    if ((Message.Msg == uiMyMsg) && (uiMyMsg != 0)) 
     ShowMe(); 
    else 
     TForm::WndProc(Message); 
} 

void __fastcall TMainForm::ShowMe() 
{ 
    Application->Restore(); 
    if (WindowState == wsMinimized) 
     WindowState = wsNormal; 
    Show(); 
    SetForegroundWindow(Handle); 
} 
+0

감사 레미는, 그러나 RegisterWindowMessage abc.exe 델파이에서 음의 값을 반환합니다. 현재 왜 그런 일이 일어나고 있는지 조사 중입니다. – skmic

+0

'RegisterWindowMessage()'는 '부호없는 정수'를 반환하므로 ** 음수 값을 반환 할 수 없습니다. 값을'UINT' 또는 적어도'LongWord'가 아닌 'Integer'에 할당해야합니다. –

+0

그래, 알아 냈어. 이렇게 깨끗한 솔루션을 제공해 주셔서 다시 한 번 감사드립니다. – skmic

관련 문제