Leaked source code of windows server 2003
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.

3106 lines
93 KiB

  1. // Defines the entry point for the DLL application.
  2. //
  3. #include "stdafx.h"
  4. #include <winver.h>
  5. #include <shlwapi.h>
  6. #include <mapix.h>
  7. #include <routemapi.h>
  8. #include <faxsetup.h>
  9. #include "Aclapi.h"
  10. #define STRSAFE_NO_DEPRECATE
  11. #include <strsafe.h>
  12. HINSTANCE g_hModule = NULL;
  13. BOOL SetDefaultPrinter(LPTSTR pPrinterName);
  14. DWORD CreateFaxPrinterName(IN LPCTSTR tzPortName, OUT LPTSTR* ptzFaxPrinterName);
  15. BOOL APIENTRY DllMain( HINSTANCE hModule,
  16. DWORD ul_reason_for_call,
  17. LPVOID lpReserved
  18. )
  19. {
  20. SET_DEBUG_MASK(DBG_ALL);
  21. g_hModule = hModule;
  22. switch (ul_reason_for_call)
  23. {
  24. case DLL_PROCESS_ATTACH:
  25. {
  26. OPEN_DEBUG_LOG_FILE(SHARED_FAX_SERVICE_SETUP_LOG_FILE);
  27. DBG_ENTER(TEXT("DllMain called reason DLL_PROCESS_ATTACH."));
  28. if (!DisableThreadLibraryCalls(hModule))
  29. {
  30. VERBOSE(GENERAL_ERR,
  31. _T("DisableThreadLibraryCalls failed (ec=%d)"),
  32. GetLastError());
  33. }
  34. break;
  35. }
  36. case DLL_PROCESS_DETACH:
  37. {
  38. DBG_ENTER(TEXT("DllMain called reason DLL_PROCESS_DETACH."));
  39. CLOSE_DEBUG_LOG_FILE;
  40. break;
  41. }
  42. }
  43. return TRUE;
  44. }
  45. ///////////////////////////////
  46. // VerifySpoolerIsRunning
  47. //
  48. // Start the Spooler service on NT4 & NT5
  49. //
  50. // Returns:
  51. // - NO_ERROR on success
  52. // - error code otherwise.
  53. //
  54. DWORD VerifySpoolerIsRunning()
  55. {
  56. OSVERSIONINFO osv;
  57. BOOL bSuccess = FALSE;
  58. DWORD dwReturn = NO_ERROR;
  59. SC_HANDLE hSvcMgr = NULL;
  60. SC_HANDLE hService = NULL;
  61. DWORD i = 0;
  62. SERVICE_STATUS Status;
  63. LPCTSTR lpctstrSpoolerServiceName = _T("Spooler");
  64. DBG_ENTER(_T("VerifySpoolerIsRunning"),dwReturn);
  65. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  66. if (!GetVersionEx(&osv))
  67. {
  68. dwReturn = GetLastError();
  69. VERBOSE(GENERAL_ERR,
  70. _T("GetVersionEx failed: (ec=%d)"),
  71. dwReturn);
  72. goto exit;
  73. }
  74. // If Windows NT, use WriteProfileString for version 4.0 and earlier...
  75. if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
  76. {
  77. VERBOSE (DBG_MSG,
  78. TEXT("W9X OS, Skipping Spooler verification"));
  79. goto exit;
  80. }
  81. // open the service manager
  82. hSvcMgr = ::OpenSCManager(NULL,
  83. NULL,
  84. SC_MANAGER_CONNECT);
  85. if (hSvcMgr == NULL)
  86. {
  87. dwReturn = ::GetLastError();
  88. VERBOSE(SETUP_ERR,
  89. _T("Failed to open the service manager, rc = 0x%lx"),
  90. dwReturn);
  91. goto exit;
  92. }
  93. hService = ::OpenService(hSvcMgr,
  94. lpctstrSpoolerServiceName,
  95. SERVICE_QUERY_STATUS|SERVICE_START);
  96. if (hService == NULL)
  97. {
  98. dwReturn = ::GetLastError();
  99. VERBOSE(SETUP_ERR,
  100. _T("Failed to open service '%s', rc = 0x%lx"),
  101. lpctstrSpoolerServiceName,
  102. dwReturn);
  103. goto exit;
  104. }
  105. // Start the fax service.
  106. bSuccess = StartService(hService, 0, NULL);
  107. if (!bSuccess)
  108. {
  109. dwReturn = ::GetLastError();
  110. if (dwReturn == ERROR_SERVICE_ALREADY_RUNNING)
  111. {
  112. dwReturn = NO_ERROR;
  113. }
  114. else
  115. {
  116. VERBOSE(SETUP_ERR,
  117. _T("Failed to start service '%s', rc = 0x%lx"),
  118. lpctstrSpoolerServiceName,
  119. dwReturn);
  120. goto exit;
  121. }
  122. }
  123. do
  124. {
  125. QueryServiceStatus(hService, &Status);
  126. i++;
  127. if (Status.dwCurrentState != SERVICE_RUNNING)
  128. {
  129. Sleep(1000);
  130. }
  131. } while ((i < 60) && (Status.dwCurrentState != SERVICE_RUNNING));
  132. if (Status.dwCurrentState != SERVICE_RUNNING)
  133. {
  134. VERBOSE(SETUP_ERR,
  135. _T("Failed to start '%s' service"),
  136. lpctstrSpoolerServiceName);
  137. dwReturn = ERROR_SERVICE_REQUEST_TIMEOUT;
  138. goto exit;
  139. }
  140. exit:
  141. if (hService)
  142. {
  143. CloseServiceHandle(hService);
  144. }
  145. if (hSvcMgr)
  146. {
  147. CloseServiceHandle(hSvcMgr);
  148. }
  149. return dwReturn;
  150. }
  151. //
  152. //
  153. // Function: ConnectW9XToRemotePrinter
  154. // Platform: This function intended to run on Win9X platforms
  155. // Description: Add fax printer connection (driver + printer connection)
  156. // This function is exported by the DLL for use by the MSI as custom action to add printer connection.
  157. // In case of failure , returns ERROR_INSTALL_FAILURE
  158. // In case of success , returns ERROR_SUCCESS
  159. // GetLastError() to get the error code in case of failure.
  160. //
  161. // Remarks:
  162. //
  163. // Args: hInstall : Handle from MSI, can get state of the current setup
  164. //
  165. // Author: AsafS
  166. DLL_API UINT __stdcall ConnectW9XToRemotePrinter(MSIHANDLE hInstall)
  167. {
  168. UINT rc = ERROR_INSTALL_FAILURE;
  169. DBG_ENTER(TEXT("ConnectW9XToRemotePrinter"), rc);
  170. TCHAR szFaxPortName[MAX_PATH] = {0};
  171. TCHAR szPrinterDriverFolder[MAX_PATH] = {0};
  172. DWORD dwNeededSize = 0;
  173. PRINTER_INFO_2 pi2 = {0};
  174. DRIVER_INFO_3 di3 = {0};
  175. HANDLE hPrinter = NULL;
  176. if (!GetPrinterDriverDirectory(
  177. NULL,
  178. TEXT("Windows 4.0"),
  179. 1,
  180. (LPBYTE) szPrinterDriverFolder,
  181. sizeof(szPrinterDriverFolder)/sizeof(TCHAR),
  182. &dwNeededSize
  183. ))
  184. {
  185. VERBOSE (PRINT_ERR,
  186. TEXT("GetPrinterDriverDirectory failed or not enough space dwNeededSize %ld (ec: %ld)"),
  187. dwNeededSize,
  188. GetLastError ());
  189. goto exit;
  190. }
  191. // Get the remote printer path
  192. if (!PrivateMsiGetProperty(hInstall,_T("CustomActionData"),szFaxPortName))
  193. {
  194. VERBOSE (SETUP_ERR, _T("PrivateMsiGetProperty failed (ec: %ld)"), GetLastError());
  195. goto exit;
  196. }
  197. if (!FillDriverInfo(&di3,W9X_PRINT_ENV))
  198. {
  199. VERBOSE (PRINT_ERR, _T("FillDriverInfo failed (ec: %ld)"), GetLastError());
  200. goto exit;
  201. }
  202. if (!AddPrinterDriver(NULL, 3, (LPBYTE)&di3))
  203. {
  204. VERBOSE (PRINT_ERR, _T("AddPrinterDriver failed (ec: %ld)"), GetLastError());
  205. goto exit;
  206. }
  207. pi2.pPortName = szFaxPortName;
  208. pi2.pDriverName = FAX_DRIVER_NAME;
  209. pi2.pPrintProcessor = TEXT("WinPrint");
  210. pi2.pDatatype = TEXT("RAW");
  211. rc = CreateFaxPrinterName(szFaxPortName, &(pi2.pPrinterName));
  212. if (rc != NO_ERROR)
  213. {
  214. VERBOSE (PRINT_ERR, _T("CreateFaxPrinterName() is failed, rc= %d. Use default."), rc);
  215. pi2.pPrinterName = FAX_PRINTER_NAME;
  216. }
  217. VERBOSE(DBG_MSG, _T("PrinterName is : '%s'."), pi2.pPrinterName);
  218. hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pi2);
  219. if (!hPrinter)
  220. {
  221. rc = GetLastError();
  222. if (rc==ERROR_PRINTER_ALREADY_EXISTS)
  223. {
  224. VERBOSE (DBG_MSG,TEXT("Printer already exists, continue..."));
  225. rc = ERROR_SUCCESS;
  226. }
  227. else
  228. {
  229. VERBOSE (PRINT_ERR, _T("AddPrinter failed (ec: %ld)"), GetLastError());
  230. goto exit;
  231. }
  232. }
  233. if (hPrinter)
  234. {
  235. ClosePrinter(hPrinter);
  236. hPrinter = NULL;
  237. }
  238. rc = ERROR_SUCCESS;
  239. exit:
  240. if (pi2.pPrinterName)
  241. {
  242. MemFree(pi2.pPrinterName);
  243. }
  244. if (rc != ERROR_SUCCESS)
  245. {
  246. VERBOSE (GENERAL_ERR, _T("CustomAction ConnectW9XToRemotePrinter() failed !"));
  247. }
  248. return rc;
  249. }
  250. //
  251. //
  252. // Function: RemoveW9XPrinterConnection
  253. // Platform: This function intended to run on Win9X platforms
  254. // Description: Remove the fax printer connection from the current machine.
  255. // This function is exported by the DLL for use by the MSI as custom action to delete printer connection.
  256. // In case of failure , returns ERROR_INSTALL_FAILURE
  257. // In case of success , returns ERROR_SUCCESS
  258. // GetLastError() to get the error code in case of failure, the error is of the first error that occured.
  259. //
  260. // Remarks:
  261. //
  262. // Args:
  263. //
  264. // hInstall : Handle from MSI, can get state of the current setup
  265. //
  266. // Author: AsafS
  267. DLL_API UINT __stdcall RemoveW9XPrinterConnection(MSIHANDLE hInstall)
  268. {
  269. UINT retVal = ERROR_INSTALL_FAILURE;
  270. PPRINTER_INFO_2 PrinterInfo = NULL;
  271. DWORD dwCount = 0;
  272. HANDLE hPrinter = NULL;
  273. DBG_ENTER(TEXT("RemoveW9XPrinterConnection"), retVal);
  274. PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL, 2, &dwCount, 0);
  275. if (!PrinterInfo)
  276. {
  277. VERBOSE(PRINT_ERR, _T("MyEnumPrinters failed : %d."), GetLastError());
  278. goto error;
  279. }
  280. VERBOSE(DBG_MSG, _T("MyEnumPrinters found %d printers installed."), dwCount);
  281. for (DWORD i=0 ; i<dwCount ; i++ )
  282. {
  283. if (_tcscmp(PrinterInfo[i].pDriverName, FAX_DRIVER_NAME) == 0)
  284. {
  285. VERBOSE(DBG_MSG, _T("Found Fax Printer : %s."), PrinterInfo[i].pPrinterName);
  286. if (!OpenPrinter(PrinterInfo[i].pPrinterName, &hPrinter, NULL))
  287. {
  288. VERBOSE(PRINT_ERR, _T("OpenPrinter() failed ! (ec: %ld)"), GetLastError());
  289. continue;
  290. }
  291. if (!DeletePrinter(hPrinter))
  292. {
  293. VERBOSE(PRINT_ERR, _T("DeletePrinter() failed ! (ec: %ld)"), GetLastError());
  294. }
  295. if (hPrinter)
  296. {
  297. ClosePrinter(hPrinter);
  298. hPrinter = NULL;
  299. }
  300. }
  301. else
  302. {
  303. VERBOSE(DBG_MSG, _T("This is not Fax Printer : %s."), PrinterInfo[i].pPrinterName);
  304. }
  305. }
  306. retVal = ERROR_SUCCESS;
  307. error:
  308. if (PrinterInfo)
  309. {
  310. MemFree( PrinterInfo );
  311. PrinterInfo = NULL;
  312. }
  313. return retVal;
  314. }
  315. class CSignalSetupInProgress
  316. {
  317. public:
  318. CSignalSetupInProgress();
  319. ~CSignalSetupInProgress();
  320. };
  321. CSignalSetupInProgress::CSignalSetupInProgress()
  322. {
  323. HKEY hFaxKey = NULL;
  324. DBG_ENTER(TEXT("CSignalSetupInProgress::CSignalSetupInProgress"));
  325. // write 'setup in progress' to the registry, to be used by the point & print
  326. // mechanism to skip doing a client installation during a setup that is
  327. // user driven
  328. hFaxKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SBS2000_FAX_SETUP,TRUE,KEY_WRITE);
  329. if (hFaxKey)
  330. {
  331. if (!SetRegistryDword(hFaxKey,REGVAL_SETUP_IN_PROGRESS,1))
  332. {
  333. VERBOSE(GENERAL_ERR,_T("SetRegistryDword failed: (ec=%d)"),GetLastError());
  334. }
  335. }
  336. else
  337. {
  338. VERBOSE(GENERAL_ERR,_T("OpenRegistryKey failed: (ec=%d)"),GetLastError());
  339. }
  340. if (hFaxKey)
  341. {
  342. RegCloseKey(hFaxKey);
  343. }
  344. }
  345. CSignalSetupInProgress::~CSignalSetupInProgress()
  346. {
  347. HKEY hFaxKey = NULL;
  348. DBG_ENTER(TEXT("CSignalSetupInProgress::~CSignalSetupInProgress"));
  349. hFaxKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SBS2000_FAX_SETUP,FALSE,KEY_WRITE);
  350. if (hFaxKey)
  351. {
  352. if (RegDeleteValue(hFaxKey,REGVAL_SETUP_IN_PROGRESS)!=ERROR_SUCCESS)
  353. {
  354. VERBOSE(GENERAL_ERR, TEXT("RegDeleteValue failed with %ld"), GetLastError());
  355. }
  356. }
  357. else
  358. {
  359. VERBOSE(DBG_MSG, TEXT("down leve client setup is not in progress"));
  360. }
  361. if (hFaxKey)
  362. {
  363. RegCloseKey(hFaxKey);
  364. }
  365. }
  366. //
  367. //
  368. // Function: AddFaxPrinterConnection
  369. // Platform: This function intended to run on NT platforms (NT4 and Win2K)
  370. // Description: Add fax printer connection
  371. // This function is exported by the DLL for use by the MSI as custom action to add printer connection.
  372. // In case of failure , returns ERROR_INSTALL_FAILURE
  373. // In case of success , returns ERROR_SUCCESS
  374. // GetLastError() to get the error code in case of failure.
  375. //
  376. // Remarks:
  377. //
  378. // Args: hInstall : Handle from MSI, can get state of the current setup
  379. //
  380. // Author: AsafS
  381. DLL_API UINT __stdcall AddFaxPrinterConnection(MSIHANDLE hInstall)
  382. {
  383. UINT rc = ERROR_SUCCESS;
  384. DBG_ENTER(TEXT("AddFaxPrinterConnection"), rc);
  385. BOOL fFaxPrinterConnectionAdded = FALSE;
  386. TCHAR szFaxPrinterName[MAX_PATH] = {0};
  387. if (!PrivateMsiGetProperty(hInstall,_T("PRINTER_NAME"),szFaxPrinterName))
  388. {
  389. VERBOSE (SETUP_ERR,
  390. TEXT("PrivateMsiGetProperty() failed ! (ec: %ld)"),
  391. GetLastError ());
  392. goto error;
  393. }
  394. //////////////////////////////////////////
  395. // Add the printer connection on client //
  396. //////////////////////////////////////////
  397. {
  398. CSignalSetupInProgress SignalSetupInProgress;
  399. fFaxPrinterConnectionAdded = AddPrinterConnection(szFaxPrinterName);
  400. if (!fFaxPrinterConnectionAdded)
  401. {
  402. DWORD dwLastError = GetLastError();
  403. VERBOSE (PRINT_ERR,
  404. TEXT("AddPrinterConnection() failed ! (ec: %ld)"),
  405. dwLastError);
  406. goto error;
  407. }
  408. else
  409. {
  410. VERBOSE (DBG_MSG,
  411. TEXT("Successfully added fax printer connection to %s"),
  412. szFaxPrinterName);
  413. }
  414. }
  415. if (!SetDefaultPrinter(szFaxPrinterName))
  416. {
  417. DWORD dwLastError = GetLastError();
  418. VERBOSE (PRINT_ERR,
  419. TEXT("SetDefaultPrinter() failed ! (ec: %ld)"),
  420. dwLastError);
  421. goto error;
  422. }
  423. return rc;
  424. error:
  425. VERBOSE (GENERAL_ERR,
  426. TEXT("CustomAction AddFaxPrinterConnection() failed !"));
  427. rc = ERROR_INSTALL_FAILURE;
  428. return rc;
  429. }
  430. //
  431. //
  432. // Function: RemoveFaxPrinterConnection
  433. // Platform: This function intended to run on NT platforms (NT4 and Win2K)
  434. // Description: Remove the fax printer connection from the current machine.
  435. // This function is exported by the DLL for use by the MSI as custom action to delete printer connection.
  436. // In case of failure , returns ERROR_INSTALL_FAILURE
  437. // In case of success , returns ERROR_SUCCESS
  438. // GetLastError() to get the error code in case of failure, the error is of the first error that occured.
  439. //
  440. // Remarks:
  441. //
  442. // Args:
  443. //
  444. // hInstall : Handle from MSI, can get state of the current setup
  445. //
  446. // Author: AsafS
  447. DLL_API UINT __stdcall RemoveFaxPrinterConnection(MSIHANDLE hInstall)
  448. {
  449. PPRINTER_INFO_2 pPrinterInfo = NULL;
  450. DWORD dwNumPrinters = 0;
  451. DWORD dwPrinter = 0;
  452. DWORD ec = ERROR_SUCCESS;
  453. DBG_ENTER(TEXT("RemoveFaxPrinterConnection"), ec);
  454. pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL,
  455. 2,
  456. &dwNumPrinters,
  457. PRINTER_ENUM_CONNECTIONS
  458. );
  459. if (!pPrinterInfo)
  460. {
  461. ec = GetLastError();
  462. if (ERROR_SUCCESS == ec)
  463. {
  464. ec = ERROR_PRINTER_NOT_FOUND;
  465. }
  466. VERBOSE (GENERAL_ERR,
  467. TEXT("MyEnumPrinters() failed (ec: %ld)"),
  468. ec);
  469. goto error;
  470. }
  471. for (dwPrinter=0; dwPrinter < dwNumPrinters; dwPrinter++)
  472. {
  473. if (IsPrinterFaxPrinter(pPrinterInfo[dwPrinter].pPrinterName))
  474. {
  475. if (!DeletePrinterConnection(pPrinterInfo[dwPrinter].pPrinterName))
  476. {
  477. VERBOSE (PRINT_ERR,
  478. TEXT("DeletePrinterConnection() %s failed ! (ec: %ld)"),
  479. pPrinterInfo[dwPrinter].pPrinterName,
  480. GetLastError ());
  481. goto error;
  482. }
  483. else
  484. {
  485. VERBOSE (DBG_MSG,
  486. TEXT("fax printer connection %s was deleted successfully"),
  487. pPrinterInfo[dwPrinter].pPrinterName);
  488. }
  489. }
  490. }
  491. error:
  492. if (pPrinterInfo)
  493. {
  494. MemFree(pPrinterInfo);
  495. }
  496. if (ec!=ERROR_SUCCESS)
  497. {
  498. VERBOSE (GENERAL_ERR,
  499. TEXT("CustomAction RemoveFaxPrinterConnection() failed !"));
  500. }
  501. return ec;
  502. }
  503. #define FXSEXTENSION _T("FXSEXT32.DLL")
  504. //
  505. //
  506. // Function: Create_FXSEXT_ECF_File
  507. // Description: Creates FxsExt.ecf in <WindowsFolder>\addins
  508. // a default file will be installed there by Windows Installer
  509. // to enable it to keep track of install/remove
  510. // GetLastError() to get the error code in case of failure, the error is of the first error that occured.
  511. //
  512. // Remarks:
  513. //
  514. // Args:
  515. //
  516. // hInstall : Handle from MSI, can get state of the current setup
  517. //
  518. // Author: MoolyB
  519. DLL_API UINT __stdcall Create_FXSEXT_ECF_File(MSIHANDLE hInstall)
  520. {
  521. // CustomActionData has the following format <WindowsFolder>;<INSTALLDIR>
  522. TCHAR szCustomActionData[2*MAX_PATH] = {0};
  523. TCHAR szWindowsFolder[2*MAX_PATH] = {0};
  524. TCHAR szExtensionPath[MAX_PATH] = {0};
  525. TCHAR* tpInstallDir = NULL;
  526. UINT uiRet = ERROR_SUCCESS;
  527. DBG_ENTER(_T("Create_FXSEXT_ECF_File"));
  528. // get the custom action data from Windows Installer (deffered action)
  529. if (!PrivateMsiGetProperty(hInstall,_T("CustomActionData"),szCustomActionData))
  530. {
  531. VERBOSE (GENERAL_ERR,
  532. _T("PrivateMsiGetProperty:CustomActionData failed (ec: %ld)."),
  533. uiRet);
  534. goto error;
  535. }
  536. if (_tcstok(szCustomActionData,_T(";"))==NULL)
  537. {
  538. VERBOSE (GENERAL_ERR,
  539. _T("_tcstok failed on first token."));
  540. uiRet = ERROR_INVALID_PARAMETER;
  541. goto error;
  542. }
  543. if ((tpInstallDir=_tcstok(NULL,_T(";\0")))==NULL)
  544. {
  545. VERBOSE (GENERAL_ERR,
  546. _T("_tcstok failed on second token."));
  547. uiRet = ERROR_INVALID_PARAMETER;
  548. goto error;
  549. }
  550. _tcscpy(szWindowsFolder,szCustomActionData);
  551. // construct the full path to the file
  552. if (_tcslen(szWindowsFolder)+_tcslen(ADDINS_DIRECTORY)+_tcslen(FXSEXT_ECF_FILE)>=MAX_PATH)
  553. {
  554. VERBOSE (GENERAL_ERR,
  555. _T("Path to <WindowsFolder>\\Addins\\fxsext.ecf is too long"));
  556. goto error;
  557. }
  558. _tcscat(szWindowsFolder,ADDINS_DIRECTORY);
  559. _tcscat(szWindowsFolder,FXSEXT_ECF_FILE);
  560. VERBOSE (DBG_MSG,
  561. _T("Filename to create is: %s."),
  562. szWindowsFolder);
  563. if (_tcslen(tpInstallDir)+_tcslen(FXSEXTENSION)+2>=MAX_PATH)
  564. {
  565. VERBOSE (GENERAL_ERR,
  566. _T("Path to <INSTALLDIR>\\Bin\\fxsext32.dll is too long"));
  567. goto error;
  568. }
  569. _tcscpy(szExtensionPath,_T("\""));
  570. _tcscat(szExtensionPath,tpInstallDir);
  571. _tcscat(szExtensionPath,FXSEXTENSION);
  572. _tcscat(szExtensionPath,_T("\""));
  573. VERBOSE (DBG_MSG,
  574. _T("MAPI Extension dll path dir is: %s."),
  575. szExtensionPath);
  576. if (!WritePrivateProfileString( _T("General"),
  577. _T("Path"),
  578. szExtensionPath,
  579. szWindowsFolder))
  580. {
  581. uiRet = GetLastError();
  582. VERBOSE (GENERAL_ERR,
  583. _T("WritePrivateProfileString failed (ec: %ld)."),
  584. uiRet);
  585. goto error;
  586. }
  587. Assert(uiRet==ERROR_SUCCESS);
  588. return uiRet;
  589. error:
  590. Assert(uiRet!=ERROR_SUCCESS);
  591. return uiRet;
  592. }
  593. //
  594. //
  595. // Function: ValidatePrinter
  596. // Description: Validates that the printer name which was entered is a legitimate
  597. // Fax Printer, and that the server is available.
  598. // Uses the MSI Property 'ValidPrinterFormat' to notify MSI if the
  599. // name is valid or not.
  600. //
  601. // Remarks:
  602. //
  603. // Args:
  604. //
  605. // hInstall : Handle from MSI, can get state of the current setup
  606. //
  607. // Author: MoolyB
  608. DLL_API UINT __stdcall ValidatePrinter(MSIHANDLE hInstall)
  609. {
  610. TCHAR szPrinterName[MAX_PATH] = {0};
  611. UINT uiRet = ERROR_SUCCESS;
  612. HANDLE hPrinterHandle = INVALID_HANDLE_VALUE;
  613. BOOL bValidPrinter = TRUE;
  614. DBG_ENTER(_T("ValidatePrinter"));
  615. // first get the PRINTER_NAME proterty from Windows Installer
  616. if (!PrivateMsiGetProperty(hInstall,_T("PRINTER_NAME"),szPrinterName))
  617. {
  618. VERBOSE (GENERAL_ERR,
  619. _T("PrivateMsiGetProperty:PRINTER_NAME failed (ec: %ld)."),
  620. uiRet);
  621. goto error;
  622. }
  623. if (VerifySpoolerIsRunning()!=NO_ERROR)
  624. {
  625. uiRet = GetLastError();
  626. VERBOSE (GENERAL_ERR,
  627. _T("VerifySpoolerIsRunning (ec:%d)"),
  628. uiRet);
  629. goto error;
  630. }
  631. // we have a string with the PRINTER_NAME, let's try to open it...
  632. if (bValidPrinter=IsPrinterFaxPrinter(szPrinterName))
  633. {
  634. VERBOSE (DBG_MSG,
  635. _T("IsPrinterFaxPrinter: %s succeeded."),
  636. szPrinterName);
  637. }
  638. else
  639. {
  640. uiRet = GetLastError();
  641. VERBOSE (GENERAL_ERR,
  642. _T("IsPrinterFaxPrinter: %s failed (ec: %ld)."),
  643. szPrinterName,
  644. uiRet);
  645. }
  646. uiRet = MsiSetProperty( hInstall,
  647. _T("ValidPrinterFormat"),
  648. bValidPrinter ? _T("TRUE") : _T("FALSE"));
  649. if (uiRet!=ERROR_SUCCESS)
  650. {
  651. VERBOSE (DBG_MSG,
  652. TEXT("MsiSetProperty failed."));
  653. goto error;
  654. }
  655. return ERROR_SUCCESS;
  656. error:
  657. return ERROR_FUNCTION_FAILED;
  658. }
  659. //
  660. //
  661. // Function: GuessPrinterName
  662. // Description: Tries to understand whether the installation is performed from the
  663. // server's FaxClients share, and if it is tries to establish a default
  664. // printer to be used
  665. //
  666. //
  667. // Args:
  668. //
  669. // hInstall : Handle from MSI, can get state of the current setup
  670. //
  671. // Author: MoolyB
  672. DLL_API UINT __stdcall GuessPrinterName(MSIHANDLE hInstall)
  673. {
  674. UINT uiRet = ERROR_SUCCESS;
  675. TCHAR szSourceDir[MAX_PATH] = {0};
  676. TCHAR szPrinterName[MAX_PATH] = {0};
  677. TCHAR* tpClientShare = NULL;
  678. PPRINTER_INFO_2 pPrinterInfo = NULL;
  679. DWORD dwNumPrinters = 0;
  680. DWORD dwPrinter = 0;
  681. DBG_ENTER(_T("GuessPrinterName"),uiRet);
  682. // get the source directory from Windows Installer
  683. if (!PrivateMsiGetProperty(hInstall,_T("SourceDir"),szSourceDir))
  684. {
  685. VERBOSE (GENERAL_ERR,
  686. _T("PrivateMsiGetProperty:SourceDir failed (ec: %ld)."),
  687. uiRet);
  688. goto exit;
  689. }
  690. // check if we have a UNC path
  691. if (_tcsncmp(szSourceDir,_T("\\\\"),2))
  692. {
  693. VERBOSE (DBG_MSG,
  694. _T("SourceDir doesn't start with \\\\"));
  695. uiRet = ERROR_INVALID_PARAMETER;
  696. goto exit;
  697. }
  698. // find drive name (skip server name)
  699. if ((tpClientShare=_tcschr(_tcsninc(szSourceDir,2),_T('\\')))==NULL)
  700. {
  701. VERBOSE (GENERAL_ERR,
  702. _T("_tcschr failed"));
  703. uiRet = ERROR_INVALID_PARAMETER;
  704. goto exit;
  705. }
  706. if (VerifySpoolerIsRunning()!=NO_ERROR)
  707. {
  708. uiRet = GetLastError();
  709. VERBOSE (GENERAL_ERR,
  710. _T("VerifySpoolerIsRunning (ec:%d)"),
  711. uiRet);
  712. goto exit;
  713. }
  714. // extract the server's name
  715. *tpClientShare = 0;
  716. // szSourceDir now holds the server's name
  717. // enumerate the printers on the server
  718. pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(szSourceDir,
  719. 2,
  720. &dwNumPrinters,
  721. PRINTER_ENUM_NAME
  722. );
  723. if (!pPrinterInfo)
  724. {
  725. uiRet = GetLastError();
  726. if (uiRet == ERROR_SUCCESS)
  727. {
  728. uiRet = ERROR_PRINTER_NOT_FOUND;
  729. }
  730. VERBOSE (GENERAL_ERR,
  731. TEXT("MyEnumPrinters() failed (ec: %ld)"),
  732. uiRet);
  733. goto exit;
  734. }
  735. for (dwPrinter=0; dwPrinter < dwNumPrinters; dwPrinter++)
  736. {
  737. // check if we have a valid fax printer driver name
  738. if (_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME ) == 0)
  739. {
  740. if ( (pPrinterInfo[dwPrinter].pServerName==NULL) ||
  741. (_tcslen(pPrinterInfo[dwPrinter].pServerName)==0) ||
  742. (pPrinterInfo[dwPrinter].pShareName==NULL) ||
  743. (_tcslen(pPrinterInfo[dwPrinter].pShareName)==0) )
  744. {
  745. // on win9x the printer name lives in the Port name field
  746. _tcscpy(szPrinterName,pPrinterInfo[dwPrinter].pPortName);
  747. }
  748. else
  749. {
  750. _tcscpy(szPrinterName,pPrinterInfo[dwPrinter].pServerName);
  751. _tcscat(szPrinterName,_T("\\"));
  752. _tcscat(szPrinterName,pPrinterInfo[dwPrinter].pShareName);
  753. }
  754. VERBOSE (DBG_MSG,
  755. TEXT("Setting PRINTER_NAME to %s."),
  756. szPrinterName);
  757. // set property to Installer
  758. uiRet = MsiSetProperty(hInstall,_T("PRINTER_NAME"),szPrinterName);
  759. if (uiRet!=ERROR_SUCCESS)
  760. {
  761. VERBOSE (GENERAL_ERR,
  762. TEXT("MsiSetProperty failed."));
  763. goto exit;
  764. }
  765. break;
  766. }
  767. else
  768. {
  769. VERBOSE (DBG_MSG,
  770. TEXT("%s is not a Fax printer - driver name is %s."),
  771. pPrinterInfo[dwPrinter].pPrinterName,
  772. pPrinterInfo[dwPrinter].pDriverName);
  773. }
  774. }
  775. exit:
  776. if (pPrinterInfo)
  777. {
  778. MemFree(pPrinterInfo);
  779. }
  780. return uiRet;
  781. }
  782. //
  783. //
  784. // Function: Remove_FXSEXT_ECF_File
  785. // Description: Removes FxsExt.ecf from <WindowsFolder>\addins
  786. //
  787. // Remarks:
  788. //
  789. // Args:
  790. //
  791. // hInstall : Handle from MSI, can get state of the current setup
  792. //
  793. // Author: MoolyB
  794. DLL_API UINT __stdcall Remove_FXSEXT_ECF_File(MSIHANDLE hInstall)
  795. {
  796. TCHAR szWindowsFolder[MAX_PATH] = {0};
  797. UINT uiRet = ERROR_SUCCESS;
  798. DBG_ENTER(_T("Remove_FXSEXT_ECF_File"));
  799. // check if the service is installed on this machine
  800. INSTALLSTATE currentInstallState = MsiQueryProductState(PRODCODE_SBS5_SERVER);
  801. if (currentInstallState != INSTALLSTATE_UNKNOWN)
  802. {
  803. VERBOSE (DBG_MSG, _T("The Microsoft Shared Fax Service is installed. Returning without removing file."));
  804. return uiRet;
  805. }
  806. // get the <WindowsFolder> from Windows Installer
  807. if (!PrivateMsiGetProperty(hInstall,_T("WindowsFolder"),szWindowsFolder))
  808. {
  809. VERBOSE (GENERAL_ERR,
  810. _T("PrivateMsiGetProperty:WindowsFolder failed (ec: %ld)."),
  811. uiRet);
  812. goto error;
  813. }
  814. // construct the full path to the file
  815. if (_tcslen(szWindowsFolder)+_tcslen(ADDINS_DIRECTORY)+_tcslen(FXSEXT_ECF_FILE)>=MAX_PATH)
  816. {
  817. VERBOSE (GENERAL_ERR,
  818. _T("Path to <WindowsFolder>\\Addins\\fxsext.ecf is too long"));
  819. goto error;
  820. }
  821. _tcscat(szWindowsFolder,ADDINS_DIRECTORY);
  822. _tcscat(szWindowsFolder,FXSEXT_ECF_FILE);
  823. VERBOSE (DBG_MSG,
  824. _T("Filename to delete is: %s."),
  825. szWindowsFolder);
  826. if (DeleteFile(szWindowsFolder))
  827. {
  828. VERBOSE (DBG_MSG,
  829. _T("File %s was deleted successfully."),
  830. szWindowsFolder);
  831. }
  832. else
  833. {
  834. VERBOSE (GENERAL_ERR,
  835. _T("DeleteFile %s failed (ec=%d)."),
  836. szWindowsFolder,
  837. GetLastError());
  838. }
  839. return ERROR_SUCCESS;
  840. error:
  841. return ERROR_INSTALL_FAILURE;
  842. }
  843. //
  844. //
  845. // Function: RemoveTrasportProviderFromProfile
  846. // Description: removes the Trasnport Provider from a MAPI profile
  847. //
  848. // Remarks:
  849. //
  850. // Args:
  851. //
  852. // hInstall : Handle from MSI, can get state of the current setup
  853. //
  854. // Author: MoolyB
  855. HRESULT RemoveTrasportProviderFromProfile(LPSERVICEADMIN lpServiceAdmin)
  856. {
  857. static SRestriction sres;
  858. static SizedSPropTagArray(2, Columns) = {2,{PR_DISPLAY_NAME_A,PR_SERVICE_UID}};
  859. HRESULT hr = S_OK;
  860. LPMAPITABLE lpMapiTable = NULL;
  861. LPSRowSet lpSRowSet = NULL;
  862. LPSPropValue lpProp = NULL;
  863. ULONG Count = 0;
  864. BOOL bMapiInitialized = FALSE;
  865. SPropValue spv;
  866. MAPIUID ServiceUID;
  867. DBG_ENTER(TEXT("RemoveTrasportProviderFromProfile"), hr);
  868. // get message service table
  869. hr = lpServiceAdmin->GetMsgServiceTable(0,&lpMapiTable);
  870. if (FAILED(hr))
  871. {
  872. VERBOSE (GENERAL_ERR,
  873. TEXT("GetMsgServiceTable failed (ec: %ld)."),
  874. hr);
  875. goto exit;
  876. }
  877. // notify MAPI that we want PR_DISPLAY_NAME_A & PR_SERVICE_UID
  878. hr = lpMapiTable->SetColumns((LPSPropTagArray)&Columns, 0);
  879. if (FAILED(hr))
  880. {
  881. VERBOSE (GENERAL_ERR,
  882. TEXT("SetColumns failed (ec: %ld)."),
  883. hr);
  884. goto exit;
  885. }
  886. // restrict the search to our service provider
  887. sres.rt = RES_PROPERTY;
  888. sres.res.resProperty.relop = RELOP_EQ;
  889. sres.res.resProperty.ulPropTag = PR_SERVICE_NAME_A;
  890. sres.res.resProperty.lpProp = &spv;
  891. spv.ulPropTag = PR_SERVICE_NAME_A;
  892. spv.Value.lpszA = FAX_MESSAGE_SERVICE_NAME_SBS50;
  893. // find it
  894. hr = lpMapiTable->FindRow(&sres, BOOKMARK_BEGINNING, 0);
  895. if (FAILED(hr))
  896. {
  897. VERBOSE (GENERAL_ERR,
  898. TEXT("FindRow failed (ec: %ld)."),
  899. hr);
  900. goto exit;
  901. }
  902. // get our service provider's row
  903. hr = lpMapiTable->QueryRows(1, 0, &lpSRowSet);
  904. if (FAILED(hr))
  905. {
  906. VERBOSE (GENERAL_ERR,
  907. TEXT("QueryRows failed (ec: %ld)."),
  908. hr);
  909. goto exit;
  910. }
  911. if (lpSRowSet->cRows != 1)
  912. {
  913. VERBOSE (GENERAL_ERR,
  914. TEXT("QueryRows returned %d rows, there should be only one."),
  915. lpSRowSet->cRows);
  916. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  917. goto exit;
  918. }
  919. // get the MAPIUID of our service
  920. lpProp = &lpSRowSet->aRow[0].lpProps[1];
  921. if (lpProp->ulPropTag != PR_SERVICE_UID)
  922. {
  923. VERBOSE (GENERAL_ERR,
  924. TEXT("Property is %d, should be PR_SERVICE_UID."),
  925. lpProp->ulPropTag);
  926. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  927. goto exit;
  928. }
  929. // Copy the UID into our member.
  930. memcpy(&ServiceUID.ab, lpProp->Value.bin.lpb,lpProp->Value.bin.cb);
  931. // finally, delete our service provider
  932. hr = lpServiceAdmin->DeleteMsgService(&ServiceUID);
  933. if (FAILED(hr))
  934. {
  935. VERBOSE (GENERAL_ERR,
  936. TEXT("DeleteMsgService failed (ec: %ld)."),
  937. hr);
  938. goto exit;
  939. }
  940. exit:
  941. return hr;
  942. }
  943. //
  944. //
  945. // Function: RemoveTrasportProvider
  946. // Description: delete FXSXP32.DLL from mapisvc.inf
  947. // and removes the Trasnport Provider from MAPI
  948. //
  949. // Remarks:
  950. //
  951. // Args:
  952. //
  953. // hInstall : Handle from MSI, can get state of the current setup
  954. //
  955. // Author: MoolyB
  956. DLL_API UINT __stdcall RemoveTrasportProvider(MSIHANDLE hInstall)
  957. {
  958. TCHAR szMapisvcFile[2 * MAX_PATH] = {0};
  959. DWORD err = 0;
  960. DWORD rc = ERROR_SUCCESS;
  961. HRESULT hr = S_OK;
  962. LPSERVICEADMIN lpServiceAdmin = NULL;
  963. LPMAPITABLE lpMapiTable = NULL;
  964. LPPROFADMIN lpProfAdmin = NULL;
  965. LPMAPITABLE lpTable = NULL;
  966. LPSRowSet lpSRowSet = NULL;
  967. LPSPropValue lpProp = NULL;
  968. ULONG Count = 0;
  969. int iIndex = 0;
  970. BOOL bMapiInitialized = FALSE;
  971. HINSTANCE hMapiDll = NULL;
  972. LPMAPIINITIALIZE fnMapiInitialize = NULL;
  973. LPMAPIADMINPROFILES fnMapiAdminProfiles = NULL;
  974. LPMAPIUNINITIALIZE fnMapiUninitialize = NULL;
  975. DBG_ENTER(TEXT("RemoveTrasportProvider"), rc);
  976. CRouteMAPICalls rmcRouteMapiCalls;
  977. // first remove ourselves from MAPISVC.INF
  978. if(!GetSystemDirectory(szMapisvcFile, sizeof(szMapisvcFile)/sizeof(TCHAR)))
  979. {
  980. rc = GetLastError();
  981. VERBOSE (GENERAL_ERR,
  982. TEXT("GetSystemDirectory failed (ec: %ld)."),
  983. rc);
  984. goto exit;
  985. }
  986. _tcscat(szMapisvcFile, TEXT("\\mapisvc.inf"));
  987. VERBOSE (DBG_MSG,
  988. TEXT("The mapi file is %s."),
  989. szMapisvcFile);
  990. if (!WritePrivateProfileString( TEXT("Default Services"),
  991. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  992. NULL,
  993. szMapisvcFile
  994. ))
  995. {
  996. rc = GetLastError();
  997. VERBOSE (GENERAL_ERR,
  998. TEXT("WritePrivateProfileString failed (ec: %ld)."),
  999. rc);
  1000. goto exit;
  1001. }
  1002. if (!WritePrivateProfileString( TEXT("Services"),
  1003. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1004. NULL,
  1005. szMapisvcFile
  1006. ))
  1007. {
  1008. rc = GetLastError();
  1009. VERBOSE (GENERAL_ERR,
  1010. TEXT("WritePrivateProfileString failed (ec: %ld)."),
  1011. rc);
  1012. goto exit;
  1013. }
  1014. if (!WritePrivateProfileString( FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1015. NULL,
  1016. NULL,
  1017. szMapisvcFile
  1018. ))
  1019. {
  1020. rc = GetLastError();
  1021. VERBOSE (GENERAL_ERR,
  1022. TEXT("WritePrivateProfileString failed (ec: %ld)."),
  1023. rc);
  1024. goto exit;
  1025. }
  1026. if (!WritePrivateProfileString( FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1027. NULL,
  1028. NULL,
  1029. szMapisvcFile
  1030. ))
  1031. {
  1032. rc = GetLastError();
  1033. VERBOSE (GENERAL_ERR,
  1034. TEXT("WritePrivateProfileString failed (ec: %ld)."),
  1035. rc);
  1036. goto exit;
  1037. }
  1038. // now remove the MAPI Service provider
  1039. rc = rmcRouteMapiCalls.Init(_T("msiexec.exe"));
  1040. if (rc!=ERROR_SUCCESS)
  1041. {
  1042. CALL_FAIL(GENERAL_ERR, TEXT("CRouteMAPICalls::Init failed (ec: %ld)."), rc);
  1043. goto exit;
  1044. }
  1045. hMapiDll = LoadLibrary(_T("MAPI32.DLL"));
  1046. if (NULL == hMapiDll)
  1047. {
  1048. CALL_FAIL(GENERAL_ERR, TEXT("LoadLibrary"), GetLastError());
  1049. goto exit;
  1050. }
  1051. fnMapiInitialize = (LPMAPIINITIALIZE)GetProcAddress(hMapiDll, "MAPIInitialize");
  1052. if (NULL == fnMapiInitialize)
  1053. {
  1054. CALL_FAIL(GENERAL_ERR, TEXT("GetProcAddress(MAPIInitialize)"), GetLastError());
  1055. goto exit;
  1056. }
  1057. fnMapiAdminProfiles = (LPMAPIADMINPROFILES)GetProcAddress(hMapiDll, "MAPIAdminProfiles");
  1058. if (NULL == fnMapiAdminProfiles)
  1059. {
  1060. CALL_FAIL(GENERAL_ERR, TEXT("GetProcAddress(fnMapiAdminProfiles)"), GetLastError());
  1061. goto exit;
  1062. }
  1063. fnMapiUninitialize = (LPMAPIUNINITIALIZE)GetProcAddress(hMapiDll, "MAPIUninitialize");
  1064. if (NULL == fnMapiUninitialize)
  1065. {
  1066. CALL_FAIL(GENERAL_ERR, TEXT("GetProcAddress(MAPIUninitialize)"), GetLastError());
  1067. goto exit;
  1068. }
  1069. // get access to MAPI functinality
  1070. hr = fnMapiInitialize(NULL);
  1071. if (FAILED(hr))
  1072. {
  1073. VERBOSE (GENERAL_ERR,
  1074. TEXT("MAPIInitialize failed (ec: %ld)."),
  1075. rc = hr);
  1076. goto exit;
  1077. }
  1078. bMapiInitialized = TRUE;
  1079. // get admin profile object
  1080. hr = fnMapiAdminProfiles(0,&lpProfAdmin);
  1081. if (FAILED(hr))
  1082. {
  1083. VERBOSE (GENERAL_ERR,
  1084. TEXT("MAPIAdminProfiles failed (ec: %ld)."),
  1085. rc = hr);
  1086. goto exit;
  1087. }
  1088. // get profile table
  1089. hr = lpProfAdmin->GetProfileTable(0,&lpTable);
  1090. if (FAILED(hr))
  1091. {
  1092. VERBOSE (GENERAL_ERR,
  1093. TEXT("GetProfileTable failed (ec: %ld)."),
  1094. rc = hr);
  1095. goto exit;
  1096. }
  1097. // get profile rows
  1098. hr = lpTable->QueryRows(4000, 0, &lpSRowSet);
  1099. if (FAILED(hr))
  1100. {
  1101. VERBOSE (GENERAL_ERR,
  1102. TEXT("QueryRows failed (ec: %ld)."),
  1103. hr);
  1104. goto exit;
  1105. }
  1106. for (iIndex=0; iIndex<(int)lpSRowSet->cRows; iIndex++)
  1107. {
  1108. lpProp = &lpSRowSet->aRow[iIndex].lpProps[0];
  1109. if (lpProp->ulPropTag != PR_DISPLAY_NAME_A)
  1110. {
  1111. VERBOSE (GENERAL_ERR,
  1112. TEXT("Property is %d, should be PR_DISPLAY_NAME_A."),
  1113. lpProp->ulPropTag);
  1114. hr = HRESULT_FROM_WIN32(ERROR_INVALID_TABLE);
  1115. goto exit;
  1116. }
  1117. hr = lpProfAdmin->AdminServices(LPTSTR(lpProp->Value.lpszA),NULL,0,0,&lpServiceAdmin);
  1118. if (FAILED(hr))
  1119. {
  1120. VERBOSE (GENERAL_ERR,
  1121. TEXT("AdminServices failed (ec: %ld)."),
  1122. rc = hr);
  1123. goto exit;
  1124. }
  1125. hr = RemoveTrasportProviderFromProfile(lpServiceAdmin);
  1126. if (FAILED(hr))
  1127. {
  1128. VERBOSE (GENERAL_ERR,
  1129. TEXT("RemoveTrasportProviderFromProfile failed (ec: %ld)."),
  1130. rc = hr);
  1131. goto exit;
  1132. }
  1133. }
  1134. exit:
  1135. if (bMapiInitialized)
  1136. {
  1137. fnMapiUninitialize();
  1138. }
  1139. if (hMapiDll)
  1140. {
  1141. FreeLibrary(hMapiDll);
  1142. hMapiDll = NULL;
  1143. }
  1144. return rc;
  1145. }
  1146. //
  1147. //
  1148. // Function: AddOutlookExtension
  1149. // Description: Add fax as outlook provider. Write into the MAPI file: 'mapisvc.inf'
  1150. // This function is exported by the DLL for use by the MSI as custom action.
  1151. // In case of failure , returns ERROR_INSTALL_FAILURE
  1152. // In case of success , returns ERROR_SUCCESS
  1153. // GetLastError() to get the error code in case of failure, the error is of the first error that occured.
  1154. //
  1155. // Remarks:
  1156. //
  1157. // Args:
  1158. //
  1159. // hInstall : Handle from MSI, can get state of the current setup
  1160. //
  1161. // Author: AsafS
  1162. DLL_API UINT __stdcall AddOutlookExtension(MSIHANDLE hInstall)
  1163. {
  1164. TCHAR szMapisvcFile[2 * MAX_PATH] = {0};
  1165. TCHAR szDisplayName[MAX_PATH] = {0};
  1166. DWORD err = 0;
  1167. DWORD rc = ERROR_SUCCESS;
  1168. DBG_ENTER(TEXT("AddOutlookExtension"), rc);
  1169. if(!GetSystemDirectory(szMapisvcFile, sizeof(szMapisvcFile)/sizeof(TCHAR)))
  1170. {
  1171. VERBOSE (GENERAL_ERR,
  1172. TEXT("GetSystemDirectory failed (ec: %ld)."),
  1173. GetLastError ());
  1174. goto error;
  1175. }
  1176. _tcscat(szMapisvcFile, TEXT("\\mapisvc.inf"));
  1177. VERBOSE (DBG_MSG,
  1178. TEXT("The mapi file is %s."),
  1179. szMapisvcFile);
  1180. if (!LoadString(
  1181. g_hModule,
  1182. IDS_FAXXP_DISPLAY_NAME,
  1183. szDisplayName,
  1184. sizeof(szDisplayName)/sizeof(TCHAR)
  1185. )) goto error;
  1186. err++;
  1187. if (!WritePrivateProfileString(
  1188. TEXT("Default Services"),
  1189. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1190. szDisplayName,
  1191. szMapisvcFile
  1192. )) goto error;
  1193. err++;
  1194. if (!WritePrivateProfileString(
  1195. TEXT("Services"),
  1196. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1197. szDisplayName,
  1198. szMapisvcFile
  1199. )) goto error;
  1200. err++;
  1201. if (!WritePrivateProfileString(
  1202. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1203. TEXT("PR_DISPLAY_NAME"),
  1204. szDisplayName,
  1205. szMapisvcFile
  1206. )) goto error;
  1207. err++;
  1208. if (!WritePrivateProfileString(
  1209. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1210. TEXT("Providers"),
  1211. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1212. szMapisvcFile
  1213. )) goto error;
  1214. err++;
  1215. if (!WritePrivateProfileString(
  1216. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1217. TEXT("PR_SERVICE_DLL_NAME"),
  1218. FAX_MESSAGE_TRANSPORT_IMAGE_NAME_T,
  1219. szMapisvcFile
  1220. )) goto error;
  1221. err++;
  1222. if (!WritePrivateProfileString(
  1223. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1224. TEXT("PR_SERVICE_SUPPORT_FILES"),
  1225. FAX_MESSAGE_TRANSPORT_IMAGE_NAME_T,
  1226. szMapisvcFile
  1227. )) goto error;
  1228. err++;
  1229. if (!WritePrivateProfileString(
  1230. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1231. TEXT("PR_SERVICE_ENTRY_NAME"),
  1232. TEXT("ServiceEntry"),
  1233. szMapisvcFile
  1234. )) goto error;
  1235. err++;
  1236. if (!WritePrivateProfileString(
  1237. FAX_MESSAGE_SERVICE_NAME_SBS50_T,
  1238. TEXT("PR_RESOURCE_FLAGS"),
  1239. TEXT("SERVICE_SINGLE_COPY|SERVICE_NO_PRIMARY_IDENTITY"),
  1240. szMapisvcFile
  1241. )) goto error;
  1242. err++;
  1243. if (!WritePrivateProfileString(
  1244. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1245. TEXT("PR_PROVIDER_DLL_NAME"),
  1246. FAX_MESSAGE_TRANSPORT_IMAGE_NAME_T,
  1247. szMapisvcFile
  1248. )) goto error;
  1249. err++;
  1250. if (!WritePrivateProfileString(
  1251. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1252. TEXT("PR_RESOURCE_TYPE"),
  1253. TEXT("MAPI_TRANSPORT_PROVIDER"),
  1254. szMapisvcFile
  1255. )) goto error;
  1256. err++;
  1257. if (!WritePrivateProfileString(
  1258. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1259. TEXT("PR_RESOURCE_FLAGS"),
  1260. TEXT("STATUS_NO_DEFAULT_STORE"),
  1261. szMapisvcFile
  1262. )) goto error;
  1263. err++;
  1264. if (!WritePrivateProfileString(
  1265. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1266. TEXT("PR_DISPLAY_NAME"),
  1267. szDisplayName,
  1268. szMapisvcFile
  1269. )) goto error;
  1270. err++;
  1271. if (!WritePrivateProfileString(
  1272. FAX_MESSAGE_PROVIDER_NAME_SBS50_T,
  1273. TEXT("PR_PROVIDER_DISPLAY"),
  1274. szDisplayName,
  1275. szMapisvcFile
  1276. )) goto error;
  1277. err++;
  1278. return rc;
  1279. error:
  1280. VERBOSE (GENERAL_ERR,
  1281. TEXT("CustomAction AddOutlookExtension() failed ! (ec: %ld) (err = %ld)"),
  1282. GetLastError(),
  1283. err
  1284. );
  1285. rc = ERROR_INSTALL_FAILURE;
  1286. return rc;
  1287. }
  1288. #define COMCTL32_401 PACKVERSION (4,72)
  1289. DLL_API UINT __stdcall IsComctlRequiresUpdate(MSIHANDLE hInstall)
  1290. {
  1291. UINT uiRet = ERROR_SUCCESS;
  1292. BOOL bRes = FALSE;
  1293. DWORD dwVer = 0;
  1294. DBG_ENTER(TEXT("IsComctlRequiresUpdate"), uiRet);
  1295. dwVer = GetDllVersion(TEXT("comctl32.dll"));
  1296. VERBOSE (DBG_MSG,
  1297. TEXT("Current COMCTL32 version is 0x%08X."),
  1298. dwVer);
  1299. if (COMCTL32_401 > dwVer)
  1300. {
  1301. VERBOSE (DBG_MSG,
  1302. TEXT("COMCTL32.DLL requires update."));
  1303. bRes = TRUE;
  1304. }
  1305. uiRet = MsiSetProperty( hInstall,
  1306. _T("IsComctlRequiresUpdate"),
  1307. bRes ? _T("TRUE") : _T("FALSE"));
  1308. if (uiRet!=ERROR_SUCCESS)
  1309. {
  1310. VERBOSE (DBG_MSG,
  1311. TEXT("MsiSetProperty IsComctlRequiresUpdate failed."));
  1312. }
  1313. return uiRet;
  1314. }
  1315. typedef struct _TypeCommand
  1316. {
  1317. LPCTSTR lpctstrType;
  1318. LPCTSTR lpctstrFolder;
  1319. LPCTSTR lpctstrCommand;
  1320. } TypeCommand;
  1321. static TypeCommand tcWin9XCommand[] =
  1322. {
  1323. // Win9X PrintTo verbs
  1324. { _T("txtfile"), _T("WindowsFolder"), _T("write.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1325. { _T("jpegfile"), _T("WindowsFolder"), _T("pbrush.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1326. };
  1327. static TypeCommand tcWinMECommand[] =
  1328. {
  1329. // WinME PrintTo verbs
  1330. { _T("txtfile"), _T("WindowsFolder"), _T("write.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1331. { _T("jpegfile"), _T("WindowsFolder"), _T("pbrush.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1332. { _T("giffile"), _T("WindowsFolder"), _T("pbrush.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1333. { _T("Paint.Picture"), _T("WindowsFolder"), _T("pbrush.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1334. };
  1335. static TypeCommand tcWin2KCommand[] =
  1336. {
  1337. // NT4 PrintTo verbs
  1338. { _T("txtfile"), _T("SystemFolder"), _T("write.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1339. { _T("jpegfile"), _T("SystemFolder"), _T("mspaint.exe /pt \"%1\" \"%2\" \"%3\" \"%4") },
  1340. };
  1341. static int iCountWin9XCommands = sizeof(tcWin9XCommand)/sizeof(tcWin9XCommand[0]);
  1342. static int iCountWinMECommands = sizeof(tcWinMECommand)/sizeof(tcWinMECommand[0]);
  1343. static int iCountWin2KCommands = sizeof(tcWin2KCommand)/sizeof(tcWin2KCommand[0]);
  1344. //
  1345. //
  1346. // Function: CrearePrintToVerb
  1347. //
  1348. // Description: Creates the PrintTo verb for text files to associate it with wordpad
  1349. // if the PrintTo verb already exists, this function does nothing.
  1350. //
  1351. // Remarks:
  1352. // on Win9x
  1353. // txtfile - PrintTo = <WindowsFolder>\write.exe /pt "%1" "%2" "%3" "%4"
  1354. // jpegfile - PrintTo = <WindowsFolder>\pbrush.exe /pt "%1" "%2" "%3" "%4"
  1355. //
  1356. // on WinME
  1357. // txtfile - PrintTo = <WindowsFolder>\write.exe /pt "%1" "%2" "%3" "%4"
  1358. // jpegfile - PrintTo = <WindowsFolder>\pbrush.exe /pt "%1" "%2" "%3" "%4"
  1359. // giffile - PrintTo = <WindowsFolder>\pbrush.exe /pt "%1" "%2" "%3" "%4"
  1360. // Paint.Picture - PrintTo = <WindowsFolder>\pbrush.exe /pt "%1" "%2" "%3" "%4"
  1361. //
  1362. // on NT4
  1363. // txtfile - PrintTo = <SystemFolder>\write.exe /pt "%1" "%2" "%3" "%4"
  1364. // jpegfile - PrintTo = <SystemFolder>\mspaint.exe /pt "%1" "%2" "%3" "%4"
  1365. // Args:
  1366. //
  1367. // hInstall : Handle from MSI, can get state of the current setup
  1368. //
  1369. // Author: MoolyB
  1370. DLL_API UINT __stdcall CreatePrintToVerb(MSIHANDLE hInstall)
  1371. {
  1372. UINT uiRet = ERROR_SUCCESS;
  1373. LPCTSTR lpctstrPrintToCommand = _T("\\shell\\printto\\command");
  1374. int iCount = 0;
  1375. DWORD cchValue = MAX_PATH;
  1376. TCHAR szValueBuf[MAX_PATH] = {0};
  1377. TCHAR szKeyBuf[MAX_PATH] = {0};
  1378. BOOL bOverwriteExisting = FALSE;
  1379. LONG rVal = 0;
  1380. HKEY hKey = NULL;
  1381. HKEY hCommandKey = NULL;
  1382. TypeCommand* pTypeCommand = NULL;
  1383. int iCommandCount = 0;
  1384. OSVERSIONINFO osv;
  1385. DBG_ENTER(TEXT("CreatePrintToVerb"),uiRet);
  1386. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1387. if (!GetVersionEx(&osv))
  1388. {
  1389. uiRet = GetLastError();
  1390. VERBOSE(GENERAL_ERR,
  1391. _T("GetVersionEx failed: (ec=%d)"),
  1392. uiRet);
  1393. goto exit;
  1394. }
  1395. if (osv.dwPlatformId==VER_PLATFORM_WIN32_NT)
  1396. {
  1397. VERBOSE (DBG_MSG, _T("This is NT4/NT5"));
  1398. pTypeCommand = tcWin2KCommand;
  1399. iCommandCount = iCountWin2KCommands;
  1400. }
  1401. else if (osv.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
  1402. {
  1403. if (osv.dwMinorVersion>=90)
  1404. {
  1405. VERBOSE (DBG_MSG, _T("This is WinME"));
  1406. pTypeCommand = tcWinMECommand;
  1407. iCommandCount = iCountWinMECommands;
  1408. bOverwriteExisting = TRUE;
  1409. }
  1410. else
  1411. {
  1412. VERBOSE (DBG_MSG, _T("This is Win9X"));
  1413. pTypeCommand = tcWin9XCommand;
  1414. iCommandCount = iCountWin9XCommands;
  1415. }
  1416. }
  1417. else
  1418. {
  1419. VERBOSE (GENERAL_ERR, _T("This is an illegal OS"));
  1420. uiRet = ERROR_INVALID_PARAMETER;
  1421. goto exit;
  1422. }
  1423. for (iCount=0; iCount<iCommandCount; iCount++)
  1424. {
  1425. _tcscpy(szKeyBuf,pTypeCommand[iCount].lpctstrType);
  1426. _tcscat(szKeyBuf,lpctstrPrintToCommand);
  1427. // go get the appropriate folder from Windows Installer
  1428. if (!PrivateMsiGetProperty( hInstall,
  1429. pTypeCommand[iCount].lpctstrFolder,
  1430. szValueBuf))
  1431. {
  1432. VERBOSE (SETUP_ERR,
  1433. TEXT("PrivateMsiGetProperty failed (ec: %ld)"),
  1434. GetLastError());
  1435. goto exit;
  1436. }
  1437. if (_tcslen(szValueBuf)+_tcslen(pTypeCommand[iCount].lpctstrCommand)>=MAX_PATH-1)
  1438. {
  1439. VERBOSE (SETUP_ERR,
  1440. TEXT("command to create is too long"));
  1441. uiRet = ERROR_INVALID_PARAMETER;
  1442. goto exit;
  1443. }
  1444. _tcscat(szValueBuf,pTypeCommand[iCount].lpctstrCommand);
  1445. // if we should not replace existing keys, let's check if it exists
  1446. if (!bOverwriteExisting)
  1447. {
  1448. uiRet = RegOpenKey( HKEY_CLASSES_ROOT,
  1449. szKeyBuf,
  1450. &hKey);
  1451. if (uiRet==ERROR_SUCCESS)
  1452. {
  1453. // this means we should skip this key
  1454. RegCloseKey(hKey);
  1455. VERBOSE(DBG_MSG,
  1456. _T("RegOpenKey:PrintTo succedded, no change in PrintTo verb for %s"),
  1457. pTypeCommand[iCount].lpctstrType);
  1458. continue;
  1459. }
  1460. else
  1461. {
  1462. if (uiRet==ERROR_FILE_NOT_FOUND)
  1463. {
  1464. VERBOSE(DBG_MSG,
  1465. _T("PrintTo verb does not exist for %s, creating..."),
  1466. pTypeCommand[iCount].lpctstrType);
  1467. }
  1468. else
  1469. {
  1470. VERBOSE (REGISTRY_ERR,
  1471. TEXT("Could not open registry key %s (ec=0x%08x)"),
  1472. szKeyBuf,
  1473. uiRet);
  1474. goto exit;
  1475. }
  1476. }
  1477. }
  1478. // if we're here, we should create the key
  1479. uiRet = RegCreateKey( HKEY_CLASSES_ROOT,
  1480. szKeyBuf,
  1481. &hCommandKey);
  1482. if (uiRet!=ERROR_SUCCESS)
  1483. {
  1484. VERBOSE (REGISTRY_ERR,
  1485. TEXT("Could not create registry key %s (ec=0x%08x)"),
  1486. szKeyBuf,
  1487. uiRet);
  1488. goto exit;
  1489. }
  1490. uiRet = RegSetValue(hCommandKey,
  1491. NULL,
  1492. REG_SZ,
  1493. szValueBuf,
  1494. sizeof(szValueBuf));
  1495. if (uiRet==ERROR_SUCCESS)
  1496. {
  1497. VERBOSE(DBG_MSG,
  1498. _T("RegSetValue success: %s "),
  1499. szValueBuf);
  1500. }
  1501. else
  1502. {
  1503. VERBOSE (REGISTRY_ERR,
  1504. TEXT("Could not set value registry key %s\\shell\\printto\\command to %s (ec=0x%08x)"),
  1505. pTypeCommand[iCount].lpctstrType,
  1506. szValueBuf,
  1507. uiRet);
  1508. goto exit;
  1509. }
  1510. if (hKey)
  1511. {
  1512. RegCloseKey(hKey);
  1513. }
  1514. if (hCommandKey)
  1515. {
  1516. RegCloseKey(hCommandKey);
  1517. }
  1518. }
  1519. exit:
  1520. if (hKey)
  1521. {
  1522. RegCloseKey(hKey);
  1523. }
  1524. if (hCommandKey)
  1525. {
  1526. RegCloseKey(hCommandKey);
  1527. }
  1528. return uiRet;
  1529. }
  1530. /*-----------------------------------------------------------------*/
  1531. /* DPSetDefaultPrinter */
  1532. /* */
  1533. /* Parameters: */
  1534. /* pPrinterName: Valid name of existing printer to make default. */
  1535. /* */
  1536. /* Returns: TRUE for success, FALSE for failure. */
  1537. /*-----------------------------------------------------------------*/
  1538. BOOL SetDefaultPrinter(LPTSTR pPrinterName)
  1539. {
  1540. OSVERSIONINFO osv;
  1541. DWORD dwNeeded = 0;
  1542. HANDLE hPrinter = NULL;
  1543. PPRINTER_INFO_2 ppi2 = NULL;
  1544. LPTSTR pBuffer = NULL;
  1545. BOOL bRes = TRUE;
  1546. PPRINTER_INFO_2 pPrinterInfo = NULL;
  1547. DWORD dwNumPrinters = 0;
  1548. DBG_ENTER(TEXT("SetDefaultPrinter"),bRes);
  1549. // What version of Windows are you running?
  1550. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1551. if (!GetVersionEx(&osv))
  1552. {
  1553. VERBOSE(GENERAL_ERR,
  1554. _T("GetVersionEx failed: (ec=%d)"),
  1555. GetLastError());
  1556. bRes = FALSE;
  1557. goto exit;
  1558. }
  1559. // If Windows NT, use WriteProfileString for version 4.0 and earlier...
  1560. if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
  1561. {
  1562. VERBOSE (DBG_MSG,
  1563. TEXT("W9X OS, not setting default printer"));
  1564. goto exit;
  1565. }
  1566. if (osv.dwMajorVersion >= 5) // Windows 2000 or later...
  1567. {
  1568. VERBOSE (DBG_MSG,
  1569. TEXT("W2K OS, not setting default printer"));
  1570. goto exit;
  1571. }
  1572. // are we the only printer installed?
  1573. pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL,
  1574. 2,
  1575. &dwNumPrinters,
  1576. PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL
  1577. );
  1578. if (!pPrinterInfo)
  1579. {
  1580. VERBOSE (GENERAL_ERR,
  1581. TEXT("MyEnumPrinters() failed (ec: %ld)"),
  1582. GetLastError());
  1583. bRes = FALSE;
  1584. goto exit;
  1585. }
  1586. if (dwNumPrinters!=1)
  1587. {
  1588. VERBOSE (DBG_MSG,
  1589. TEXT("More than one printer installed on NT4, not setting default printer"));
  1590. goto exit;
  1591. }
  1592. // Open this printer so you can get information about it...
  1593. if (!OpenPrinter(pPrinterName, &hPrinter, NULL))
  1594. {
  1595. VERBOSE(GENERAL_ERR,
  1596. _T("OpenPrinter failed: (ec=%d)"),
  1597. GetLastError());
  1598. bRes = FALSE;
  1599. goto exit;
  1600. }
  1601. // The first GetPrinter() tells you how big our buffer should
  1602. // be in order to hold ALL of PRINTER_INFO_2. Note that this will
  1603. // usually return FALSE. This only means that the buffer (the 3rd
  1604. // parameter) was not filled in. You don't want it filled in here...
  1605. if (!GetPrinter(hPrinter, 2, 0, 0, &dwNeeded))
  1606. {
  1607. if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
  1608. {
  1609. VERBOSE(GENERAL_ERR,
  1610. _T("GetPrinter failed: (ec=%d)"),
  1611. GetLastError());
  1612. bRes = FALSE;
  1613. goto exit;
  1614. }
  1615. }
  1616. // Allocate enough space for PRINTER_INFO_2...
  1617. ppi2 = (PRINTER_INFO_2 *)MemAlloc(dwNeeded);
  1618. if (!ppi2)
  1619. {
  1620. VERBOSE(GENERAL_ERR,
  1621. _T("MemAlloc failed"));
  1622. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1623. bRes = FALSE;
  1624. goto exit;
  1625. }
  1626. // The second GetPrinter() fills in all the current<BR/>
  1627. // information...
  1628. if (!GetPrinter(hPrinter, 2, (LPBYTE)ppi2, dwNeeded, &dwNeeded))
  1629. {
  1630. VERBOSE(GENERAL_ERR,
  1631. _T("GetPrinter failed: (ec=%d)"),
  1632. GetLastError());
  1633. bRes = FALSE;
  1634. goto exit;
  1635. }
  1636. if ((!ppi2->pDriverName) || (!ppi2->pPortName))
  1637. {
  1638. VERBOSE(GENERAL_ERR,
  1639. _T("pDriverName or pPortNameare NULL"));
  1640. SetLastError(ERROR_INVALID_PARAMETER);
  1641. bRes = FALSE;
  1642. goto exit;
  1643. }
  1644. // Allocate buffer big enough for concatenated string.
  1645. // String will be in form "printername,drivername,portname"...
  1646. pBuffer = (LPTSTR)MemAlloc( ( _tcslen(pPrinterName) +
  1647. _tcslen(ppi2->pDriverName) +
  1648. _tcslen(ppi2->pPortName) + 3) *
  1649. sizeof(TCHAR) );
  1650. if (!pBuffer)
  1651. {
  1652. VERBOSE(GENERAL_ERR,
  1653. _T("MemAlloc failed"));
  1654. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1655. bRes = FALSE;
  1656. goto exit;
  1657. }
  1658. // Build string in form "printername,drivername,portname"...
  1659. _tcscpy(pBuffer, pPrinterName);
  1660. _tcscat(pBuffer, _T(","));
  1661. _tcscat(pBuffer, ppi2->pDriverName);
  1662. _tcscat(pBuffer, _T(","));
  1663. _tcscat(pBuffer, ppi2->pPortName);
  1664. // Set the default printer in Win.ini and registry...
  1665. if (!WriteProfileString(_T("windows"), _T("device"), pBuffer))
  1666. {
  1667. VERBOSE(GENERAL_ERR,
  1668. _T("WriteProfileString failed: (ec=%d)"),
  1669. GetLastError());
  1670. bRes = FALSE;
  1671. goto exit;
  1672. }
  1673. // Tell all open applications that this change occurred.
  1674. // Allow each app 1 second to handle this message.
  1675. if (!SendMessageTimeout( HWND_BROADCAST,
  1676. WM_SETTINGCHANGE,
  1677. 0L,
  1678. 0L,
  1679. SMTO_NORMAL,
  1680. 1000,
  1681. NULL))
  1682. {
  1683. VERBOSE(GENERAL_ERR,
  1684. _T("SendMessageTimeout failed: (ec=%d)"),
  1685. GetLastError());
  1686. bRes = FALSE;
  1687. goto exit;
  1688. }
  1689. exit:
  1690. // Cleanup...
  1691. if (pPrinterInfo)
  1692. {
  1693. MemFree(pPrinterInfo);
  1694. }
  1695. if (hPrinter)
  1696. {
  1697. ClosePrinter(hPrinter);
  1698. }
  1699. if (ppi2)
  1700. {
  1701. MemFree(ppi2);
  1702. }
  1703. if (pBuffer)
  1704. {
  1705. MemFree(pBuffer);
  1706. }
  1707. return bRes;
  1708. }
  1709. //
  1710. //
  1711. // Function: CheckForceReboot
  1712. //
  1713. // Description: This function checks if the ForceReboot flag is set in the registry
  1714. // if it is, signals WindowsInstaller that a reboot is needed
  1715. //
  1716. // Remarks:
  1717. // this is due to a bug in the Install Shield bootstrap which doesn't
  1718. // force a reboot after initial installation of WindowsIsntaller.
  1719. // this flag is set by our custom bootstrap before running the
  1720. // Install Shield bootstrap
  1721. // if we are run from the Application Launcher then we need to leave
  1722. // this registry entry for the Launcher to reboot, we know this by
  1723. // using the property APPLAUNCHER=TRUE
  1724. // Args:
  1725. //
  1726. // hInstall : Handle from MSI, can get state of the current setup
  1727. //
  1728. // Author: MoolyB
  1729. DLL_API UINT __stdcall CheckForceReboot(MSIHANDLE hInstall)
  1730. {
  1731. UINT uiRet = ERROR_SUCCESS;
  1732. TCHAR szPropBuffer[MAX_PATH] = {0};
  1733. HKEY hKey = NULL;
  1734. DWORD Size = sizeof(DWORD);
  1735. DWORD Value = 0;
  1736. LONG Rslt;
  1737. DWORD Type;
  1738. DBG_ENTER(TEXT("CheckForceReboot"),uiRet);
  1739. // check if we're running from the AppLauncher
  1740. if (!PrivateMsiGetProperty(hInstall,_T("APPLAUNCHER"),szPropBuffer))
  1741. {
  1742. VERBOSE (SETUP_ERR,
  1743. TEXT("PrivateMsiGetProperty failed (ec: %ld)"),
  1744. GetLastError());
  1745. goto exit;
  1746. }
  1747. if (_tcscmp(szPropBuffer,_T("TRUE"))==0)
  1748. {
  1749. // we're running from the Application Launcher, the registry entry DeferredReboot
  1750. // is sufficient.
  1751. VERBOSE(DBG_MSG,
  1752. _T("AppLauncher will take care of any needed boot"));
  1753. goto exit;
  1754. }
  1755. // open HKLM\\Software\\Microsoft\\SharedFax
  1756. Rslt = RegOpenKeyEx(
  1757. HKEY_LOCAL_MACHINE,
  1758. REGKEY_SBS2000_FAX_SETUP,
  1759. 0,
  1760. KEY_READ,
  1761. &hKey
  1762. );
  1763. if (Rslt != ERROR_SUCCESS)
  1764. {
  1765. VERBOSE(DBG_MSG,
  1766. _T("RegOpenKeyEx failed: (ec=%d)"),
  1767. GetLastError());
  1768. goto exit;
  1769. }
  1770. // check if ForceReboot flag exists
  1771. Rslt = RegQueryValueEx(
  1772. hKey,
  1773. DEFERRED_BOOT,
  1774. NULL,
  1775. &Type,
  1776. (LPBYTE) &Value,
  1777. &Size
  1778. );
  1779. if (Rslt!=ERROR_SUCCESS)
  1780. {
  1781. VERBOSE(DBG_MSG,
  1782. _T("RegQueryValueEx failed: (ec=%d)"),
  1783. GetLastError());
  1784. goto exit;
  1785. }
  1786. // tell WindowsInstaller a reboot is needed
  1787. uiRet = MsiSetProperty(hInstall,_T("REBOOT"),_T("Force"));
  1788. if (uiRet!=ERROR_SUCCESS)
  1789. {
  1790. VERBOSE(DBG_MSG,
  1791. _T("MsiSetProperty failed: (ec=%d)"),
  1792. uiRet);
  1793. goto exit;
  1794. }
  1795. // delete ForceReboot flag
  1796. Rslt = RegDeleteValue(hKey,DEFERRED_BOOT);
  1797. if (Rslt!=ERROR_SUCCESS)
  1798. {
  1799. VERBOSE(DBG_MSG,
  1800. _T("MsiSetMode failed: (ec=%d)"),
  1801. Rslt);
  1802. goto exit;
  1803. }
  1804. exit:
  1805. if (hKey)
  1806. {
  1807. RegCloseKey(hKey);
  1808. }
  1809. return uiRet;
  1810. }
  1811. #define KODAKPRV_EXE_NAME _T("\\KODAKPRV.EXE")
  1812. #define TIFIMAGE_COMMAND_KEY _T("TIFImage.Document\\shell\\open\\command")
  1813. #define TIFIMAGE_DDEEXEC_KEY _T("TIFImage.Document\\shell\\open\\ddeexec")
  1814. //
  1815. //
  1816. // Function: ChangeTifAssociation
  1817. //
  1818. // Description: This function changes the open verb for TIF files
  1819. // on WinME from Image Preview to Kodak Imaging
  1820. //
  1821. // Remarks:
  1822. // this is due to bad quality of viewing TIF faxes in the Image Preview tool
  1823. //
  1824. // Args:
  1825. //
  1826. // hInstall : Handle from MSI, can get state of the current setup
  1827. //
  1828. // Author: MoolyB
  1829. DLL_API UINT __stdcall ChangeTifAssociation(MSIHANDLE hInstall)
  1830. {
  1831. UINT uiRet = ERROR_SUCCESS;
  1832. TCHAR szWindowsDirectory[MAX_PATH] = {0};
  1833. HANDLE hFind = INVALID_HANDLE_VALUE;
  1834. HKEY hKey = NULL;
  1835. LONG lRet = 0;
  1836. OSVERSIONINFO viVersionInfo;
  1837. WIN32_FIND_DATA FindFileData;
  1838. DBG_ENTER(TEXT("ChangeTifAssociation"),uiRet);
  1839. viVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1840. if (!GetVersionEx(&viVersionInfo))
  1841. {
  1842. uiRet = GetLastError();
  1843. VERBOSE( SETUP_ERR,
  1844. TEXT("GetVersionEx failed (ec: %ld)"),
  1845. uiRet);
  1846. goto exit;
  1847. }
  1848. // Is this millennium?
  1849. if (!
  1850. ( (viVersionInfo.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) &&
  1851. (viVersionInfo.dwMajorVersion==4) &&
  1852. (viVersionInfo.dwMinorVersion>=90)
  1853. )
  1854. )
  1855. {
  1856. VERBOSE(DBG_MSG,
  1857. _T("This is not Windows Millenium, exit fucntion"));
  1858. goto exit;
  1859. }
  1860. // find <WindowsFolder>\KODAKPRV.EXE
  1861. if (GetWindowsDirectory(szWindowsDirectory,MAX_PATH)==0)
  1862. {
  1863. uiRet = GetLastError();
  1864. VERBOSE( SETUP_ERR,
  1865. TEXT("GetWindowsDirectory failed (ec: %ld)"),
  1866. uiRet);
  1867. goto exit;
  1868. }
  1869. if (_tcslen(KODAKPRV_EXE_NAME)+_tcslen(szWindowsDirectory)>=MAX_PATH-4)
  1870. {
  1871. VERBOSE( SETUP_ERR,
  1872. TEXT("Path to Kodak Imaging too long"));
  1873. uiRet = ERROR_INVALID_PARAMETER;
  1874. goto exit;
  1875. }
  1876. _tcscat(szWindowsDirectory,KODAKPRV_EXE_NAME);
  1877. hFind = FindFirstFile(szWindowsDirectory, &FindFileData);
  1878. if (hFind==INVALID_HANDLE_VALUE)
  1879. {
  1880. uiRet = GetLastError();
  1881. VERBOSE( SETUP_ERR,
  1882. TEXT("FindFirstFile %s failed (ec: %ld)"),
  1883. szWindowsDirectory,
  1884. uiRet);
  1885. goto exit;
  1886. }
  1887. FindClose(hFind);
  1888. _tcscat(szWindowsDirectory,_T(" \"%1\""));
  1889. // set open verb
  1890. lRet = RegOpenKey( HKEY_CLASSES_ROOT,
  1891. TIFIMAGE_COMMAND_KEY,
  1892. &hKey);
  1893. if (lRet!=ERROR_SUCCESS)
  1894. {
  1895. uiRet = GetLastError();
  1896. VERBOSE( SETUP_ERR,
  1897. TEXT("RegOpenKey %s failed (ec: %ld)"),
  1898. TIFIMAGE_COMMAND_KEY,
  1899. uiRet);
  1900. goto exit;
  1901. }
  1902. lRet = RegSetValueEx( hKey,
  1903. NULL,
  1904. 0,
  1905. REG_EXPAND_SZ,
  1906. (LPBYTE) szWindowsDirectory,
  1907. (_tcslen(szWindowsDirectory) + 1) * sizeof (TCHAR)
  1908. );
  1909. if (lRet!=ERROR_SUCCESS)
  1910. {
  1911. uiRet = GetLastError();
  1912. VERBOSE( SETUP_ERR,
  1913. TEXT("RegSetValueEx %s failed (ec: %ld)"),
  1914. szWindowsDirectory,
  1915. uiRet);
  1916. goto exit;
  1917. }
  1918. lRet = RegDeleteKey(HKEY_CLASSES_ROOT,TIFIMAGE_DDEEXEC_KEY);
  1919. if (lRet!=ERROR_SUCCESS)
  1920. {
  1921. uiRet = GetLastError();
  1922. VERBOSE( SETUP_ERR,
  1923. TEXT("RegDeleteKey %s failed (ec: %ld)"),
  1924. TIFIMAGE_DDEEXEC_KEY,
  1925. uiRet);
  1926. goto exit;
  1927. }
  1928. exit:
  1929. if (hKey)
  1930. {
  1931. RegCloseKey(hKey);
  1932. }
  1933. return uiRet;
  1934. }
  1935. #define MAKE_RELATIVE(pMember,pBase) (pMember ? (((UINT)pMember)-UINT(pBase)) : NULL)
  1936. #define MAKE_ABSOLUTE(pMember,pBase) (pMember ? (((UINT)pMember)+UINT(pBase)) : NULL)
  1937. ///////////////////////////////////////////////////////////////////////////////////////
  1938. // Function:
  1939. // FindExistingPrinters
  1940. //
  1941. // Purpose:
  1942. // This function enumerates the existing printers to SBS/BOS 2000
  1943. // Fax servers.
  1944. // The found printers are stored in the registry to be restored
  1945. // after the RemoveExistingProducts is run.
  1946. // Since the upgrade from SBS/BOS2000 requires uninstalling the existing
  1947. // Shared fax service client, the printer connection will be lost unless we
  1948. // save it prior to the removal of the client and restore afterwards.
  1949. //
  1950. // Params:
  1951. // MSIHANDLE hInstall - handle to the instllation package
  1952. //
  1953. // Return Value:
  1954. // NO_ERROR - everything was ok.
  1955. // Win32 Error code in case if failure.
  1956. //
  1957. // Author:
  1958. // Mooly Beery (MoolyB) 28-Oct-2001
  1959. ///////////////////////////////////////////////////////////////////////////////////////
  1960. DLL_API UINT __stdcall FindExistingPrinters(MSIHANDLE hInstall)
  1961. {
  1962. BYTE* pbPrinterInfo = NULL;
  1963. DWORD cb = 0;
  1964. DWORD dwNumPrinters = 0;
  1965. DWORD dwIndex = 0;
  1966. HKEY hKey = NULL;
  1967. DWORD dwRet = ERROR_SUCCESS;
  1968. DBG_ENTER(TEXT("FindExistingPrinters"), dwRet);
  1969. // this call should fail due to lack of space...
  1970. if (EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,NULL,2,NULL,0,&cb,&dwNumPrinters))
  1971. {
  1972. VERBOSE( SETUP_ERR,TEXT("EnumPrinters succeeded with zero buffer, probably no printers."));
  1973. goto exit;
  1974. }
  1975. dwRet = GetLastError();
  1976. if (dwRet!=ERROR_INSUFFICIENT_BUFFER)
  1977. {
  1978. VERBOSE( SETUP_ERR,TEXT("EnumPrinters failed (ec: %ld)"),dwRet);
  1979. goto exit;
  1980. }
  1981. dwRet = ERROR_SUCCESS;
  1982. pbPrinterInfo = (BYTE*)MemAlloc(cb);
  1983. if (!pbPrinterInfo)
  1984. {
  1985. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  1986. VERBOSE( SETUP_ERR,TEXT("MemAlloc failed (ec: %ld)"),dwRet);
  1987. goto exit;
  1988. }
  1989. // Get all existing printers into pbPrinterInfo
  1990. if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,NULL,2,pbPrinterInfo,cb,&cb,&dwNumPrinters))
  1991. {
  1992. dwRet = GetLastError();
  1993. VERBOSE( SETUP_ERR,TEXT("EnumPrinters failed (ec: %ld)"),dwRet);
  1994. goto exit;
  1995. }
  1996. if (dwNumPrinters==0)
  1997. {
  1998. VERBOSE( SETUP_ERR,TEXT("No printers to store"));
  1999. goto exit;
  2000. }
  2001. // fix up pointers in the PRINTER_INFO_2 structure to become relative.
  2002. for ( dwIndex=0 ; dwIndex<dwNumPrinters ; dwIndex++ )
  2003. {
  2004. PPRINTER_INFO_2 pInfo = &((PPRINTER_INFO_2)pbPrinterInfo)[dwIndex];
  2005. VERBOSE(DBG_MSG,_T("Printer ' %s ' will be saved"), pInfo->pPrinterName);
  2006. pInfo->pServerName = LPTSTR(MAKE_RELATIVE(pInfo->pServerName,pInfo));
  2007. pInfo->pPrinterName = LPTSTR(MAKE_RELATIVE(pInfo->pPrinterName,pInfo));
  2008. pInfo->pShareName = LPTSTR(MAKE_RELATIVE(pInfo->pShareName,pInfo));
  2009. pInfo->pPortName = LPTSTR(MAKE_RELATIVE(pInfo->pPortName,pInfo));
  2010. pInfo->pDriverName = LPTSTR(MAKE_RELATIVE(pInfo->pDriverName,pInfo));
  2011. pInfo->pComment = LPTSTR(MAKE_RELATIVE(pInfo->pComment,pInfo));
  2012. pInfo->pLocation = LPTSTR(MAKE_RELATIVE(pInfo->pLocation,pInfo));
  2013. pInfo->pSepFile = LPTSTR(MAKE_RELATIVE(pInfo->pSepFile,pInfo));
  2014. pInfo->pPrintProcessor = LPTSTR(MAKE_RELATIVE(pInfo->pPrintProcessor,pInfo));
  2015. pInfo->pDatatype = LPTSTR(MAKE_RELATIVE(pInfo->pDatatype,pInfo));
  2016. pInfo->pParameters = LPTSTR(MAKE_RELATIVE(pInfo->pParameters,pInfo));
  2017. pInfo->pDevMode = LPDEVMODE(MAKE_RELATIVE(pInfo->pDevMode,pInfo));
  2018. pInfo->pSecurityDescriptor = PSECURITY_DESCRIPTOR(MAKE_RELATIVE(pInfo->pSecurityDescriptor,pInfo));
  2019. }
  2020. // open HKLM\\Software\\Microsoft\\SharedFax\\Setup\\Upgrade
  2021. hKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SBS2000_FAX_SETUP_UPGRADE,TRUE,KEY_WRITE);
  2022. if (!hKey)
  2023. {
  2024. dwRet = GetLastError();
  2025. VERBOSE( SETUP_ERR,TEXT("OpenRegistryKey failed (ec: %ld)"),dwRet);
  2026. goto exit;
  2027. }
  2028. // store pbPrinterInfo to the registry.
  2029. if (!SetRegistryBinary(hKey,REGVAL_STORED_PRINTERS,pbPrinterInfo,cb))
  2030. {
  2031. dwRet = GetLastError();
  2032. VERBOSE( SETUP_ERR,TEXT("SetRegistryBinary failed (ec: %ld)"),dwRet);
  2033. goto exit;
  2034. }
  2035. if (!SetRegistryDword(hKey,REGVAL_STORED_PRINTERS_COUNT,dwNumPrinters))
  2036. {
  2037. dwRet = GetLastError();
  2038. VERBOSE( SETUP_ERR,TEXT("SetRegistryDword failed (ec: %ld)"),dwRet);
  2039. goto exit;
  2040. }
  2041. exit:
  2042. if (pbPrinterInfo)
  2043. {
  2044. MemFree(pbPrinterInfo);
  2045. }
  2046. if (hKey)
  2047. {
  2048. RegCloseKey(hKey);
  2049. }
  2050. return dwRet;
  2051. }
  2052. ///////////////////////////////////////////////////////////////////////////////////////
  2053. // Function:
  2054. // RestorePrinters
  2055. //
  2056. // Purpose:
  2057. // This function reads the list of printers from the registry and restores them
  2058. // the list was stored by a prior call to FindExistingPrinters and what was
  2059. // stored was the the result of a call to EnumPrinters which is an array of
  2060. // PRINTER_INFO_2. this array is scanned now for fax printers and they are
  2061. // restored. this data is kept in the registry during fax client setup since
  2062. // it's practically impossible to transfer large chunks of binary data between
  2063. // two deferred custom actions.
  2064. //
  2065. // Params:
  2066. // MSIHANDLE hInstall - handle to the instllation package
  2067. //
  2068. // Return Value:
  2069. // NO_ERROR - everything was ok.
  2070. // Win32 Error code in case if failure.
  2071. //
  2072. // Author:
  2073. // Mooly Beery (MoolyB) 28-Oct-2001
  2074. ///////////////////////////////////////////////////////////////////////////////////////
  2075. DLL_API UINT __stdcall RestorePrinters(MSIHANDLE hInstall)
  2076. {
  2077. HKEY hKey = NULL;
  2078. BYTE* pPrinterInfo = NULL;
  2079. DWORD cb = 0;
  2080. DWORD dwIndex = 0;
  2081. DWORD dwNumPrinters = 0;
  2082. HANDLE hPrinter = NULL;
  2083. DWORD dwRet = ERROR_SUCCESS;
  2084. BOOL fIsW9X = FALSE;
  2085. OSVERSIONINFO osv;
  2086. DBG_ENTER(TEXT("RestorePrinters"), dwRet);
  2087. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  2088. if (!GetVersionEx(&osv))
  2089. {
  2090. dwRet = GetLastError();
  2091. VERBOSE( SETUP_ERR,TEXT("GetVersionEx failed (ec: %ld)"),dwRet);
  2092. goto exit;
  2093. }
  2094. // If NT4/W2K, use AddPrinterConnection. if W9X, use AddPrinter.
  2095. if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
  2096. {
  2097. fIsW9X = TRUE;
  2098. }
  2099. // open HKLM\\Software\\Microsoft\\SharedFax\\Setup\\Upgrade
  2100. hKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SBS2000_FAX_SETUP_UPGRADE,TRUE,KEY_READ);
  2101. if (!hKey)
  2102. {
  2103. dwRet = GetLastError();
  2104. VERBOSE( SETUP_ERR,TEXT("OpenRegistryKey failed (ec: %ld)"),dwRet);
  2105. goto exit;
  2106. }
  2107. // get the array of PRINTER_INFO_2
  2108. pPrinterInfo = GetRegistryBinary(hKey,REGVAL_STORED_PRINTERS,&cb);
  2109. if (!pPrinterInfo)
  2110. {
  2111. dwRet = GetLastError();
  2112. VERBOSE( SETUP_ERR,TEXT("GetRegistryBinary failed (ec: %ld)"),dwRet);
  2113. goto exit;
  2114. }
  2115. if (cb==1)
  2116. {
  2117. // Data wasn't found in the registry.
  2118. // Current implementation of GetRegistryBinary returns a 1-byte buffer of 0 in that case.
  2119. // We know for sure that data must be longer than 10 bytes.
  2120. //
  2121. dwRet = ERROR_FILE_NOT_FOUND;
  2122. VERBOSE( SETUP_ERR,TEXT("GetRegistryBinary failed (ec: %ld)"),dwRet);
  2123. goto exit;
  2124. }
  2125. // get the number of stored printers
  2126. dwNumPrinters = GetRegistryDword(hKey,REGVAL_STORED_PRINTERS_COUNT);
  2127. if (dwNumPrinters==0)
  2128. {
  2129. dwRet = GetLastError();
  2130. VERBOSE( SETUP_ERR,TEXT("GetRegistryDword failed (ec: %ld)"),dwRet);
  2131. goto exit;
  2132. }
  2133. // for each printer check if this is a fax printer
  2134. for (dwIndex=0;dwIndex<dwNumPrinters;dwIndex++)
  2135. {
  2136. PPRINTER_INFO_2 pInfo = &((PPRINTER_INFO_2)pPrinterInfo)[dwIndex];
  2137. // fixup pointers to become absulute again.
  2138. pInfo->pServerName = LPTSTR(MAKE_ABSOLUTE(pInfo->pServerName,pInfo));
  2139. pInfo->pPrinterName = LPTSTR(MAKE_ABSOLUTE(pInfo->pPrinterName,pInfo));
  2140. pInfo->pShareName = LPTSTR(MAKE_ABSOLUTE(pInfo->pShareName,pInfo));
  2141. pInfo->pPortName = LPTSTR(MAKE_ABSOLUTE(pInfo->pPortName,pInfo));
  2142. pInfo->pDriverName = LPTSTR(MAKE_ABSOLUTE(pInfo->pDriverName,pInfo));
  2143. pInfo->pComment = LPTSTR(MAKE_ABSOLUTE(pInfo->pComment,pInfo));
  2144. pInfo->pLocation = LPTSTR(MAKE_ABSOLUTE(pInfo->pLocation,pInfo));
  2145. pInfo->pSepFile = LPTSTR(MAKE_ABSOLUTE(pInfo->pSepFile,pInfo));
  2146. pInfo->pPrintProcessor = LPTSTR(MAKE_ABSOLUTE(pInfo->pPrintProcessor,pInfo));
  2147. pInfo->pDatatype = LPTSTR(MAKE_ABSOLUTE(pInfo->pDatatype,pInfo));
  2148. pInfo->pParameters = LPTSTR(MAKE_ABSOLUTE(pInfo->pParameters,pInfo));
  2149. pInfo->pDevMode = LPDEVMODE(MAKE_ABSOLUTE(pInfo->pDevMode,pInfo));
  2150. pInfo->pSecurityDescriptor = PSECURITY_DESCRIPTOR(MAKE_ABSOLUTE(pInfo->pSecurityDescriptor,pInfo));
  2151. if ( _tcsicmp(pInfo->pDriverName,FAX_DRIVER_NAME))
  2152. {
  2153. VERBOSE( DBG_MSG,TEXT("Printer %s is not a fax printer "),pInfo->pDriverName);
  2154. continue;
  2155. }
  2156. // This is SBS 5.0 or .NET SB3/RC1 Server Fax Printer Connections.
  2157. // During the upgrade, Uninstall removed them from the system.
  2158. // We need to put them back.
  2159. //
  2160. if (fIsW9X)
  2161. {
  2162. hPrinter = AddPrinter(NULL,2,LPBYTE(pInfo));
  2163. if (!hPrinter)
  2164. {
  2165. // Failed to add printer
  2166. dwRet = GetLastError();
  2167. VERBOSE( SETUP_ERR,TEXT("AddPrinter failed (ec: %ld)"),dwRet);
  2168. continue;
  2169. }
  2170. ClosePrinter(hPrinter);
  2171. hPrinter = NULL;
  2172. VERBOSE(DBG_MSG, _T("Printer ' %s ' is restored"), pInfo->pPrinterName);
  2173. }
  2174. else
  2175. {
  2176. if (!AddPrinterConnection(pInfo->pPrinterName))
  2177. {
  2178. // Failed to add printer connection
  2179. dwRet = GetLastError();
  2180. VERBOSE( SETUP_ERR,TEXT("AddPrinterConnection failed (ec: %ld)"),dwRet);
  2181. continue;
  2182. }
  2183. }
  2184. }
  2185. exit:
  2186. if (pPrinterInfo)
  2187. {
  2188. MemFree(pPrinterInfo);
  2189. }
  2190. if (hKey)
  2191. {
  2192. RegCloseKey(hKey);
  2193. hKey = NULL;
  2194. }
  2195. // finally, remove the stored printers key from the registry
  2196. if (!DeleteRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_SBS2000_FAX_SETUP_UPGRADE))
  2197. {
  2198. dwRet = GetLastError();
  2199. VERBOSE( SETUP_ERR,TEXT("DeleteRegistryKey failed (ec: %ld)"),dwRet);
  2200. goto exit;
  2201. }
  2202. return dwRet;
  2203. }
  2204. ///////////////////////////////////////////////////////////////////////////////////////
  2205. // Function:
  2206. // DetectSBSServer
  2207. //
  2208. // Purpose:
  2209. // This function detects if SBS2000 Fax service is installed
  2210. // If it is, it sets a property in the MSI installation and
  2211. // causes the LaunchCondition to block the installation of
  2212. // the client on such machines.
  2213. //
  2214. // Params:
  2215. // MSIHANDLE hInstall - handle to the instllation package
  2216. //
  2217. // Return Value:
  2218. // NO_ERROR - everything was ok.
  2219. // Win32 Error code in case if failure.
  2220. //
  2221. // Author:
  2222. // Mooly Beery (MoolyB) 23-Jan-2002
  2223. ///////////////////////////////////////////////////////////////////////////////////////
  2224. DLL_API UINT __stdcall DetectSBSServer(MSIHANDLE hInstall)
  2225. {
  2226. DWORD dwRet = NO_ERROR;
  2227. DWORD dwFaxInstalled = FXSTATE_NONE;
  2228. DBG_ENTER(TEXT("DetectSBSServer"),dwRet);
  2229. if (CheckInstalledFax(FXSTATE_SBS5_SERVER, &dwFaxInstalled) != ERROR_SUCCESS)
  2230. {
  2231. dwRet = GetLastError();
  2232. VERBOSE( SETUP_ERR,TEXT("CheckInstalledFaxClient failed (ec: %ld)"),dwRet);
  2233. return dwRet;
  2234. }
  2235. if (dwFaxInstalled != FXSTATE_NONE)
  2236. {
  2237. VERBOSE( DBG_MSG,TEXT("SBS2000 Fax service is installed, set SBSSERVERDETECTED in MSI"));
  2238. if (MsiSetProperty(hInstall,_T("SBSSERVERDETECTED"),_T("1"))!=ERROR_SUCCESS)
  2239. {
  2240. dwRet = GetLastError();
  2241. VERBOSE( SETUP_ERR,TEXT("MsiSetProperty failed (ec: %ld)"),dwRet);
  2242. return dwRet;
  2243. }
  2244. }
  2245. return dwRet;
  2246. }
  2247. ///////////////////////////////////////////////////////////////////////////////////////
  2248. // Function:
  2249. // SecureFxsTmpFolder
  2250. //
  2251. // Purpose:
  2252. // This function secures the FxsTmp folder we create under
  2253. // %systemroot%\system32.
  2254. // This folder needs special security since it holds the preview
  2255. // file of the sent TIFF and can potentially expose all
  2256. // outgoing faxes.
  2257. // The security applied to this folder is as follows:
  2258. //
  2259. // BUILTIN\Administrators:(OI)(CI)F - Full control, folder and files
  2260. // NT AUTHORITY\SYSTEM:(OI)(CI)F - Full control, folder and files
  2261. // CREATOR OWNER:(OI)(CI)(IO)F - Full control, files only
  2262. // BUILTIN\Users:(special access:) - SYNCHRONIZE
  2263. // - FILE_READ_DATA
  2264. // - FILE_WRITE_DATA
  2265. //
  2266. // Params:
  2267. // MSIHANDLE hInstall - handle to the instllation package
  2268. //
  2269. // Return Value:
  2270. // NO_ERROR - everything was ok.
  2271. // Win32 Error code in case if failure.
  2272. //
  2273. // Author:
  2274. // Mooly Beery (MoolyB) 09-Dec-2001
  2275. ///////////////////////////////////////////////////////////////////////////////////////
  2276. DLL_API UINT __stdcall SecureFxsTmpFolder(MSIHANDLE hInstall)
  2277. {
  2278. DWORD dwRet = 0;
  2279. DWORD dwFileAttributes = 0;
  2280. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2281. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  2282. PSID pSidAliasAdmins = NULL;
  2283. PSID pSidAliasUsers = NULL;
  2284. PSID pSidAliasSystem = NULL;
  2285. PSID pSidCreatorOwner = NULL;
  2286. TCHAR szFolderToSecure[MAX_PATH] = {0};
  2287. PACL pNewAcl = NULL;
  2288. EXPLICIT_ACCESS ExplicitAccess[4];
  2289. SECURITY_DESCRIPTOR NewSecurityDescriptor;
  2290. BOOL bNT4OS;
  2291. OSVERSIONINFO osv;
  2292. DBG_ENTER(TEXT("SecureFxsTmpFolder"), dwRet);
  2293. // What version of Windows are you running?
  2294. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  2295. if (!GetVersionEx(&osv))
  2296. {
  2297. dwRet = GetLastError();
  2298. VERBOSE(GENERAL_ERR,
  2299. _T("GetVersionEx failed: (ec=%d)"),
  2300. dwRet);
  2301. goto exit;
  2302. }
  2303. if (osv.dwMajorVersion >= 5) // Windows 2000 or later...
  2304. {
  2305. bNT4OS = FALSE;
  2306. }
  2307. else
  2308. {
  2309. //
  2310. // On NT4, SetEntriesInAcl() does not seem to work with CREATOR OWNER SID.
  2311. // Adding the CREATOR OWNER ACE using AddAccessAllowedAce()
  2312. //
  2313. bNT4OS = TRUE;
  2314. }
  2315. if (GetSystemDirectory(szFolderToSecure,MAX_PATH-_tcslen(FAX_PREVIEW_TMP_DIR)-2))
  2316. {
  2317. VERBOSE( DBG_MSG,TEXT("GetSystemDirectory succeeded (%s)"),szFolderToSecure);
  2318. }
  2319. else
  2320. {
  2321. dwRet = GetLastError();
  2322. VERBOSE( SETUP_ERR,TEXT("GetSystemDirectory failed (ec: %ld)"),dwRet);
  2323. goto exit;
  2324. }
  2325. _tcscat(szFolderToSecure,FAX_PREVIEW_TMP_DIR);
  2326. VERBOSE( DBG_MSG,TEXT("Folder to secure is %s"),szFolderToSecure);
  2327. // Allocate and initialize the local admins SID
  2328. if (!AllocateAndInitializeSid( &NtAuthority,
  2329. 2,
  2330. SECURITY_BUILTIN_DOMAIN_RID,
  2331. DOMAIN_ALIAS_RID_ADMINS,
  2332. 0,0,0,0,0,0,
  2333. &pSidAliasAdmins
  2334. ))
  2335. {
  2336. dwRet = GetLastError();
  2337. VERBOSE( SETUP_ERR,TEXT("AllocateAndInitializeSid failed (ec: %ld)"),dwRet);
  2338. goto exit;
  2339. }
  2340. // Allocate and initialize the local users SID
  2341. if (!AllocateAndInitializeSid( &NtAuthority,
  2342. 2,
  2343. SECURITY_BUILTIN_DOMAIN_RID,
  2344. DOMAIN_ALIAS_RID_USERS,
  2345. 0,0,0,0,0,0,
  2346. &pSidAliasUsers
  2347. ))
  2348. {
  2349. dwRet = GetLastError();
  2350. VERBOSE( SETUP_ERR,TEXT("AllocateAndInitializeSid failed (ec: %ld)"),dwRet);
  2351. goto exit;
  2352. }
  2353. // Allocate and initialize the system SID
  2354. if (!AllocateAndInitializeSid( &NtAuthority,
  2355. 1,
  2356. SECURITY_LOCAL_SYSTEM_RID,
  2357. 0,0,0,0,0,0,0,
  2358. &pSidAliasSystem
  2359. ))
  2360. {
  2361. dwRet = GetLastError();
  2362. VERBOSE( SETUP_ERR,TEXT("AllocateAndInitializeSid failed (ec: %ld)"),dwRet);
  2363. goto exit;
  2364. }
  2365. // Allocate and initialize the creator owner SID
  2366. if (!AllocateAndInitializeSid( &CreatorSidAuthority,
  2367. 1,
  2368. SECURITY_CREATOR_OWNER_RID,
  2369. 0,0,0,0,0,0,0,
  2370. &pSidCreatorOwner
  2371. ))
  2372. {
  2373. dwRet = GetLastError();
  2374. VERBOSE( SETUP_ERR,TEXT("AllocateAndInitializeSid failed (ec: %ld)"),dwRet);
  2375. goto exit;
  2376. }
  2377. // Admins have full control
  2378. ExplicitAccess[0].grfAccessPermissions = GENERIC_ALL;
  2379. ExplicitAccess[0].grfAccessMode = SET_ACCESS;
  2380. ExplicitAccess[0].grfInheritance= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  2381. ExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2382. ExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  2383. ExplicitAccess[0].Trustee.ptstrName = (LPTSTR) pSidAliasAdmins;
  2384. // System has full control
  2385. ExplicitAccess[1].grfAccessPermissions = GENERIC_ALL;
  2386. ExplicitAccess[1].grfAccessMode = SET_ACCESS;
  2387. ExplicitAccess[1].grfInheritance= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  2388. ExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2389. ExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  2390. ExplicitAccess[1].Trustee.ptstrName = (LPTSTR) pSidAliasSystem;
  2391. // Users have SYNCHRONIZE, FILE_READ_DATA, FILE_WRITE_DATA - this folder only
  2392. ExplicitAccess[2].grfAccessPermissions = FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE;
  2393. ExplicitAccess[2].grfAccessMode = SET_ACCESS;
  2394. ExplicitAccess[2].grfInheritance= NO_INHERITANCE;
  2395. ExplicitAccess[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2396. ExplicitAccess[2].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  2397. ExplicitAccess[2].Trustee.ptstrName = (LPTSTR) pSidAliasUsers;
  2398. if (FALSE == bNT4OS)
  2399. {
  2400. //
  2401. // SetEntriesInAcl works fine with CREATOR OWNER
  2402. //
  2403. // Creator Owner - full control - subfolders and files only
  2404. ExplicitAccess[3].grfAccessPermissions = GENERIC_ALL;
  2405. ExplicitAccess[3].grfAccessMode = SET_ACCESS;
  2406. ExplicitAccess[3].grfInheritance= INHERIT_ONLY_ACE | SUB_OBJECTS_ONLY_INHERIT | SUB_CONTAINERS_ONLY_INHERIT;
  2407. ExplicitAccess[3].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2408. ExplicitAccess[3].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  2409. ExplicitAccess[3].Trustee.ptstrName = (LPTSTR) pSidCreatorOwner;
  2410. }
  2411. // make an ACL from the admins only
  2412. dwRet = SetEntriesInAcl(
  2413. bNT4OS ? 3 : 4,
  2414. ExplicitAccess,
  2415. NULL,
  2416. &pNewAcl);
  2417. if (dwRet!=ERROR_SUCCESS)
  2418. {
  2419. VERBOSE( SETUP_ERR,TEXT("SetEntriesInAcl failed (ec: %ld)"),dwRet);
  2420. goto exit;
  2421. }
  2422. if (TRUE == bNT4OS)
  2423. {
  2424. //
  2425. // We are running on NT4, add the CREATOR OWNER ACE using AddAccessAllowedAce()
  2426. //
  2427. ACL_SIZE_INFORMATION AclSizeInfo;
  2428. PACL pFullNewAcl = NULL;
  2429. WORD wFullAclSize = 0;
  2430. ACCESS_ALLOWED_ACE* pAce = NULL;
  2431. //
  2432. // Get the current ACL size
  2433. //
  2434. if (!GetAclInformation(pNewAcl, &AclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  2435. {
  2436. dwRet = GetLastError();
  2437. VERBOSE( SETUP_ERR, TEXT("GetAclInformation failed (ec: %ld)"), dwRet);
  2438. goto exit;
  2439. }
  2440. wFullAclSize = (WORD)(AclSizeInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
  2441. + GetLengthSid(pSidCreatorOwner));
  2442. //
  2443. // Re-allocate big enough ACL
  2444. //
  2445. pFullNewAcl = (PACL)LocalAlloc(0, wFullAclSize);
  2446. if (NULL == pFullNewAcl)
  2447. {
  2448. VERBOSE( SETUP_ERR,TEXT("LocalAlloc failed (ec: %ld)"),GetLastError());
  2449. goto exit;
  2450. }
  2451. CopyMemory(pFullNewAcl, pNewAcl, AclSizeInfo.AclBytesInUse);
  2452. LocalFree(pNewAcl);
  2453. pNewAcl = pFullNewAcl;
  2454. //
  2455. // Set the correct ACL size
  2456. //
  2457. pNewAcl->AclSize = wFullAclSize;
  2458. if (!AddAccessAllowedAce(
  2459. pNewAcl,
  2460. ACL_REVISION,
  2461. GENERIC_ALL,
  2462. pSidCreatorOwner))
  2463. {
  2464. dwRet = GetLastError();
  2465. VERBOSE( SETUP_ERR, TEXT("AddAccessAllowedAce failed (ec: %ld)"), dwRet);
  2466. goto exit;
  2467. }
  2468. //
  2469. // Change the last ACE flags, so it will be inherited to child objects.
  2470. //
  2471. if (!GetAce(
  2472. pNewAcl,
  2473. 3,
  2474. (VOID**)&pAce
  2475. ))
  2476. {
  2477. dwRet = GetLastError();
  2478. VERBOSE( SETUP_ERR, TEXT("GetAce failed (ec: %ld)"),dwRet);
  2479. goto exit;
  2480. }
  2481. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE;
  2482. }
  2483. if (!InitializeSecurityDescriptor(&NewSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
  2484. {
  2485. dwRet = GetLastError();
  2486. VERBOSE( SETUP_ERR,TEXT("InitializeSecurityDescriptor failed (ec: %ld)"),dwRet);
  2487. goto exit;
  2488. }
  2489. //
  2490. // Add the ACL to the security descriptor.
  2491. //
  2492. if (!SetSecurityDescriptorDacl(&NewSecurityDescriptor, TRUE, pNewAcl, FALSE))
  2493. {
  2494. dwRet = GetLastError();
  2495. VERBOSE( SETUP_ERR,TEXT("SetSecurityDescriptorDacl failed (ec: %ld)"),dwRet);
  2496. goto exit;
  2497. }
  2498. // set security so only admins can access
  2499. if (!SetFileSecurity( szFolderToSecure,
  2500. DACL_SECURITY_INFORMATION,
  2501. &NewSecurityDescriptor))
  2502. {
  2503. dwRet = GetLastError();
  2504. VERBOSE( SETUP_ERR,TEXT("SetFileSecurity failed (ec: %ld)"),dwRet);
  2505. goto exit;
  2506. }
  2507. exit:
  2508. if (pSidAliasUsers)
  2509. {
  2510. FreeSid(pSidAliasUsers);
  2511. }
  2512. if (pSidAliasAdmins)
  2513. {
  2514. FreeSid(pSidAliasAdmins);
  2515. }
  2516. if (pSidAliasSystem)
  2517. {
  2518. FreeSid(pSidAliasSystem);
  2519. }
  2520. if (pSidCreatorOwner)
  2521. {
  2522. FreeSid(pSidCreatorOwner);
  2523. }
  2524. if (pNewAcl)
  2525. {
  2526. LocalFree(pNewAcl);
  2527. }
  2528. return dwRet;
  2529. }
  2530. /*
  2531. Function:
  2532. CreateFaxPrinterName
  2533. Purpose:
  2534. This function extracts Server Name from the Port Name and concatenates to it
  2535. the FAX_PRINTER_NAME. This is used when adding a fax printer connection in
  2536. the W9x systems.
  2537. This function takes the '\\server-name\fax-printer-name' port name and returns
  2538. 'fax-printer-name (server-name)' fax printer name.
  2539. This is done to prevent clashing between fax printer names for different servers.
  2540. The caller must free the *ptzFaxPrinterName.
  2541. Params:
  2542. IN LPCTSTR tzPortName - the port name, of format "\\server-name\fax-printer-name"
  2543. OUT LPTSTR* ptzFaxPrinterName - the resulting buffer
  2544. Return Value:
  2545. NO_ERROR - everything was ok.
  2546. Win32 Error code in case if failure.
  2547. Author:
  2548. Iv Vakaluk, 28-May-2002
  2549. */
  2550. DWORD CreateFaxPrinterName(
  2551. IN LPCTSTR tzPortName,
  2552. OUT LPTSTR* ptzPrinterName
  2553. )
  2554. {
  2555. DWORD dwRet = NO_ERROR;
  2556. TCHAR tzFaxServerName[MAX_PATH];
  2557. TCHAR tzFaxPrinterName[MAX_PATH];
  2558. LPTSTR lptstrResult = NULL;
  2559. DWORD dwSize = 0;
  2560. DBG_ENTER(_T("CreateFaxPrinterName"), dwRet);
  2561. if ((!tzPortName) || ((_tcslen(tzPortName)) == 0))
  2562. {
  2563. VERBOSE(SETUP_ERR, _T("Port Name is empty."));
  2564. dwRet = ERROR_INVALID_PARAMETER;
  2565. return dwRet;
  2566. }
  2567. //
  2568. // delimiter scanf uses by default is white-space characters ( ' ', '\t', '\n' )
  2569. // i need that '\\' will be delimiter.
  2570. // this is done by specifiing the [^\\] for scanf.
  2571. // [x] instructs scanf to read only 'x' and stop at any other input.
  2572. // [^x] instructs scanf to read anything until 'x' is reached.
  2573. //
  2574. if (_stscanf(tzPortName, _T("\\\\%[^\\] \\ %[^\0]"), tzFaxServerName, tzFaxPrinterName) != 2)
  2575. {
  2576. VERBOSE(SETUP_ERR, _T("sscanf() failed. Should be wrong tzPortName='%s'."), tzPortName);
  2577. dwRet = ERROR_INVALID_PARAMETER;
  2578. return dwRet;
  2579. }
  2580. //
  2581. // size(result name) = size(server name) + size(FAX_PRINTER_NAME) + size(space + 2 parentesis + NULL)
  2582. //
  2583. dwSize = _tcslen(tzFaxServerName) + _tcslen(tzFaxPrinterName) + 4;
  2584. lptstrResult = LPTSTR(MemAlloc(dwSize * sizeof TCHAR));
  2585. if (!lptstrResult)
  2586. {
  2587. VERBOSE (GENERAL_ERR, _T("Not enough memory"));
  2588. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  2589. return dwRet;
  2590. }
  2591. _sntprintf(lptstrResult, dwSize, _T("%s (%s)"), tzFaxPrinterName, tzFaxServerName);
  2592. VERBOSE(DBG_MSG, _T("Printer Name is : '%s'"), lptstrResult);
  2593. *ptzPrinterName = lptstrResult;
  2594. return dwRet;
  2595. }
  2596. /*
  2597. Function:
  2598. SetBOSProgramFolder
  2599. Purpose:
  2600. This function does the following :
  2601. a) creates path from the given CSIDL of the system path and given folder name.
  2602. b) verifyes that the path is valid.
  2603. c) optionally writes the valid path in the MSI property called 'BOSProgramFolder'.
  2604. Called from FindBOSProgramFolder custom action.
  2605. Params:
  2606. IN MSIHANDLE hInstall - the MSI handle
  2607. IN int nFolder - A CSIDL value that identifies the folder whose path is to be retrieved
  2608. LPCTSTR tzProgramName - localized name of the BOS Fax Client Program Menu Entry
  2609. Return Value:
  2610. NO_ERROR - everything was ok.
  2611. Win32 Error code in case if failure.
  2612. Author:
  2613. Iv Vakaluk, 01-July-2002
  2614. */
  2615. DWORD SetBOSProgramFolder(MSIHANDLE hInstall, int nFolder, LPCTSTR tzProgramName)
  2616. {
  2617. DWORD dwRes = ERROR_SUCCESS;
  2618. HRESULT hr = ERROR_SUCCESS;
  2619. TCHAR tzFullProgramPath[MAX_PATH*2] = {0};
  2620. DBG_ENTER(_T("SetBOSProgramFolder"), dwRes);
  2621. //
  2622. // Get the path to the given CSIDL system folder
  2623. //
  2624. hr = SHGetFolderPath (NULL, nFolder, NULL, SHGFP_TYPE_CURRENT, (LPTSTR)tzFullProgramPath);
  2625. if (FAILED(hr))
  2626. {
  2627. CALL_FAIL (GENERAL_ERR, TEXT("SHGetFolderPath()"), hr);
  2628. return (dwRes = ERROR_PATH_NOT_FOUND);
  2629. }
  2630. VERBOSE(DBG_MSG, _T("The system folder to look in : %s"), tzFullProgramPath);
  2631. //
  2632. // add the program name to the path
  2633. //
  2634. _tcsncat(tzFullProgramPath, _T("\\"), (ARR_SIZE(tzFullProgramPath) - _tcslen(tzFullProgramPath) - 1));
  2635. _tcsncat(tzFullProgramPath, tzProgramName, (ARR_SIZE(tzFullProgramPath) - _tcslen(tzFullProgramPath) -1));
  2636. VERBOSE(DBG_MSG, _T("The full path to look for : %s"), tzFullProgramPath);
  2637. //
  2638. // check that this path is valid
  2639. //
  2640. if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(tzFullProgramPath))
  2641. {
  2642. VERBOSE(DBG_MSG, _T("The full path is not found."));
  2643. return (dwRes = ERROR_PATH_NOT_FOUND);
  2644. }
  2645. VERBOSE(DBG_MSG, _T("The full path is OK ==> write it into MSI property."));
  2646. //
  2647. // write it into the MSI
  2648. //
  2649. if (hInstall)
  2650. {
  2651. UINT uiRes = ERROR_SUCCESS;
  2652. uiRes = MsiSetProperty(hInstall, _T("BOSProgramFolder"), tzFullProgramPath);
  2653. if (uiRes != ERROR_SUCCESS)
  2654. {
  2655. VERBOSE(SETUP_ERR, _T("MSISetProperty(BOSProgramFolder) is failed."));
  2656. return (dwRes = ERROR_FUNCTION_FAILED);
  2657. }
  2658. }
  2659. return dwRes;
  2660. }
  2661. /*
  2662. Function:
  2663. FindBOSProgramFolder
  2664. Purpose:
  2665. This custom action is used to set the MSI property called 'BOSProgramFolder'
  2666. to the name of the folder of BOS Fax Client on NT4 machines.
  2667. This is because the shortcuts of BOS Fax Client is not removed during the upgrade to .NET Fax Client.
  2668. And we must remove them manually.
  2669. We are using RemoveFile table for this, and we must know the folder where these shortcuts reside.
  2670. The function does following :
  2671. a) reads from the MSI the name of the BOS Fax Client Program Menu Entry.
  2672. b) calls SetBOSProgramFolder to look for this program first in the
  2673. COMMON PROGRAMS and if not successfull, then in the CURRENT USER PROGRAMS profiles.
  2674. c) SetBOSProgramFolder checks for the path validity and writes it into the MSI.
  2675. Params:
  2676. IN MSIHANDLE hInstall - the MSI handle
  2677. Return Value:
  2678. NO_ERROR - everything was ok.
  2679. Win32 Error code in case if failure.
  2680. Author:
  2681. Iv Vakaluk, 30-June-2002
  2682. */
  2683. DLL_API UINT __stdcall FindBOSProgramFolder(MSIHANDLE hInstall)
  2684. {
  2685. UINT rc = ERROR_INSTALL_FAILURE;
  2686. TCHAR tzProgramName[MAX_PATH] = {0};
  2687. DBG_ENTER(TEXT("FindBOSProgramFolder"), rc);
  2688. //
  2689. // Get from MSI the localized name of the program menu entry that we are looking for
  2690. //
  2691. if (!PrivateMsiGetProperty(hInstall, _T("BOSProgramName"), tzProgramName))
  2692. {
  2693. VERBOSE (SETUP_ERR, _T("PrivateMsiGetProperty(BOSProgramName) failed (ec: %ld)"), GetLastError());
  2694. return rc;
  2695. }
  2696. //
  2697. // Look in the COMMON PROGRAMS
  2698. //
  2699. rc = SetBOSProgramFolder(hInstall, CSIDL_COMMON_PROGRAMS, tzProgramName);
  2700. if (rc == ERROR_PATH_NOT_FOUND)
  2701. {
  2702. //
  2703. // Look in the CURRENT USER PROGRAMS
  2704. //
  2705. rc = SetBOSProgramFolder(hInstall, CSIDL_PROGRAMS, tzProgramName);
  2706. }
  2707. if (rc != ERROR_SUCCESS)
  2708. {
  2709. VERBOSE(SETUP_ERR, _T("Failed to find a program path / to set MSI property."));
  2710. rc = ERROR_INSTALL_FAILURE;
  2711. }
  2712. return rc;
  2713. }