본문 바로가기
C++

ProcessID로 Handle 찾기 및 WM_COPYDATA 처리 문제

by leo21c 2021. 4. 12.

IPC를 할 때 다양한 방법이 있지만 WM_COPYDATA를 사용한 윈도우Q에 SendMessage를 보내는 방식이 있다.

간단하고 쉬워서 많이 사용을 한다.

WM_COPYDATA를 이용해서 C#, MFC 등 다른 개발 언어로 통신을 하는 경우도 많다.

이번에 C# <-> MFC 프로그램간에 SendMessage를 보내는데 잘 안되는 문제가 발생했다.

 

C#에서 RunExecute로 MFC 프로그램을 실행하고 C# 앱의 ProcessID를 전달받아 MFC에서는 ProcessID로 핸들을 찾고 다시 SendMessage를 보내는 방식이다.

 

MFC에서 아래와 같은 방식으로 핸들을 구했다.

//Get Device Manage HWND
HWND m_hwndDeviceMan = NULL;
HWND m_tHwnd = NULL;
DWORD dwProcessID = _ttoi(m_strProcessName);//m_strProcessName: ProcessID string
do 
{
    m_tHwnd = FindWindowEx (NULL, m_tHwnd, NULL, NULL);
    DWORD dwPID = 0;
    GetWindowThreadProcessId (m_tHwnd, &dwPID);
    if (dwPID == dwProcessID)
    {
      m_hwndDeviceMan = m_tHwnd;
      break;
    }
}
while (m_tHwnd != NULL);

위와 같이 처리를 했는데 찾은 Hwnd로 SendMessage를 보냈는데 C#에서 WM_COPYDATA로 받지는 못하는 것이다.

원인을 확인해 보니 찾은 윈도우 핸들이 최상위 윈도우 핸들이 아니고 하위 윈도우 핸들이었던 것이다.

 

ProcessID를 가지고 Window Handle을 찾을 때 그 Handle이 어떤 윈도우의 핸들인지 정확하게 알아야 한다.

아니면 최소한 Main Window handle을 찾아야 한다.

그래서 검색을 해서 찾은 방식이 아래와 같은 방식이다.

struct handle_data {
    unsigned long process_id;
    HWND window_handle;
};

BOOL is_main_window(HWND handle)
{
    return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}

BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
    handle_data& data = *(handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data.process_id != process_id || !is_main_window(handle))
        return TRUE;
    data.window_handle = handle;
    return FALSE;
}

HWND find_main_window(unsigned long process_id)
{
    handle_data data;
    data.process_id = process_id;
    data.window_handle = 0;
    EnumWindows(enum_windows_callback, (LPARAM)&data);
    return data.window_handle;
}
DWORD dwProcessID = _ttoi(m_strProcessName);
HWND m_hwndDeviceMan = find_main_window(dwProcessID);

위와 같은 방식으로 Window Handle을 찾아서 사용을 하니 문제가 해결이 되었다.

이런 문제로 ProcessID를 전달하는 것보다는 Window Handle을 전달해서 바로 SendMessage를 보낼 수 있도록 하는 것이 좋을 것 같다.