Получение сообщения Windows на C # от управляемого Dll с помощью p / invoke - PullRequest
1 голос
/ 10 октября 2011

Мне нужно вызывать некоторые родные функции C из C #, используя p / invoke. До сих пор у меня не было проблем с маршалингом различных методов и структур на C #. Моя проблема заключается в том, что многие методы, которые я должен вызывать, являются асинхронными и возвращают свои окончательные результаты в мое приложение WinForms через сообщения Windows. Например, у меня есть вызов метода, который имеет следующую подпись в C:

HRESULT AsyncOpenSession( LPSTR lpszLogicalName,
          HANDLE hApp,
          LPSTR lpszAppID,
          DWORD dwTraceLevel,
          DWORD dwTimeOut,
          USHORT lphService,
          HWND hWnd,
          DWORD dwSrvcVersionsRequired,
          LPWFSVERSION lpSrvcVersion,
          LPWFSVERSION lpSPIVersion,
          ULONG lpRequestID );

Где lpszAppID ожидает получить ИМЯ моего приложения (MyApp.exe), а hWnd - указатель на РУЧКУ ОКНА моего приложения, которую я получаю при вызове

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public static IntPtr GetCurrentWindowHandle()
{
    IntPtr handle = GetForegroundWindow();
    return handle;
}

Импортированная подпись:

[DllImport("MSXFS.DLL", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int AsyncOpenSession([MarshalAs(UnmanagedType.LPStr)] string lpszLogicalName,
                                       IntPtr hApp,
                                       [MarshalAs(UnmanagedType.LPStr)] string lpszAppID,
                                       UInt32 dwTraceLevel,
                                       UInt32 dwTimeOut,
                                       out Int32 lphService,
                                       IntPtr hWnd,
                                       UInt32 dwSrvcVersionsRequired,
                                       out WFSVersion lpSrvcVersion,
                                       out WFSVersion lpSPIVersion,
                                       out Int32 lpRequestID); 

Я вызываю метод следующим образом:

Int32 r = AsyncOpenSession(lpszLogicalName,
                               appHanlder,
                               "MyApp.exe",
                               dwTraceLevel,
                               dwTimeOut,
                               out hServ,
                               GetCurrentWindowHandle(),
                               dwSrvcVersionsRequired,
                               out srvcVersion,
                               out spiVersion,
                               out requestID);

Первоначально вызов метода возвращает код результата, который указывает, что запрошенный вызов был помещен в очередь выполнения. В любое время после исходного вызова нативный Dll завершает выполнение запроса и отправляет сообщение Windows приложению с помощью своего дескриптора окна и имени. Код сообщения Windows для этого метода определяется следующим образом:

#define WM_USER               0x0400
#define OPEN_SESSION_COMPLETE (WM_USER + 1)

Подробнее о сообщениях Windows здесь: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644931(v=vs.85).aspx

В моем приложении я переопределил метод WndProc, чтобы иметь возможность управлять сообщениями Windows следующим образом:

protected override void WndProc(ref Message m)
{
    const int wm_user = 0x0400;
    const int OPEN_SESSION_COMPLETE = wm_user + 1;

    switch (m.Msg)
    {
        case OPEN_SESSION_COMPLETE:
        txtEventsState.Text = m.ToString();
        break;
    }
    base.WndProc(ref m);
}

Но я никогда не получаю сообщение Windows с этим кодом. Там нет ошибок в журналах или просмотра событий. Я знаю, что мой вызов метода завершился успешно, потому что я не получаю никакого кода ошибки и потому что обязательно иметь открытый сеанс перед вызовом других методов, и я могу вызывать другие методы, которым требуется обработчик сеанса успешно (без кода ошибки).

Моя импортированная подпись и вызов метода находятся в проекте библиотеки классов, на который ссылается мое приложение. Я что-то здесь не так делаю? Кто-нибудь может пролить свет на то, что может происходить? У меня нет доступа к нативному коду, просто тестовое приложение показывает, что сообщения Windows отправляются нативным C Dll.

Спасибо всем заранее.

1 Ответ

2 голосов
/ 26 октября 2011

Итак, вот в чем дело: GetForegroundWindow () не получает правильный дескриптор окна.Бывает, что у моего приложения есть два окна.Одна - это основная форма, которую я использую для своего теста, а другая отображает все результаты и ведение журналов, которые я делаю.Таким образом, метод фактически возвращал дескриптор окна входа в систему, а не окна формы.

Использование this.Handle и передача этого значения нативным методам заставляли все работать правильно.

Спасибо Гансу за указание на это.

...