~ubuntu-branches/ubuntu/oneiric/enigmail/oneiric-updates

« back to all changes in this revision

Viewing changes to toolkit/mozapps/installer/wince/uninstall/Uninstall.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2010-04-10 01:42:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100410014224-fbq9ui5x3b0h2t36
Tags: 2:1.0.1-0ubuntu1
* First releaase of enigmail 1.0.1 for tbird/icedove 3
  (LP: #527138)
* redo packaging from scratch 
  + add debian/make-orig target that uses xulrunner provided
    buildsystem + enigmail tarball to produce a proper orig.tar.gz
  + use debhelper 7 with mozilla-devscripts
  + use debian source format 3.0 (quilt)
  + patch enigmail to use frozen API only
    - add debian/patches/frozen_api.diff
  + patch build system to not link against -lxul - which isnt
    available for sdks produced by all-static apps like tbird
    - add debian/patches/build_system_dont_link_libxul.diff
  + add minimal build-depends to control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil; -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is Fennec Installer for WinCE.
 
16
 *
 
17
 * The Initial Developer of the Original Code is The Mozilla Foundation.
 
18
 *
 
19
 * Portions created by the Initial Developer are Copyright (C) 2009
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *   Alex Pakhotin <alexp@mozilla.com> (original author)
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the MPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the MPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
/**
 
40
 *
 
41
 * Uninstall.cpp : Mozilla Fennec Uninstaller
 
42
 *
 
43
 */
 
44
 
 
45
#include <windows.h>
 
46
#include <aygshell.h>
 
47
#include <cfgmgrapi.h>
 
48
 
 
49
#include "nsSetupStrings.h"
 
50
#include "Uninstall.rh"
 
51
 
 
52
#define WM_DIALOGCREATED (WM_USER + 1)
 
53
 
 
54
const WCHAR c_sStringsFile[] = L"setup.ini";
 
55
nsSetupStrings Strings;
 
56
 
 
57
BOOL g_bRunFromSetupDll = FALSE;
 
58
 
 
59
WCHAR g_sInstallPath[MAX_PATH];
 
60
WCHAR g_sUninstallPath[MAX_PATH];
 
61
HWND g_hDlg = NULL;
 
62
 
 
63
const WCHAR c_sAppRegKeyTemplate[] = L"Software\\Mozilla\\%s";
 
64
 
 
65
const DWORD c_nTempBufSize = MAX_PATH * 2;
 
66
const WCHAR c_sRemoveParam[] = L"[remove]";
 
67
const WCHAR c_sSetupParam[] = L"[setup]";   // means executed by Setup.dll
 
68
 
 
69
// Retry counter for the file/directory deletion
 
70
int nTotalRetries = 0;
 
71
const int c_nMaxTotalRetries = 10;
 
72
const int c_nMaxOneFileRetries = 6;
 
73
const int c_nRetryDelay = 500; //milliseconds
 
74
 
 
75
int g_nDirsDeleted = 0;
 
76
const int c_nMaxDirs = 25; // approximate number of dirs just to show some progress
 
77
 
 
78
enum {
 
79
  ErrOK = 0,
 
80
  ErrCancel = IDCANCEL,
 
81
  ErrNoStrings = -1,
 
82
  ErrInstallationNotFound = -2,
 
83
  ErrShutdownFailed = -3,
 
84
};
 
85
 
 
86
int g_nResult = ErrOK;
 
87
 
 
88
// Forward declarations
 
89
BOOL GetModulePath(WCHAR *sPath);
 
90
BOOL LoadStrings();
 
91
BOOL GetInstallPath(WCHAR *sPath);
 
92
BOOL DeleteShortcut(HWND hwndParent);
 
93
BOOL DeleteDirectory(const WCHAR* sPathToDelete);
 
94
BOOL DeleteRegistryKey();
 
95
BOOL CopyAndLaunch();
 
96
BOOL ShutdownFastStartService(const WCHAR *sInstallPath);
 
97
BOOL RunSystemUninstall();
 
98
 
 
99
BOOL CALLBACK DlgUninstall(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
 
100
BOOL OnDialogInit(HWND hDlg);
 
101
BOOL OnDialogCreated(HWND hDlg);
 
102
int OnUninstall(HWND hDlg);
 
103
void UpdateProgress();
 
104
 
 
105
///////////////////////////////////////////////////////////////////////////////
 
106
// Main
 
107
//
 
108
int WINAPI WinMain(HINSTANCE hInstance,
 
109
                   HINSTANCE hPrevInstance,
 
110
                   LPTSTR    lpCmdLine,
 
111
                   int       nCmdShow)
 
112
{
 
113
  HWND hWnd = GetForegroundWindow();
 
114
  *g_sUninstallPath = 0;
 
115
 
 
116
  WCHAR *sCommandLine = GetCommandLine();
 
117
  WCHAR *sRemoveParam = wcsstr(sCommandLine, c_sRemoveParam);
 
118
  WCHAR g_bRunFromSetupDll = (wcsstr(sCommandLine, c_sSetupParam) != NULL);
 
119
  if (sRemoveParam != NULL)
 
120
  {
 
121
    // Launched from a temp directory with parameters "[remove] \Program Files\Fennec\"
 
122
    wcscpy(g_sUninstallPath, sRemoveParam + wcslen(c_sRemoveParam) + 1);
 
123
  }
 
124
  else
 
125
  {
 
126
    // Just copy this EXE and launch it from a temp location with a special parameter
 
127
    // to delete itself in the installation directory
 
128
    if (CopyAndLaunch())
 
129
      return ErrOK;
 
130
  }
 
131
  // Perform uninstallation when executed with a special parameter
 
132
  // (or in case when CopyAndLaunch failed - just execute in place)
 
133
 
 
134
  if (!LoadStrings())
 
135
  {
 
136
    MessageBoxW(hWnd, L"Cannot find the strings file.", L"Uninstall", MB_OK|MB_ICONWARNING);
 
137
    return ErrNoStrings;
 
138
  }
 
139
 
 
140
  if (GetInstallPath(g_sInstallPath))
 
141
  {
 
142
    int nDlgResult = DialogBox(hInstance, (LPCTSTR)IDD_MAIN, NULL, (DLGPROC)DlgUninstall);
 
143
    if (nDlgResult != ErrOK)
 
144
      g_nResult = nDlgResult;
 
145
  }
 
146
  else
 
147
  {
 
148
    MessageBoxW(hWnd, Strings.GetString(StrID_InstallationNotFound),
 
149
                Strings.GetString(StrID_UninstallCaption), MB_OK|MB_ICONINFORMATION);
 
150
    return ErrInstallationNotFound;
 
151
  }
 
152
 
 
153
  return g_nResult;
 
154
}
 
155
 
 
156
int Uninstall(HWND hWnd)
 
157
{
 
158
  // Remove all installed files
 
159
  DeleteDirectory(g_sInstallPath);
 
160
  DeleteShortcut(hWnd);
 
161
  DeleteRegistryKey();
 
162
 
 
163
  if (!g_bRunFromSetupDll)
 
164
    RunSystemUninstall();
 
165
 
 
166
  // TODO: May probably handle errors during deletion (such as locked directories)
 
167
  // and notify user. Right now just return OK.
 
168
  return ErrOK;
 
169
}
 
170
 
 
171
///////////////////////////////////////////////////////////////////////////////
 
172
// Dialog
 
173
//
 
174
BOOL CALLBACK DlgUninstall(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 
175
{
 
176
  switch (message)
 
177
  {
 
178
    case WM_INITDIALOG:
 
179
      return OnDialogInit(hDlg);
 
180
 
 
181
    case WM_DIALOGCREATED:
 
182
      return OnDialogCreated(hDlg);
 
183
 
 
184
    case WM_COMMAND:
 
185
      switch (LOWORD(wParam))
 
186
      {
 
187
        case IDOK:
 
188
          EndDialog(hDlg, ErrOK);
 
189
          return TRUE;
 
190
 
 
191
        case IDCANCEL:
 
192
          EndDialog(hDlg, ErrCancel);
 
193
          return TRUE;
 
194
 
 
195
        case IDC_BTN_UNINSTALL:
 
196
          g_nResult = OnUninstall(hDlg);
 
197
          return TRUE;
 
198
      }
 
199
      break;
 
200
 
 
201
    case WM_CLOSE:
 
202
      EndDialog(hDlg, ErrCancel);
 
203
      return TRUE;
 
204
  }
 
205
  return FALSE;
 
206
}
 
207
 
 
208
BOOL OnDialogCreated(HWND)
 
209
{
 
210
  ShutdownFastStartService(g_sInstallPath);
 
211
  // Just continue regardless of the result
 
212
  return TRUE;
 
213
}
 
214
 
 
215
BOOL OnDialogInit(HWND hDlg)
 
216
{
 
217
  g_hDlg = hDlg;
 
218
  PostMessage(hDlg, WM_DIALOGCREATED, 0, 0);
 
219
 
 
220
  SetWindowText(hDlg, Strings.GetString(StrID_UninstallCaption));
 
221
 
 
222
  SHINITDLGINFO shidi;
 
223
  shidi.dwMask = SHIDIM_FLAGS;
 
224
  shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_EMPTYMENU;
 
225
  shidi.hDlg = hDlg;
 
226
  SHInitDialog(&shidi);
 
227
 
 
228
  // Hide the Done button
 
229
  SHDoneButton(hDlg, SHDB_HIDE);
 
230
 
 
231
  // Init controls
 
232
  WCHAR sMsg[c_nTempBufSize];
 
233
  _snwprintf(sMsg, c_nTempBufSize, L"%s %s", Strings.GetString(StrID_FilesWillBeRemoved), g_sInstallPath);
 
234
  SetWindowText(GetDlgItem(hDlg, IDC_STATIC_TEXT), sMsg);
 
235
  SetWindowText(GetDlgItem(hDlg, IDC_QUESTION_TEXT), Strings.GetString(StrID_AreYouSure));
 
236
  SetWindowText(GetDlgItem(hDlg, IDC_BTN_UNINSTALL), L"OK"); // TODO: Use localized text "Uninstall"
 
237
  SetWindowText(GetDlgItem(hDlg, IDCANCEL), Strings.GetString(StrID_Cancel));
 
238
  ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS), SW_HIDE);
 
239
  ShowWindow(GetDlgItem(hDlg, IDOK), SW_HIDE);
 
240
 
 
241
  return TRUE; 
 
242
}
 
243
 
 
244
int OnUninstall(HWND hDlg)
 
245
{
 
246
  SetWindowText(GetDlgItem(hDlg, IDC_QUESTION_TEXT), L"");
 
247
  ShowWindow(GetDlgItem(hDlg, IDC_BTN_UNINSTALL), SW_HIDE);
 
248
  ShowWindow(GetDlgItem(hDlg, IDCANCEL), SW_HIDE);
 
249
  ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS), SW_SHOW);
 
