Winapi P/Invoke 콜백 함수 실행

SetWinEventHook와 같은 파라미터에 콜백 함수를 받는 Winapi P/Invoke 함수가 작동되지 않는 문제가 있습니다.
(SetWinEventHook 함수 설명 : SetWinEventHook function (winuser.h) - Win32 apps | Microsoft Learn)

생성자와 같은 메소드 안에 SetWinEventHook 메소드를 집어넣을 때는 원할 때 마다 콜백 함수가 제대로 작동하는 데

그 외 일반 코드에서는 작동되지 않는데 이걸 어떻게 해결할 수 있는지 해메고 있습니다.

[DllImport("user32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc,
  [MarshalAs(UnmanagedType.FunctionPtr)] WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, WinEventFlags dwFlags);

// import 한 P/Invoke 함수

public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{

}

// 실행되야하는 콜백 함수

public MyApp()
{
  var MFCLibGridCtrl = AutomationElement.RootElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "MFCLibGridCtrl"));
    var MFCLibProcess = Process.GetProcessById(MFCLibGridCtrl.Current.ProcessId);

    WindowControlService.WinEventDelegate winEventDelegate = new WindowControlService.WinEventDelegate(WinEventProc);
    GCHandle.Alloc(winEventDelegate);

    WindowControlService.SetWinEventHook(
      0x7, 0x8,
      IntPtr.Zero,
      winEventDelegate,
      MFCLibProcess.Id, 0,
      WindowControlService.WinEventFlags.WINEVENT_OUTOFCONTEXT);
}

// 생성자에서는 콜백 함수를 제대로 불러옴

ILogic iLogic = new Logic();
iLogic.Execute();

public async Task Execute()
{
var MFCLibGridCtrl = AutomationElement.RootElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "MFCLibGridCtrl"));
    var MFCLibProcess = Process.GetProcessById(MFCLibGridCtrl.Current.ProcessId);

    WindowControlService.WinEventDelegate winEventDelegate = new WindowControlService.WinEventDelegate(WinEventProc);
    GCHandle.Alloc(winEventDelegate);

    WindowControlService.SetWinEventHook(
      0x7, 0x8,
      IntPtr.Zero,
      winEventDelegate,
      MFCLibProcess.Id, 0,
      WindowControlService.WinEventFlags.WINEVENT_OUTOFCONTEXT);
}

// 여기서는 제대로 콜백 함수가 작동되지 않음
2개의 좋아요

WinEventDelegate 타입의 코드가 어떻게 작성되어있는지 알 수 없지만, 우선 확인해보셔야 할 부분이 UnmanagedFunctionPointerAttribute를 잘 지정하셨고, 정확한 Calling Convention을 맞춰서 지정했는지 여부를 먼저 확인해보셔야 할 것 같습니다.

DllImportAttribute를 쓸 때와 마찬가지로 대리자 포인터의 경우에도 함수 콜 스택을 어떻게 정리할 것인지 서로 규약을 맞추어야 합니다. 정확한 것은 Windows SDK 헤더의 선언을 확인해보시는 것이 좋습니다.

참고: How to pass function pointer from C# to a C++ Dll? - Stack Overflow

그리고 네이티브 코드에서 매니지드 코드를 부를 때 주의하셔야 하는 또 다른 부분은, 매니지드 코드 측의 인스턴스는 언제든 가비지 컬렉터에 의하여 소거될 수 있다는 점입니다. 이를 방지하기 위해서 인스턴스의 호출 주기를 잘 관리해서 네이티브 코드가 매니지드 코드의 콜백을 항상 성공적으로 부를 수 있게 잘 관리해주셔야 합니다.

3개의 좋아요

Delegate 타입은 다음과 같이 헤더 없이 이렇게 선언했습니다.

public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

헤더에 어떤 걸 붙이는 게 적절할까요?

1개의 좋아요

말씀해주신 API에 관해서 좀 더 찾아보니 이런 설명이 있네요.

For out-of-context events, the event is delivered on the same thread that called SetWinEventHook.

보여주신 WinEventDelegate를 사용하는 다른 코드에서 특별히 P/Invoke에서 맞춰줘야 할 부분은 없어보이는 것 같습니다.

아래 Stack Overflow의 질답 내용이 문제 해결에 도움이 되실지 한 번 검토해보시면 좋을 것 같네요.

참고: pinvoke - C# SetWinEventHook fails (returns 0) - Stack Overflow

1개의 좋아요