A certain engineer "COMPLEX"

開発メモ その128 子プロセスに対してWM_CLOSEを送る

Introduction


備忘録。
C++/C#の連携で、C++アプリから起動したC#アプリを、C++アプリから正常終了させる方法。
基本は、

  1. CreateProcessの戻りのプロセスIDを保持
  2. 終了させる際、プロセスIDからウィンドウハンドルを取得
  3. PostMessageでWM_CLOSEを送る

です。

ソースは下記になります

Sample source code for Demonstration, Experiment and Test - takuya-takeuchi/Demo

Demo


C++


#include "stdafx.h"

HWND GetWindowHandle(const DWORD target_id)
{
auto hWnd = GetTopWindow(nullptr);
do {
if (GetWindowLong(hWnd, GWLP_HWNDPARENT) != 0 || !IsWindowVisible(hWnd))
continue;

DWORD process_id;
GetWindowThreadProcessId(hWnd, &process_id);
if (target_id == process_id)
return hWnd;
} while ((hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) != nullptr);

return nullptr;
}

int main()
{
// Launch application
STARTUPINFO si;
PROCESS_INFORMATION pi;
::ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
::CreateProcessW(L"Wpf.exe", nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);

_tprintf(_T("Terminate application: %d\n"), pi.dwProcessId);

// Wait until application completely starts to create window handle
Sleep(1000);
auto handle = GetWindowHandle(pi.dwProcessId);
::PostMessage(handle, WM_CLOSE, 0, 0);

// Terminate forcibly if application does not quit in 5sec.
if (::WaitForSingleObject(pi.hProcess, 5000) == WAIT_TIMEOUT)
{
_tprintf(_T("Terminate forcibly"));
TerminateProcess(pi.hProcess, 0);
}

::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);

return 0;
}

GetWindowHandleで、プロセスIDからウィンドウハンドルを探し出しているのが肝です。
そして、このサンプルではプロセス起動後、Sleepで少し待機しています。
そうしないと、ウィンドウハンドルが取れないので...
コメントにも書いたように、おそらくウィンドウハンドルが生成され切っていないのかと。

C#

WPFのサンプルです。
コードビハインドですが、気にしません。


using System;
using System.Windows;
using System.Windows.Interop;
namespace Wpf
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{

public MainWindow()
{
InitializeComponent();
this.Loaded += this.WindowLoaded;
}

private void WindowLoaded(object sender, RoutedEventArgs e)
{
var source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source?.AddHook(WndProc);
}

private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_CLOSE = 0x0010;
if (msg == WM_CLOSE)
{
MessageBox.Show("Get WM_CLOSE");

//handled = true;
}

return IntPtr.Zero;
}

}
}

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/KillProcessSafetyByHWND

コメントを残す

メールアドレスが公開されることはありません。

%d人のブロガーが「いいね」をつけました。