250
  SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, (LPARAM) MAKELPARAM (0, c_nMaxDirs));
 
251
  SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETPOS, 0, 0);
 
252
 
 
253
  UpdateWindow(hDlg); // make sure the text is drawn
 
254
  
 
255
  int ret = Uninstall(hDlg);
 
256
 
 
257
  if (ret == ErrOK)
 
258
  {
 
259
    SetWindowText(GetDlgItem(hDlg, IDC_STATIC_TEXT), Strings.GetString(StrID_UninstalledSuccessfully));
 
260
  }
 
261
  else
 
262
  {
 
263
    //TODO: Localize this message. It might be shown later when the errors will be handled
 
264
    SetWindowText(GetDlgItem(hDlg, IDC_STATIC_TEXT), L"There were errors during uninstallation.");
 
265
  }
 
266
 
 
267
  ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS), SW_HIDE);
 
268
  ShowWindow(GetDlgItem(hDlg, IDOK), SW_SHOW);
 
269
 
 
270
  return ret;
 
271
}
 
272
 
 
273
void UpdateProgress()
 
274
{
 
275
  SendMessage(GetDlgItem(g_hDlg, IDC_PROGRESS), PBM_SETPOS, (WPARAM)g_nDirsDeleted, 0);
 
276
}
 
277
 
 
278
///////////////////////////////////////////////////////////////////////////////
 
