Изящно закройте приложение перед установкой через настраиваемое действие, управляемое Wix - PullRequest
2 голосов
/ 08 февраля 2011

В моем установщике WiX я хочу изящно закрыть приложение, которое должно быть обновлено, если оно все еще работает. Я не хочу предлагать пользователю закрыть и не хочу убивать процесс. Мне нужно иметь возможность выполнить некоторую очистку и т. Д. Перед закрытием приложения.

Приложение представляет собой приложение WinForms, которое запускается в системном трее. Основная форма имеет заголовок, скажем, «mainwindow», например, но она скрыта и имеет ShowInTaskbar = false.

Играя с различными приложениями-тестерами, пытаясь Process.Kill() Process.CloseMainWindow() FindWindow, SendMessage, PostMessage и т. Д., Я обнаружил, что лучший способ сделать это - использовать PostMessage

var hWnd = FindWindow(null, "mainwindowtitle");
PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

Таким образом, я могу переопределить OnFormClosing и выполнить любую необходимую очистку. Это прекрасно работает с приложением тестер, которое я бросил вместе. Проблема в том, что он не работает при запуске в установщике WiX. У меня есть c # Custom Action CA.dll, и установщик определенно вызывает настраиваемое действие - я вижу это из журналов msiexec, и если я изменяю код настраиваемого действия на Process.Kill(), это останавливает приложение правильно. Однако, когда он работает с кодом PostMessage, приложение не закрывается, и OnFormClosing никогда не вызывается.

Вот мой код CustomAction

        private const int WM_CLOSE = 0x0010;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [CustomAction]
    public static ActionResult CloseApplicationGracefully(Session session)
    {
        session.Log("Starting the CloseApplicationGracefully Custom Action - attempting to stop DUC.");

        var hWnd = FindWindow(null, "mainwindowtitle");

        session.Log("Window handle found: " + hWnd);

        bool result = PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

        session.Log("Result of calling app to close: " + result);

        if (result)
        {
            return ActionResult.Success;
        }
        return ActionResult.Failure;
    }

вот код настройки wx

<Binary Id="WixCustomAction.dll"
        SourceFile="$(var.WixCustomAction.TargetDir)$(var.WixCustomAction.TargetName).CA.dll" />
<CustomAction Id="WixCustomAction"
              BinaryKey="WixCustomAction.dll"
              DllEntry="CloseDeploymentUpdater" />
<InstallExecuteSequence>
  <Custom Action="WixCustomAction" After="FindRelatedProducts"></Custom>
</InstallExecuteSequence>

Я пытался вызывать это пользовательское действие в разных последовательностях, но не повезло ... Код работает из приложения тестера, и настраиваемое действие работает, когда я использую Process.Kill, но код не работает, когда помещается в настраиваемое действие - должна быть последовательность событий?

EDIT

Использование CA WixCloseApplications, как предлагается ниже в ответе, приводит к следующим записям журнала

WixCloseApplications:  App: DUC.exe found running, 1 processes, attempting to send close message.
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x12
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x0
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x578
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x0
.
.
.
MSI (s) (C8!D4) [15:00:47:985]: PROPERTY CHANGE: Adding WixCloseApplicationsDeferred property. Its value is 'DUC.exe5'.
MSI (s) (C8!D4) [15:00:48:000]: Doing action: WixCloseApplicationsDeferred
.
.
Action 15:00:48: WixCloseApplicationsDeferred. 
Action start 15:00:48: WixCloseApplicationsDeferred.
.
.
Action ended 15:00:48: WixCloseApplicationsDeferred. Return value 1.
Action ended 15:00:48: WixCloseApplications. Return value 1.

1 Ответ

2 голосов
/ 08 февраля 2011

Если вы правильно понимаете CustomAction CloseApp из Wix, вы должны перечислить все окна в процессе.

http://wix.codeplex.com/SourceControl/changeset/view/175af30efe78#src%2fca%2fwixca%2fdll%2fCloseApps.cpp

Поэтому вам необходимо реализовать EnumWindows (EnumCallBack, HANDLE processToClose)А в EnumCallBack вы фактически отправляете сообщение WM_CLOSE для каждого окна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...