Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

974 lines
26 KiB

  1. #include "precomp.h"
  2. #include "resource.h"
  3. #ifdef DEBUG
  4. #define TRACE(x) Trace x
  5. #else
  6. #define TRACE(x) Trace x
  7. #endif
  8. #define ARRAY_LENGTH(x) (sizeof(x)/sizeof((x)[0]))
  9. static const CHAR __filename[] = __FILE__;
  10. #define CHECK(x) do { if(!(x)) \
  11. { CHAR ErrorText[80]; GetErrorText(GetLastError(), ErrorText, 80); \
  12. TRACE((_T("%hs(%d): %hs failed. Error: %hs\n"), \
  13. __filename, __LINE__, #x, ErrorText)); \
  14. goto Cleanup; } } while(0)
  15. #define CHECK2(x, y) do { if(!(x)) \
  16. { CHAR ErrorText[80]; GetErrorText(GetLastError(), ErrorText, 80); \
  17. TRACE((_T("%hs(%d): %hs ("), __filename, __LINE__, #x)); \
  18. TRACE((y)); \
  19. TRACE((_T(") failed. Error: %hs\n"), ErrorText)); \
  20. goto Cleanup; } } while(0)
  21. #define CHECK_SUCCESS(x) do { LONG lr; lr = (x); if(lr != ERROR_SUCCESS) \
  22. { CHAR ErrorText[80]; GetErrorText(lr, ErrorText, 80); \
  23. TRACE((_T("%hs(%d): %s failed. Error: %hs\n"), \
  24. __filename, __LINE__, #x, ErrorText)); \
  25. goto Cleanup; } } while(0)
  26. void Trace(LPTSTR fmt, ...);
  27. void GetErrorText(DWORD dwError, CHAR *ErrorText, UINT maxChar);
  28. void MakeFileName(TCHAR *FileName, TCHAR *Directory, TCHAR *BaseName);
  29. BOOL MyDeleteService(TCHAR *ServiceName);
  30. BOOL MyMoveFile(TCHAR *File, TCHAR *SourceDir, TCHAR *DestinationDir);
  31. BOOL MyDeleteDirectory(TCHAR *Directory);
  32. BOOL MyRegDeleteKey(HKEY hKey, TCHAR *subkey);
  33. BOOL RegisterServer32(TCHAR *Module, TCHAR *Options);
  34. BOOL IsFirstFileOlderThanSecond(TCHAR *Source, TCHAR *Destination);
  35. #define REGKEY_SVCHOST _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost")
  36. #define REGKEY_STISVC_PARAMETERS _T("SYSTEM\\CurrentControlSet\\Services\\StiSvc\\Parameters")
  37. #define STIBACKUP_DIR _T("%SystemRoot%\\System32\\StiBackup.bak")
  38. #define WINDOWS_DIR _T("%SystemRoot%")
  39. #define TWAIN_DIR _T("%SystemRoot%\\twain_32")
  40. #define SYSTEM32_DIR _T("%SystemRoot%\\System32")
  41. #define DRIVERS_DIR _T("%SystemRoot%\\System32\\Drivers")
  42. #define INF_DIR _T("%SystemRoot%\\Inf")
  43. TCHAR WindowsDirectory[MAX_PATH];
  44. TCHAR TwainDirectory[MAX_PATH];
  45. TCHAR SystemDirectory[MAX_PATH];
  46. TCHAR DriversDirectory[MAX_PATH];
  47. TCHAR InfDirectory[MAX_PATH];
  48. TCHAR szModuleName[] = _T("wiasetup.dll");
  49. typedef struct FileTableEntry {
  50. TCHAR *FileName;
  51. TCHAR *Location;
  52. BOOL bRegister;
  53. BOOL bIgnore;
  54. } FileTableEntry;
  55. FileTableEntry FileTable[] = {
  56. // { _T("camocx.dll"), SystemDirectory, TRUE, FALSE },
  57. // { _T("cropview.dll"), SystemDirectory, TRUE, FALSE },
  58. // { _T("extend.dll"), SystemDirectory, FALSE, FALSE },
  59. { _T("scsiscan.sys"), DriversDirectory, FALSE, FALSE },
  60. { _T("sti.dll"), SystemDirectory, TRUE, FALSE },
  61. { _T("sti_ci.dll"), SystemDirectory, TRUE, FALSE },
  62. { _T("sticpl.cpl"), SystemDirectory, FALSE, FALSE },
  63. { _T("stimon.exe"), SystemDirectory, FALSE, FALSE },
  64. { _T("stisvc.exe"), SystemDirectory, FALSE, FALSE },
  65. { _T("twain_32.dll"), WindowsDirectory, FALSE, FALSE },
  66. { _T("twunk_32.exe"), WindowsDirectory, FALSE, FALSE },
  67. { _T("twunk_16.exe"), WindowsDirectory, FALSE, FALSE },
  68. { _T("wiatwain.ds"), TwainDirectory, FALSE, FALSE },
  69. { _T("usbscan.sys"), DriversDirectory, FALSE, FALSE },
  70. // { _T("wiaacmgr.exe"), SystemDirectory, FALSE, FALSE },
  71. { _T("wiadefui.dll"), SystemDirectory, TRUE, FALSE },
  72. // { _T("wiadenum.dll"), SystemDirectory, TRUE, FALSE },
  73. { _T("wiadss.dll"), SystemDirectory, TRUE, FALSE },
  74. { _T("wiafbdrv.dll"), SystemDirectory, TRUE, FALSE },
  75. // { _T("wiascanx.dll"), SystemDirectory, TRUE, FALSE },
  76. // { _T("wiascr.dll"), SystemDirectory, TRUE, FALSE },
  77. // { _T("wiascr.tlb"), SystemDirectory, FALSE, FALSE },
  78. { _T("wiaservc.dll"), SystemDirectory, TRUE, FALSE },
  79. { _T("wiasf.ax"), SystemDirectory, TRUE, FALSE },
  80. { _T("wiashext.dll"), SystemDirectory, TRUE, FALSE },
  81. // { _T("wiastatd.dll"), SystemDirectory, FALSE, FALSE },
  82. // { _T("wiatscan.dll"), SystemDirectory, FALSE, FALSE },
  83. { _T("wiavusd.dll"), SystemDirectory, TRUE, FALSE },
  84. { _T("sti.inf"), InfDirectory, FALSE, FALSE },
  85. { NULL, NULL, FALSE, FALSE }
  86. };
  87. BOOL __stdcall InstallWia(void);
  88. BOOL __stdcall RemoveWia(void);
  89. UINT CALLBACK wsIterateCabinetCallback(PVOID, UINT, UINT, UINT);
  90. BOOL InstallFileTable(FileTableEntry *pTable, TCHAR *DirInstallFrom, TCHAR *BackupDir);
  91. BOOL InstallWiaService(void);
  92. BOOL InstallStiService(void);
  93. #if 0
  94. #ifdef UNICODE
  95. #define WinMain wWinMain
  96. #endif
  97. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR lpCmd, int nShow)
  98. {
  99. if((lpCmd[0] == _T('-') || lpCmd[0] == _T('/')) &&
  100. (lpCmd[1] == _T('u') || lpCmd[0] == _T('U')))
  101. {
  102. CHECK(RemoveWia());
  103. }
  104. else
  105. {
  106. CHECK(InstallWia());
  107. }
  108. Cleanup:
  109. return 0;
  110. }
  111. #endif
  112. BOOL __stdcall InstallWia(void)
  113. {
  114. BOOL success = FALSE;
  115. HINSTANCE hCi = NULL;
  116. TCHAR StiBackupDirectory[MAX_PATH];
  117. TCHAR TempDirectory[MAX_PATH];
  118. TCHAR WiaCabFile[MAX_PATH];
  119. TCHAR path[MAX_PATH];
  120. DWORD dwAttributes;
  121. int i;
  122. HMODULE hModule;
  123. BOOL CreatedBackupDirectory = FALSE;
  124. BOOL CreatedTempDirectory = FALSE;
  125. BOOL InstalledWiaEnvironment = FALSE;
  126. OSVERSIONINFOEX osv;
  127. ZeroMemory(&osv, sizeof(osv));
  128. osv.dwOSVersionInfoSize = sizeof(osv);
  129. osv.dwMajorVersion = 5;
  130. // make sure we have NT5 or better
  131. CHECK(VerifyVersionInfo(&osv, VER_MAJORVERSION, VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL)));
  132. //
  133. // Get system paths
  134. //
  135. CHECK(ExpandEnvironmentStrings(WINDOWS_DIR, WindowsDirectory, MAX_PATH));
  136. CHECK(ExpandEnvironmentStrings(TWAIN_DIR, TwainDirectory, MAX_PATH));
  137. CHECK(ExpandEnvironmentStrings(SYSTEM32_DIR, SystemDirectory, MAX_PATH));
  138. CHECK(ExpandEnvironmentStrings(DRIVERS_DIR, DriversDirectory, MAX_PATH));
  139. CHECK(ExpandEnvironmentStrings(INF_DIR, InfDirectory, MAX_PATH));
  140. CHECK(ExpandEnvironmentStrings(STIBACKUP_DIR, StiBackupDirectory, MAX_PATH));
  141. // Get our module file name
  142. hModule = GetModuleHandle(szModuleName);
  143. CHECK(hModule != NULL);
  144. CHECK(GetModuleFileName(hModule, WiaCabFile, MAX_PATH));
  145. //
  146. // Create backup directory, if it does not already exist
  147. //
  148. dwAttributes = GetFileAttributes(StiBackupDirectory);
  149. if(dwAttributes == -1)
  150. {
  151. CHECK(CreateDirectory(StiBackupDirectory, NULL));
  152. }
  153. CreatedBackupDirectory = TRUE;
  154. MakeFileName(path, StiBackupDirectory, _T("wiasetup.dll"));
  155. CHECK(CopyFile(WiaCabFile, path, FALSE));
  156. // Find the last "\"
  157. for(i = 0; i < MAX_PATH && WiaCabFile[i] != _T('\0'); i++)
  158. ;
  159. while(i > 0 && WiaCabFile[i] != _T('\\'))
  160. i--;
  161. CHECK(WiaCabFile[i] == _T('\\'));
  162. // Append cabinet name afer the last backslash
  163. lstrcpy(WiaCabFile + i, _T("\\wiasetup.cab"));
  164. // Verify that CAB file exist
  165. CHECK((dwAttributes = GetFileAttributes(WiaCabFile)) != -1);
  166. // Generate temp directory name and create temp directory
  167. CHECK(GetTempPath(MAX_PATH, path));
  168. CHECK(GetTempFileName(path, _T("wsetup"), 0, TempDirectory));
  169. CHECK(DeleteFile(TempDirectory));
  170. CHECK(CreateDirectory(TempDirectory, NULL));
  171. CreatedTempDirectory = TRUE;
  172. //
  173. // Extract our .CAB file into it
  174. //
  175. CHECK(SetupIterateCabinet(WiaCabFile, 0, wsIterateCabinetCallback, TempDirectory));
  176. //
  177. // Remove STISVC service
  178. //
  179. CHECK(MyDeleteService(_T("stisvc")));
  180. //
  181. // Install and register all the files
  182. //
  183. CHECK(InstallFileTable(FileTable, TempDirectory, StiBackupDirectory));
  184. InstalledWiaEnvironment = TRUE;
  185. CHECK(InstallWiaService());
  186. //
  187. // Mark success
  188. //
  189. success = TRUE;
  190. Cleanup:
  191. if(CreatedTempDirectory) MyDeleteDirectory(TempDirectory);
  192. if(!success)
  193. {
  194. if(InstalledWiaEnvironment) RemoveWia();
  195. }
  196. return success;
  197. }
  198. BOOL __stdcall RemoveWia(void)
  199. {
  200. BOOL success = FALSE;
  201. TCHAR StiBackupDirectory[MAX_PATH];
  202. //
  203. // Get system paths
  204. //
  205. CHECK(ExpandEnvironmentStrings(WINDOWS_DIR, WindowsDirectory, MAX_PATH));
  206. CHECK(ExpandEnvironmentStrings(TWAIN_DIR, TwainDirectory, MAX_PATH));
  207. CHECK(ExpandEnvironmentStrings(SYSTEM32_DIR, SystemDirectory, MAX_PATH));
  208. CHECK(ExpandEnvironmentStrings(DRIVERS_DIR, DriversDirectory, MAX_PATH));
  209. CHECK(ExpandEnvironmentStrings(STIBACKUP_DIR, StiBackupDirectory, MAX_PATH));
  210. CHECK(MyDeleteService(_T("stisvc")));
  211. CHECK(InstallFileTable(FileTable, StiBackupDirectory, NULL));
  212. CHECK(InstallStiService());
  213. CHECK(MyDeleteDirectory(StiBackupDirectory));
  214. success = TRUE;
  215. Cleanup:
  216. return success;
  217. }
  218. //
  219. // This is called by SetupIterateCabinet for each file in cabinet
  220. //
  221. UINT CALLBACK
  222. wsIterateCabinetCallback(PVOID pContext, UINT Notification,
  223. UINT Param1, UINT Param2)
  224. {
  225. UINT result = NO_ERROR;
  226. TCHAR *TargetDir = (TCHAR *)pContext;
  227. FILE_IN_CABINET_INFO *pInfo = NULL;
  228. FILEPATHS *pFilePaths = NULL;
  229. switch(Notification)
  230. {
  231. case SPFILENOTIFY_FILEINCABINET:
  232. pInfo = (FILE_IN_CABINET_INFO *)Param1;
  233. MakeFileName(pInfo->FullTargetName, TargetDir, (TCHAR *)pInfo->NameInCabinet);
  234. result = FILEOP_DOIT; // Extract the file.
  235. break;
  236. case SPFILENOTIFY_FILEEXTRACTED:
  237. pFilePaths = (FILEPATHS *)Param1;
  238. result = NO_ERROR;
  239. break;
  240. case SPFILENOTIFY_NEEDNEWCABINET: // Unexpected.
  241. result = NO_ERROR;
  242. break;
  243. }
  244. return result;
  245. }
  246. BOOL
  247. InstallFileTable(
  248. FileTableEntry *pTable,
  249. TCHAR *DirInstallFrom,
  250. TCHAR *BackupDir)
  251. /*++
  252. Performs four passes over the specified file table:
  253. 1. Checks version stamp of both source and destination files
  254. and marks older source files to ignore
  255. 2. Unregister any old file that needs to be unregistered;
  256. 3. Moves every old file into BackupDir and copies any new
  257. file into place from DirInstallFrom;
  258. 4. Registers any new file that needs to be registered;
  259. --*/
  260. {
  261. BOOL success = FALSE;
  262. DWORD dwAttributes;
  263. TCHAR Source[MAX_PATH];
  264. TCHAR Destination[MAX_PATH];
  265. HANDLE hSfc = NULL;
  266. FileTableEntry *p;
  267. CHECK(hSfc = SfcConnectToServer(NULL));
  268. //
  269. // Pass 1: mark any older source files to ignore
  270. //
  271. for(p = pTable; p->FileName != NULL; p++)
  272. {
  273. MakeFileName(Source, DirInstallFrom, p->FileName);
  274. dwAttributes = GetFileAttributes(Source);
  275. if(dwAttributes == -1)
  276. {
  277. continue;
  278. }
  279. MakeFileName(Destination, p->Location, p->FileName);
  280. dwAttributes = GetFileAttributes(Destination);
  281. if(dwAttributes == -1)
  282. {
  283. continue;
  284. }
  285. if(IsFirstFileOlderThanSecond(Source, Destination))
  286. {
  287. p->bIgnore = TRUE;
  288. }
  289. }
  290. //
  291. // Pass 2: unregister all DLLs that need registration
  292. //
  293. for(p = pTable; p->FileName != NULL; p++)
  294. {
  295. if(!p->bRegister) continue;
  296. MakeFileName(Destination, p->Location, p->FileName);
  297. dwAttributes = GetFileAttributes(Destination);
  298. if(dwAttributes != -1)
  299. {
  300. CHECK(RegisterServer32(Destination, _T("/u /s")));
  301. }
  302. }
  303. //
  304. // Pass 3: Install all the files
  305. //
  306. for(p = pTable; p->FileName != NULL; p++)
  307. {
  308. //
  309. // Prepare full destination file name, make sure it exists
  310. //
  311. MakeFileName(Destination, p->Location, p->FileName);
  312. dwAttributes = GetFileAttributes(Destination);
  313. if(dwAttributes != -1)
  314. {
  315. //
  316. // If this file is under SFP, make exception
  317. //
  318. if(SfcIsFileProtected(hSfc, Destination))
  319. {
  320. if(SfcFileException(hSfc, Destination,
  321. SFC_ACTION_REMOVED | SFC_ACTION_MODIFIED |
  322. SFC_ACTION_RENAMED_OLD_NAME) != ERROR_SUCCESS)
  323. {
  324. TRACE((_T("InstallFileTable: Failed setting up SFC exception for %s\n"), Destination));
  325. }
  326. }
  327. //
  328. // delete the old file to backup directory
  329. //
  330. CHECK(MyMoveFile(p->FileName, p->Location, BackupDir));
  331. }
  332. //
  333. // Prepare full source file name, make sure it exists
  334. //
  335. MakeFileName(Source, DirInstallFrom, p->FileName);
  336. dwAttributes = GetFileAttributes(Source);
  337. if(dwAttributes != -1)
  338. {
  339. //
  340. // move the new file into place
  341. //
  342. CHECK2(CopyFile(Source, Destination, FALSE), (_T("%s %s"), Source, Destination));
  343. }
  344. }
  345. //
  346. // Pass 4: Register all DLLs that need registration
  347. //
  348. for(p = pTable; p->FileName != NULL; p++)
  349. {
  350. if(!p->bRegister) continue;
  351. MakeFileName(Destination, p->Location, p->FileName);
  352. dwAttributes = GetFileAttributes(Destination);
  353. if(dwAttributes != -1)
  354. {
  355. CHECK(RegisterServer32(Destination, _T("/s")));
  356. }
  357. }
  358. success = TRUE;
  359. Cleanup:
  360. if(hSfc != NULL) SfcClose(hSfc);
  361. return success;
  362. }
  363. BOOL InstallWiaService(void)
  364. {
  365. BOOL success = FALSE;
  366. SC_HANDLE hSvcMgr = NULL;
  367. SC_HANDLE hService = NULL;
  368. SERVICE_STATUS ServiceStatus;
  369. DWORD checkPoint;
  370. TCHAR DisplayName[260];
  371. TCHAR Description[260];
  372. TCHAR mszStiSvc[] = _T("StiSvc\0");
  373. TCHAR szServiceDll[] = _T("%SystemRoot%\\System32\\wiaservc.dll");
  374. HMODULE hModule;
  375. HKEY hKey = NULL;
  376. CHECK(hModule = GetModuleHandle(szModuleName));
  377. CHECK(LoadString(hModule, IDS_WIA_DISPLAY_NAME, DisplayName, ARRAY_LENGTH(DisplayName)));
  378. CHECK(LoadString(hModule, IDS_WIA_DESCRIPTION, Description, ARRAY_LENGTH(Description)));
  379. //
  380. // Add svchost.exe -- specific entries
  381. //
  382. CHECK_SUCCESS(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SVCHOST,
  383. 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL));
  384. CHECK_SUCCESS(RegSetValueEx(hKey, _T("imgsvc"), 0, REG_MULTI_SZ,
  385. (BYTE *)mszStiSvc, (lstrlen(mszStiSvc) + 1) * sizeof(TCHAR)));
  386. CHECK_SUCCESS(RegCloseKey(hKey));
  387. CHECK_SUCCESS(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_STISVC_PARAMETERS,
  388. 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL));
  389. CHECK_SUCCESS(RegSetValueEx(hKey, _T("ServiceDll"), 0, REG_EXPAND_SZ,
  390. (BYTE *)szServiceDll, lstrlen(szServiceDll) * sizeof(TCHAR)));
  391. CHECK(hSvcMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
  392. CHECK(hService = CreateService(hSvcMgr,
  393. _T("StiSvc"),
  394. DisplayName,
  395. SERVICE_ALL_ACCESS,
  396. SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
  397. SERVICE_DEMAND_START,
  398. SERVICE_ERROR_NORMAL,
  399. _T("%SystemRoot%\\System32\\svchost.exe -k imgsvc"),
  400. NULL,
  401. NULL,
  402. _T("RpcSs\0"),
  403. _T("LocalSystem"),
  404. NULL));
  405. success = TRUE;
  406. Cleanup:
  407. if(hService) CloseServiceHandle(hService);
  408. if(hSvcMgr) CloseServiceHandle(hSvcMgr);
  409. if(hKey) RegCloseKey(hKey);
  410. return success;
  411. }
  412. BOOL InstallStiService(void)
  413. {
  414. BOOL success = FALSE;
  415. HINF hInf = INVALID_HANDLE_VALUE;
  416. SC_HANDLE hSvcMgr = NULL;
  417. SC_HANDLE hService = NULL;
  418. TCHAR DisplayName[260];
  419. TCHAR Description[260];
  420. HMODULE hModule;
  421. HKEY hKey = NULL;
  422. LONG lResult;
  423. CHECK(hModule = GetModuleHandle(szModuleName));
  424. CHECK(LoadString(hModule, IDS_STI_DISPLAY_NAME, DisplayName, ARRAY_LENGTH(DisplayName)));
  425. CHECK(LoadString(hModule, IDS_STI_DESCRIPTION, Description, ARRAY_LENGTH(Description)));
  426. lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SVCHOST,
  427. 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
  428. if(lResult == ERROR_SUCCESS)
  429. {
  430. RegDeleteValue(hKey, _T("imgsvc"));
  431. CHECK_SUCCESS(RegCloseKey(hKey));
  432. hKey = NULL;
  433. }
  434. lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGKEY_STISVC_PARAMETERS,
  435. 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
  436. if(lResult == ERROR_SUCCESS)
  437. {
  438. RegDeleteValue(hKey, _T("ServiceDll"));
  439. CHECK_SUCCESS(RegCloseKey(hKey));
  440. hKey = NULL;
  441. }
  442. CHECK(hSvcMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
  443. CHECK(hService = CreateService(hSvcMgr,
  444. _T("StiSvc"),
  445. DisplayName,
  446. SERVICE_ALL_ACCESS,
  447. SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
  448. SERVICE_DEMAND_START,
  449. SERVICE_ERROR_NORMAL,
  450. _T("%SystemRoot%\\System32\\stisvc.exe"),
  451. NULL,
  452. NULL,
  453. _T("RpcSs\0"),
  454. _T("LocalSystem"),
  455. NULL));
  456. hInf = SetupOpenInfFile(_T("sti.inf"), NULL, INF_STYLE_WIN4, NULL);
  457. CHECK(hInf != INVALID_HANDLE_VALUE);
  458. CHECK(SetupInstallFromInfSection(NULL, hInf, _T("ClassInstall32"),
  459. SPINST_REGISTRY, NULL, NULL, 0, NULL, NULL, NULL, NULL));
  460. success = TRUE;
  461. Cleanup:
  462. if(hService) CloseServiceHandle(hService);
  463. if(hSvcMgr) CloseServiceHandle(hSvcMgr);
  464. if(hInf != INVALID_HANDLE_VALUE) SetupCloseInfFile(hInf);
  465. if(hKey) RegCloseKey(hKey);
  466. return TRUE;
  467. }
  468. void GetErrorText(DWORD dwError, CHAR *ErrorText, UINT maxChar)
  469. {
  470. DWORD messageLength, charsToMove;
  471. LPSTR pBuffer = NULL;
  472. messageLength = FormatMessageA(
  473. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  474. NULL,
  475. dwError,
  476. 0,
  477. (LPSTR)&pBuffer,
  478. 0,
  479. NULL);
  480. charsToMove = min(maxChar, messageLength);
  481. if(charsToMove == 0)
  482. {
  483. wsprintfA(ErrorText, "Unknown error %d (0x%X)", dwError, dwError);
  484. }
  485. else if(charsToMove == maxChar)
  486. {
  487. lstrcpyA(ErrorText, pBuffer);
  488. ErrorText[maxChar - 1] = '\0';
  489. }
  490. else
  491. {
  492. lstrcpyA(ErrorText, pBuffer);
  493. }
  494. if(pBuffer) LocalFree(pBuffer);
  495. }
  496. void Trace(LPTSTR fmt, ...)
  497. {
  498. TCHAR buffer[1024];
  499. TCHAR fileName[MAX_PATH];
  500. HANDLE hFile;
  501. DWORD cbWritten;
  502. va_list a;
  503. va_start(a, fmt);
  504. wvsprintf(buffer, fmt, a);
  505. if(!ExpandEnvironmentStrings(_T("%SystemRoot%\\system32\\wiasetup.log"), fileName, MAX_PATH))
  506. lstrcpy(fileName, _T("wiasetup.log"));
  507. hFile = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
  508. NULL, OPEN_ALWAYS, 0, NULL);
  509. if(hFile != INVALID_HANDLE_VALUE)
  510. {
  511. #ifdef UNICODE
  512. CHAR bufferA[1024];
  513. WideCharToMultiByte(CP_ACP, 0, buffer, -1, bufferA, 1024, NULL, NULL);
  514. #endif
  515. SetFilePointer(hFile, 0, 0, FILE_END);
  516. #ifdef UNICODE
  517. WriteFile(hFile, bufferA, lstrlenA(bufferA), &cbWritten, NULL);
  518. #else
  519. WriteFile(hFile, buffer, lstrlen(buffer), &cbWritten, NULL);
  520. #endif
  521. CloseHandle(hFile);
  522. }
  523. #ifdef DEBUG
  524. OutputDebugString(buffer);
  525. #endif
  526. }
  527. void MakeFileName(TCHAR *FileName, TCHAR *Directory, TCHAR *BaseName)
  528. {
  529. TCHAR c = _T('\0');
  530. // copy directory name
  531. while(*Directory)
  532. {
  533. c = *(Directory++);
  534. *(FileName++) = c;
  535. }
  536. // make sure there is "\" or "/" between directory and file name
  537. if(c != _T('\\') && c != _T('/'))
  538. {
  539. *(FileName++) = _T('\\');
  540. }
  541. // append base name
  542. while(*BaseName)
  543. {
  544. *(FileName++) = *(BaseName++);
  545. }
  546. // zero-terminate resulting file name
  547. *(FileName++) = _T('\0');
  548. }
  549. BOOL MyDeleteService(TCHAR *ServiceName)
  550. {
  551. BOOL success = FALSE;
  552. SC_HANDLE hSvcMgr = NULL;
  553. SC_HANDLE hService = NULL;
  554. SERVICE_STATUS ServiceStatus;
  555. DWORD checkPoint;
  556. CHECK(hSvcMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
  557. hService = OpenService(hSvcMgr, ServiceName, SERVICE_ALL_ACCESS);
  558. if(hService == NULL)
  559. {
  560. if(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
  561. {
  562. success = TRUE;
  563. goto Cleanup;
  564. }
  565. TRACE((_T("Failed to open service\n")));
  566. }
  567. if(ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus))
  568. {
  569. while(ServiceStatus.dwCurrentState != SERVICE_STOPPED)
  570. {
  571. checkPoint = ServiceStatus.dwCheckPoint;
  572. Sleep(ServiceStatus.dwWaitHint);
  573. CHECK(QueryServiceStatus(hService, &ServiceStatus));
  574. CHECK(ServiceStatus.dwCheckPoint != checkPoint);
  575. }
  576. }
  577. else
  578. {
  579. CHECK(GetLastError() == ERROR_SERVICE_NOT_ACTIVE);
  580. }
  581. CHECK(DeleteService(hService));
  582. success = TRUE;
  583. Cleanup:
  584. if(hService) CloseServiceHandle(hService);
  585. if(hSvcMgr) CloseServiceHandle(hSvcMgr);
  586. return success;
  587. }
  588. BOOL
  589. MyDeleteFile(TCHAR *File)
  590. {
  591. BOOL success = FALSE;
  592. TCHAR Backup[MAX_PATH];
  593. DWORD dwAttributes;
  594. dwAttributes = GetFileAttributes(File);
  595. if(dwAttributes == -1 || DeleteFile(File))
  596. {
  597. success = TRUE;
  598. goto Cleanup;
  599. }
  600. lstrcpy(Backup, File);
  601. lstrcat(Backup, _T(".deleted"));
  602. dwAttributes = GetFileAttributes(Backup);
  603. if(dwAttributes != -1)
  604. {
  605. if(!DeleteFile(Backup))
  606. {
  607. TRACE((_T("Can't delete %s, GetLastError() = \n"), Backup, GetLastError()));
  608. goto Cleanup;
  609. }
  610. }
  611. success = MoveFile(File, Backup);
  612. MoveFileEx(Backup, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  613. Cleanup:
  614. return success;
  615. }
  616. BOOL
  617. MyMoveFile(
  618. TCHAR *File,
  619. TCHAR *SourceDir,
  620. TCHAR *DestinationDir)
  621. /*++
  622. --*/
  623. {
  624. BOOL success = FALSE;
  625. TCHAR Source[MAX_PATH];
  626. TCHAR Destination[MAX_PATH];
  627. DWORD dwAttributes;
  628. MakeFileName(Source, SourceDir, File);
  629. if(DestinationDir != NULL)
  630. {
  631. //
  632. // If backup directory is specified, produce destination file name
  633. //
  634. MakeFileName(Destination, DestinationDir, File);
  635. //
  636. // Delete the destination file if it exists
  637. //
  638. dwAttributes = GetFileAttributes(Destination);
  639. if(dwAttributes == -1)
  640. {
  641. //
  642. // We don't expect this to fail even if file is in use
  643. //
  644. CHECK2(MoveFile(Source, Destination), ("%s %s", Source, Destination));
  645. }
  646. else
  647. {
  648. // Destination file already exists -- don't clobber it,
  649. // just delete the source file
  650. CHECK2(MyDeleteFile(Source), ("%s", Source));
  651. }
  652. }
  653. else
  654. {
  655. //
  656. // If backup directory is not specified, we just delete the source file
  657. //
  658. CHECK2(MyDeleteFile(Source), ("%s", Source));
  659. }
  660. success = TRUE;
  661. Cleanup:
  662. return success;
  663. }
  664. BOOL
  665. MyDeleteDirectory(
  666. TCHAR *Directory)
  667. {
  668. BOOL success = TRUE;
  669. TCHAR path[MAX_PATH];
  670. WIN32_FIND_DATA fd;
  671. HANDLE hFind = INVALID_HANDLE_VALUE;
  672. DWORD dwAttributes;
  673. dwAttributes = GetFileAttributes(Directory);
  674. if(dwAttributes == -1) {
  675. success = TRUE;
  676. goto Cleanup;
  677. }
  678. CHECK((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  679. MakeFileName(path, Directory, _T("*.*"));
  680. hFind = FindFirstFile(path, &fd);
  681. while(hFind != INVALID_HANDLE_VALUE)
  682. {
  683. // delete any file or directory that is not "." or ".."
  684. if(lstrcmp(fd.cFileName, _T(".")) != 0 &&
  685. lstrcmp(fd.cFileName, _T("..")) != 0)
  686. {
  687. MakeFileName(path, Directory, fd.cFileName);
  688. dwAttributes = GetFileAttributes(path);
  689. if(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
  690. {
  691. CHECK2(MyDeleteDirectory(path), ("%s", path));
  692. } else {
  693. CHECK2(MyDeleteFile(path), ("%s", path));
  694. }
  695. }
  696. // if no more files,
  697. // close enumerator (and thus break out of loop)
  698. if(!FindNextFile(hFind, &fd))
  699. {
  700. FindClose(hFind);
  701. hFind = INVALID_HANDLE_VALUE;
  702. }
  703. }
  704. // don't forget to delete the directory
  705. CHECK2(RemoveDirectory(Directory), ("%s", Directory));
  706. success = TRUE;
  707. Cleanup:
  708. // if we jumped out of while() loop in error,
  709. // don't leave enumerator orphaned
  710. if(hFind != INVALID_HANDLE_VALUE)
  711. {
  712. FindClose(hFind);
  713. }
  714. return success;
  715. }
  716. BOOL MyRegDeleteKey(HKEY hKey, TCHAR *subkey)
  717. {
  718. BOOL success;
  719. UINT result;
  720. result = RegDeleteKey(hKey, subkey);
  721. success = (result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
  722. if(!success)
  723. {
  724. SetLastError(result);
  725. }
  726. return success;
  727. }
  728. BOOL RegisterServer32(TCHAR *Module, TCHAR *Options)
  729. {
  730. BOOL success = FALSE;
  731. STARTUPINFO si;
  732. PROCESS_INFORMATION pi;
  733. TCHAR Regsvr32[MAX_PATH];
  734. TCHAR *CmdLine = NULL;
  735. CHECK(ExpandEnvironmentStrings(_T("%SystemRoot%\\system32\\regsvr32.exe "), Regsvr32, MAX_PATH));
  736. CmdLine = (TCHAR *)LocalAlloc(LPTR,
  737. sizeof(TCHAR) * (2 + lstrlen(Options) + lstrlen(Module) + lstrlen(Regsvr32)));
  738. CHECK(CmdLine != NULL);
  739. lstrcpy(CmdLine, Regsvr32);
  740. lstrcat(CmdLine, Options);
  741. lstrcat(CmdLine, _T(" "));
  742. lstrcat(CmdLine, Module);
  743. ZeroMemory(&si, sizeof(si));
  744. si.cb = sizeof(si);
  745. CHECK2(CreateProcess(NULL, CmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi), ("%s", CmdLine));
  746. CHECK(WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0);
  747. CloseHandle(pi.hProcess);
  748. CloseHandle(pi.hThread);
  749. success = TRUE;
  750. Cleanup:
  751. if(CmdLine) LocalFree((HLOCAL) CmdLine);
  752. return success;
  753. }
  754. BOOL IsFirstFileOlderThanSecond(TCHAR *FirstFile, TCHAR *SecondFile)
  755. {
  756. BOOL success = FALSE;
  757. DWORD dwFirst, dwSecond;
  758. LPVOID pFirst = NULL;
  759. LPVOID pSecond = NULL;
  760. DWORD dummy;
  761. VS_FIXEDFILEINFO *pvFirst;
  762. VS_FIXEDFILEINFO *pvSecond;
  763. UINT uFirst, uSecond;
  764. dwFirst = GetFileVersionInfoSize(FirstFile, &dummy);
  765. dwSecond = GetFileVersionInfoSize(SecondFile, &dummy);
  766. if(dwFirst == 0 || dwSecond == 0)
  767. {
  768. // one of them does not have version information.
  769. // consider this "not older"
  770. goto Cleanup;
  771. }
  772. CHECK(pFirst = LocalAlloc(LPTR, dwFirst));
  773. CHECK(pSecond = LocalAlloc(LPTR, dwSecond));
  774. CHECK(GetFileVersionInfo(FirstFile, 0, dwFirst, pFirst));
  775. CHECK(GetFileVersionInfo(SecondFile, 0, dwSecond, pSecond));
  776. CHECK(VerQueryValue(pFirst, _T("\\"), &pvFirst, &uFirst) && pvFirst);
  777. CHECK(VerQueryValue(pSecond, _T("\\"), &pvSecond, &uSecond) && pvSecond);
  778. if(pvFirst->dwFileVersionMS > pvSecond->dwFileVersionMS)
  779. {
  780. // first file version is definitely newer
  781. goto Cleanup;
  782. }
  783. if(pvFirst->dwFileVersionMS < pvSecond->dwFileVersionMS)
  784. {
  785. // first file is definitely older
  786. success = TRUE;
  787. }
  788. //
  789. // at this point we know that MS versions are the same
  790. //
  791. success = pvFirst->dwFileVersionLS < pvFirst->dwFileVersionLS;
  792. Cleanup:
  793. if(pFirst) LocalFree(pFirst);
  794. if(pSecond) LocalFree(pSecond);
  795. return success;
  796. }