279
// Utility functions
 
280
//
 
281
 
 
282
BOOL LoadStrings()
 
283
{
 
284
  // Locate and load the strings file used by installer
 
285
  if (*g_sUninstallPath == 0)
 
286
    GetModulePath(g_sUninstallPath);
 
287
 
 
288
  WCHAR sStringsFile[MAX_PATH];
 
289
  _snwprintf(sStringsFile, MAX_PATH, L"%s\\%s", g_sUninstallPath, c_sStringsFile);
 
290
 
 
291
  return Strings.LoadStrings(sStringsFile);
 
292
}
 
293
 
 
294
BOOL GetModulePath(WCHAR *sPath)
 
295
{
 
296
  if (GetModuleFileName(NULL, sPath, MAX_PATH) == 0)
 
297
    return FALSE;
 
298
 
 
299
  WCHAR *sSlash = wcsrchr(sPath, L'\\') + 1;
 
300
  *sSlash = L'\0'; // cut the file name
 
301
 
 
302
  return TRUE;
 
303
}
 
304
 
 
305
BOOL GetInstallPath(WCHAR *sPath)
 
306
{
 
307
  HKEY hKey;
 
308
  WCHAR sRegFennecKey[MAX_PATH];
 
309
  _snwprintf(sRegFennecKey, MAX_PATH, c_sAppRegKeyTemplate, Strings.GetString(StrID_AppShortName));
 
310
 
 
311
  LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sRegFennecKey, 0, KEY_ALL_ACCESS, &hKey);
 
