将WM#U发送到靠近C#应用程序的位置会产生意想不到的效果

将WM#U发送到靠近C#应用程序的位置会产生意想不到的效果,c#,c++,winapi,sendmessage,C#,C++,Winapi,Sendmessage,在使用WM#U CLOSE消息关闭C#应用程序时,我遇到了意外行为。在我的场景中,我需要确保C#应用程序在其MSI安装包运行时关闭。MSI没有相应的操作,因此我正在编写一个自定义操作DLL,它嵌入到MSI包中,并公开EnsureApplicationClosed函数。下面是DLL的相关代码: #include "stdafx.h" #include <iostream> #include <vector> #include <string> #include

在使用WM#U CLOSE消息关闭C#应用程序时,我遇到了意外行为。在我的场景中,我需要确保C#应用程序在其MSI安装包运行时关闭。MSI没有相应的操作,因此我正在编写一个自定义操作DLL,它嵌入到MSI包中,并公开EnsureApplicationClosed函数。下面是DLL的相关代码:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include "TlHelp32.h"

std::vector<DWORD> processesList;

//This method is the main point of interest
BOOL CALLBACK enumWindowsProc(__in HWND hWnd, __in LPARAM lParam)
{
    if(processesList.size()==0) return FALSE;
    DWORD processId;
    GetWindowThreadProcessId(hWnd, &processId);
    int index=0;
    while(index<processesList.size())
    {
        if(processesList.at(index)==processId)
        {
            //Remove process id from the list
            processesList.erase(processesList.begin()+index);
            //Should close main windows of the process found.
            SendMessage(hWnd, WM_CLOSE, (LPARAM)0, (WPARAM)0);
        }
        else
        {
            index++;
        }
    }
    return TRUE;
}
std::vector<DWORD> FindProcessesId(const LPCWSTR processName)
{
    std::vector<DWORD> result;

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

    HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if ( processesSnapshot == INVALID_HANDLE_VALUE ) return result;

    Process32First(processesSnapshot, &processInfo);
    if (wcscmp(processName, processInfo.szExeFile)==0)
    {
        result.push_back(processInfo.th32ProcessID);
    }

    while ( Process32Next(processesSnapshot, &processInfo) )
    {
        if ( wcscmp(processName, processInfo.szExeFile)==0 )
        {
            result.push_back(processInfo.th32ProcessID);
        }
    }

    CloseHandle(processesSnapshot);
    return result;
}
void InnerEnsureApplicationClosed(const LPCWSTR processName)
{
    processesList=FindProcessesId(processName);
    BOOL enumeratingWindowsSucceeded = ::EnumWindows( enumWindowsProc, NULL );
}
//Function exported by the DLL
UINT __stdcall EnsureApplicationClosed ( MSIHANDLE hModule )
{
    InnerEnsureApplicationClosed(L"SomeApplication.exe");
    return ERROR_SUCCESS;
}
我使用SendMessage(hWnd,WM#u CLOSE,(LPARAM)0,(WPARAM)0)来关闭C#应用程序。当收到此WM#U close消息时,需要检查TaskManager关闭原因才能关闭,因为我发现SendMessage(hWnd,WM#U close,(LPARAM)0,(WPARAM)0)在C#应用程序中生成TaskManager关闭原因。Console.Beep()用于测试生成声音信号,以便我可以听到输入了处理程序代码

问题是,只有当我第二次运行DLL测试应用程序时,这种方法才有效。当我第一次运行测试应用程序时,我听不到声音信号,C#进程仍在任务管理器中。因此,不会触发C#应用程序的FormClosing事件。我试图用PostMessage替换SendMessage,但没有成功。GetLastError()在这两种情况下始终返回18。是否有人面临同样的问题,并且知道如何解决它


提前感谢。

玩了一整天之后,我找到了出现此问题的原因。自定义操作DLL正常。问题来自.NET ListView控件。若窗体的Visible属性在显示的事件处理程序中设置为false,并且窗体上有ListView控件,那个么它将对第一次从另一个应用程序发送的WM_CLOSE消息免疫。WndProc方法中不显示WM_CLOSE。我已经通过覆盖表单的SetVisibleCore解决了这个问题,但无论如何,这个问题看起来很奇怪,似乎是.NET中的一个错误。

Windows Installer检测应用程序是否正在运行(XP和更高版本),并通过发送
WM\u close
提示关闭它(在Win7上看到,可能是Vista和更高版本上看到的)。此行为可能取决于Windows Installer的版本,而不是Windows。我想您可以编写MSI脚本来静默地执行此操作,而不是自定义DLL。当像这样发送
WM\u CLOSE
时,接收应用程序总是得到
CloseReason.TaskManagerClosing
。我对Windows Installer不是很有经验,但在谷歌搜索我的任务时,大多数建议都是创建一个自定义操作,作为这类事情的纯粹方式。它适用于具有可见窗口的普通应用程序。
#include "stdafx.h"
#include <SomeApplicationCustomActions.h>

int _tmain(int argc, _TCHAR* argv[])
{
    EnsureApplicationClosed(NULL);
    return 0;
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
   Console.Beep();
   if (e.CloseReason != CloseReason.WindowsShutDown && e.CloseReason!= CloseReason.TaskManagerClosing)
   {
       e.Cancel = true;
       this.Hide();
   }
}