312
  if (result == ERROR_SUCCESS)
 
313
  {
 
314
    DWORD dwType = NULL;
 
315
    DWORD dwCount = MAX_PATH * sizeof(WCHAR);
 
316
    result = RegQueryValueEx(hKey, L"Path", NULL, &dwType, (LPBYTE)sPath, &dwCount);
 
317
 
 
318
    RegCloseKey(hKey);
 
319
  }
 
320
 
 
321
  return (result == ERROR_SUCCESS);
 
322
}
 
323
 
 
324
BOOL DeleteDirectory(const WCHAR* sPathToDelete)
 
325
{
 
326
  BOOL            bResult = TRUE;
 
327
  HANDLE          hFile;
 
328
  WCHAR           sFilePath[MAX_PATH];
 
329
  WCHAR           sPattern[MAX_PATH];
 
330
  WIN32_FIND_DATA findData;
 
331
 
 
332
  wcscpy(sPattern, sPathToDelete);
 
333
  wcscat(sPattern, L"\\*.*");
 
334
  hFile = FindFirstFile(sPattern, &findData);
 
335
  if (hFile != INVALID_HANDLE_VALUE)
 
336
  {
 
337
    do
 
338
    {
 
339
      if (findData.cFileName[0] != L'.')
 
340
      {
 
341
        _snwprintf(sFilePath, MAX_PATH, L"%s\\%s", sPathToDelete, findData.cFileName);
 
342
 
 
343
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 
344
        {
 
345
          // Delete subdirectory
 
346
          if (!DeleteDirectory(sFilePath))
 
347
            bResult = FALSE;
 
348
        }
 
349
        else
 
350
        {
 
351
          // Set file attributes
 
352
          if (SetFileAttributes(sFilePath, FILE_ATTRIBUTE_NORMAL))
 
353
          {
 
354
            // Delete file
 
355
            if (!DeleteFile(sFilePath) && nTotalRetries < c_nMaxTotalRetries)
 
356
            {
 
357
              BOOL bDeleted = FALSE;
 
358
              nTotalRetries++;
 
359
              for (int nRetry = 0; nRetry < c_nMaxOneFileRetries; nRetry++)
 
360
              {
 
361
                Sleep(c_nRetryDelay);
 
362
                if (DeleteFile(sFilePath))
 
363
                {
 
364
                  bDeleted = TRUE;
 
365
                  break;
 
366
                }
 
367
              }
 
368
              if (!bDeleted)
 
369
                bResult = FALSE;
 
370
            }
 
371
          }
 
372
        }
 
373
      }
 
374
    } while (FindNextFile(hFile, &findData));
 
375
 
 
376
    // Close handle
 
377
    FindClose(hFile);
 
378
  }
 
379
 
 
380
  // Set directory attributes
 
381
  if (SetFileAttributes(sPathToDelete, FILE_ATTRIBUTE_NORMAL))
 
382
  {
 
383
    g_nDirsDeleted++;
 
384
    UpdateProgress();
 
385
    // Delete directory
 
386
    if (!RemoveDirectory(sPathToDelete) && nTotalRetries < c_nMaxTotalRetries)
 
387
    {
 
388
      BOOL bDeleted = FALSE;
 
389
      nTotalRetries++;
 
390
      for (int nRetry = 0; nRetry < c_nMaxOneFileRetries; nRetry++)
 
391
      {
 
392
        Sleep(c_nRetryDelay);
 
393
        if (RemoveDirectory(sPathToDelete))
 
394
        {
 
395
          bDeleted = TRUE;
 
396
          break;
 
397
        }
 
398
      }
 
399
      if (!bDeleted)
 
400
        bResult = FALSE;
 
401
    }
 
402
  }
 
403
 
 
404
  return bResult;
 
405
}
 
406
 
 
407
// Deletes shortcuts for Fennec and FastStart service created by the installer.
 
408
// Note: The shortcut names have to be in sync with CreateShortcut in nsInstallerDlg.cpp
 
409
BOOL DeleteShortcut(HWND hwndParent)
 
410
{
 
411
  BOOL result = FALSE;
 
412
 
 
413
  WCHAR sProgramsPath[MAX_PATH];
 
414
  if (SHGetSpecialFolderPath(hwndParent, sProgramsPath, CSIDL_PROGRAMS, FALSE))
 
415
  {
 
416
    WCHAR sShortcutPath[MAX_PATH];
 
417
    _snwprintf(sShortcutPath, MAX_PATH, L"%s\\%s.lnk", sProgramsPath, Strings.GetString(StrID_AppShortName));
 
418
 
 
419
 
 
420
    if(SetFileAttributes(sShortcutPath, FILE_ATTRIBUTE_NORMAL))
 
421
      result = DeleteFile(sShortcutPath);
 
422
  }
 
423
 
 
424
  // Handle faststart shortcut
 
425
  WCHAR sStartupPath[MAX_PATH];
 
426
  if (SHGetSpecialFolderPath(hwndParent, sStartupPath, CSIDL_STARTUP, FALSE))
 
427
  {
 
428
    WCHAR sStartupShortcutPath[MAX_PATH];
 
429
    _snwprintf(sStartupShortcutPath, MAX_PATH, L"%s\\%sFastStart.lnk", sStartupPath, Strings.GetString(StrID_AppShortName));
 
430
 
 
431
    // It may not exist - just ignore that
 
432
    if(SetFileAttributes(sStartupShortcutPath, FILE_ATTRIBUTE_NORMAL))
 
433
      DeleteFile(sStartupShortcutPath);
 
434
  }
 
435
 
 
436
  return result;
 
437
}
 
438
 
 
439
BOOL DeleteRegistryKey()
 
440
{
 
441
  WCHAR sRegFennecKey[MAX_PATH];
 
442
  _snwprintf(sRegFennecKey, MAX_PATH, c_sAppRegKeyTemplate, Strings.GetString(StrID_AppShortName));
 
443
 
 
444
  LONG result = RegDeleteKey(HKEY_LOCAL_MACHINE, sRegFennecKey);
 
445
  return (result == ERROR_SUCCESS);
 
446
}
 
447
 
 
448
// Copy to a temp directory and launch from there
 
449
BOOL CopyAndLaunch()
 
450
{
 
451
  WCHAR sNewName[] = L"\\Temp\\uninstall.exe";
 
452
  WCHAR sModule[MAX_PATH];
 
453
  if (GetModuleFileName(NULL, sModule, MAX_PATH) == 0 || !GetModulePath(g_sUninstallPath))
 
454
    return FALSE;
 
455
  if (CopyFile(sModule, sNewName, FALSE))
 
456
  {
 
457
    PROCESS_INFORMATION pi;
 
458
    WCHAR sParam[c_nTempBufSize];
 
459
    if (g_bRunFromSetupDll)
 
460
      _snwprintf(sParam, c_nTempBufSize, L"%s %s %s", c_sSetupParam, c_sRemoveParam, g_sUninstallPath);
 
461
    else
 
462
      _snwprintf(sParam, c_nTempBufSize, L"%s %s", c_sRemoveParam, g_sUninstallPath);
 
463
 
 
464
    // Launch "\Temp\uninstall.exe remove \Program Files\Fennec\"
 
465
    return CreateProcess(sNewName, sParam, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi);
 
466
  }
 
467
  else
 
468
    return FALSE;
 
469
}
 
470
 
 
471
BOOL ConvertToChar(const WCHAR *wstr, char *str, DWORD bufSize)
 
472
{
 
473
  return 0 != WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, bufSize, NULL, NULL);
 
474
}
 
475
 
 
476
BOOL ShutdownFastStartService(const WCHAR *wsInstallPath)
 
477
{
 
478
  BOOL result = TRUE;
 
479
 
 
480
  // Class name: appName + "MessageWindow"
 
481
  WCHAR sClassName[c_nTempBufSize];
 
482
  _snwprintf(sClassName, c_nTempBufSize, L"%s%s", Strings.GetString(StrID_AppShortName), L"MessageWindow");
 
483
 
 
484
  HWND handle = ::FindWindowW(sClassName, NULL);
 
485
  if (handle)
 
486
  {
 
487
    char sPath[MAX_PATH];
 
488
    ConvertToChar(wsInstallPath, sPath, MAX_PATH);
 
489
    size_t pathLen = strlen(sPath);
 
490
    if (pathLen > 0 && sPath[pathLen-1] != '\\')
 
491
    {
 
492
      strcat(sPath, "\\");
 
493
      pathLen++;
 
494
    }
 
495
 
 
496
    char sCopyData[MAX_PATH * 3];
 
497
    _snprintf(sCopyData, MAX_PATH * 2, "\"%s%S.exe\" -shutdown-faststart", sPath, Strings.GetString(StrID_AppShortName));
 
498
    size_t cmdLineLen = strlen(sCopyData);
 
499
 
 
500
    char *sRest = sCopyData + cmdLineLen + 1;
 
501
    strcpy(sRest, sPath);
 
502
 
 
503
    COPYDATASTRUCT cds = {
 
504
      1,
 
505
      pathLen + 1 + cmdLineLen,
 
506
      (void*) sCopyData
 
507
    };
 
508
    ::SendMessage(handle, WM_COPYDATA, 0, (LPARAM)&cds);
 
509
 
 
510
    // Wait until it's shut down or for some timeout
 
511
    for (int i = 0; i < 20 && handle; i++)
 
512
    {
 
513
      Sleep(500);
 
514
      handle = ::FindWindowW(sClassName, NULL);
 
515
    }
 
516
 
 
517
    // The window must not exist if the service shut down properly
 
518
    result = (handle == NULL);
 
519
  }
 
520
  return result;
 
521
}
 
522
 
 
523
// Remove the part installed from the CAB
 
524
BOOL RunSystemUninstall()
 
525
{
 
526
  WCHAR sXML[c_nTempBufSize];
 
527
  LPWSTR sXMLOut = NULL;
 
528
 
 
529
  _snwprintf(sXML, c_nTempBufSize,
 
530
             L"<wap-provisioningdoc>"
 
531
             L"  <characteristic type=\"UnInstall\">"
 
532
             L"    <characteristic type=\"%s\">"
 
533
             L"      <parm name=\"uninstall\" value=\"1\" />"
 
534
             L"    </characteristic>"
 
535
             L"  </characteristic>"
 
536
             L"</wap-provisioningdoc>",
 
537
             Strings.GetString(StrID_AppLongName));
 
538
 
 
539
  HRESULT hr = DMProcessConfigXML(sXML, CFGFLAG_PROCESS, &sXMLOut);
 
540
  delete[] sXMLOut;
 
541
 
 
542
  return hr == S_OK;
 
543
}