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

790 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: NCNetCPA.CPP
  4. //
  5. // Module: NetOC.DLL
  6. //
  7. // Synopsis: Implements the dll entry points required to integrate into
  8. // NetOC.DLL the installation of the following components.
  9. //
  10. // NETCPS
  11. //
  12. // Copyright (C) Microsoft Corporation. All rights reserved.
  13. //
  14. // Author: Anas Jarrah (a-anasj) Created 3/9/98
  15. //
  16. //+---------------------------------------------------------------------------
  17. #include "pch.h"
  18. #pragma hdrstop
  19. #include <atlbase.h>
  20. extern CComModule _Module;
  21. #include <atlcom.h>
  22. #include "ncatl.h"
  23. #include "resource.h"
  24. #include "nccm.h"
  25. //
  26. // Define Globals
  27. //
  28. WCHAR g_szCpaPath[MAX_PATH+1];
  29. WCHAR g_szDaoPath[MAX_PATH+1];
  30. //
  31. // Define Constants
  32. //
  33. const DWORD c_dwCpaDirID = 123176; // just must be larger than DIRID_USER = 0x8000;
  34. const DWORD c_dwDaoDirID = 123177; // just must be larger than DIRID_USER = 0x8000;
  35. const WCHAR* const c_szDaoClientsPath = L"SOFTWARE\\Microsoft\\Shared Tools\\DAO\\Clients";
  36. const WCHAR* const c_szCommonFilesPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
  37. const WCHAR* const c_szCommonFilesDirValue = L"CommonFilesDir";
  38. HRESULT HrGetPBAPathIfInstalled(PWSTR pszCpaPath, DWORD dwNumChars)
  39. {
  40. HRESULT hr;
  41. HKEY hKey;
  42. BOOL bFound = FALSE;
  43. // We need to see if PBA is installed or not. If it is then we want to
  44. // add back the PBA start menu link. If it isn't, then we want to do nothing
  45. // with PBA.
  46. //
  47. ZeroMemory(pszCpaPath, sizeof(WCHAR)*dwNumChars);
  48. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, KEY_READ, &hKey);
  49. if (SUCCEEDED(hr))
  50. {
  51. WCHAR szCurrentValue[MAX_PATH+1];
  52. WCHAR szCurrentData[MAX_PATH+1];
  53. DWORD dwValueSize = MAX_PATH;
  54. DWORD dwDataSize = MAX_PATH;
  55. DWORD dwType;
  56. DWORD dwIndex = 0;
  57. while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType,
  58. (LPBYTE)szCurrentData, &dwDataSize))
  59. {
  60. _wcslwr(szCurrentValue);
  61. if (NULL != wcsstr(szCurrentValue, L"pbadmin.exe"))
  62. {
  63. //
  64. // Then we have found the PBA path
  65. //
  66. WCHAR* pszTemp = wcsrchr(szCurrentValue, L'\\');
  67. if (NULL != pszTemp)
  68. {
  69. *pszTemp = L'\0';
  70. lstrcpyW(pszCpaPath, szCurrentValue);
  71. bFound = TRUE;
  72. break;
  73. }
  74. }
  75. dwValueSize = MAX_PATH;
  76. dwDataSize = MAX_PATH;
  77. dwIndex++;
  78. }
  79. RegCloseKey(hKey);
  80. }
  81. if (!bFound)
  82. {
  83. // We didn't find PBA, so lets return S_FALSE
  84. //
  85. hr = S_FALSE;
  86. }
  87. else
  88. {
  89. hr = S_OK;
  90. }
  91. return hr;
  92. }
  93. BOOL GetAdminToolsFolder(PWSTR pszAdminTools)
  94. {
  95. BOOL bReturn = FALSE;
  96. if (pszAdminTools)
  97. {
  98. bReturn = SHGetSpecialFolderPath(NULL, pszAdminTools, CSIDL_COMMON_PROGRAMS, TRUE);
  99. if (bReturn)
  100. {
  101. // Now Append Administrative Tools
  102. //
  103. lstrcat(pszAdminTools, SzLoadIds(IDS_OC_ADMIN_TOOLS));
  104. }
  105. }
  106. return bReturn;
  107. }
  108. HRESULT HrCreatePbaShortcut(PWSTR pszCpaPath)
  109. {
  110. HRESULT hr = CoInitialize(NULL);
  111. if (SUCCEEDED(hr))
  112. {
  113. IShellLink *psl = NULL;
  114. hr = CoCreateInstance(CLSID_ShellLink, NULL,
  115. CLSCTX_INPROC_SERVER, //CLSCTX_LOCAL_SERVER,
  116. IID_IShellLink,
  117. (LPVOID*)&psl);
  118. if (SUCCEEDED(hr))
  119. {
  120. IPersistFile *ppf = NULL;
  121. // Set up the properties of the Shortcut
  122. //
  123. static const WCHAR c_szPbAdmin[] = L"\\pbadmin.exe";
  124. WCHAR szPathToPbadmin[MAX_PATH+1] = {0};
  125. DWORD dwLen = lstrlen(c_szPbAdmin) + lstrlen(pszCpaPath) + 1;
  126. if (MAX_PATH >= dwLen)
  127. {
  128. // Set the Path to pbadmin.exe
  129. //
  130. lstrcpy(szPathToPbadmin, pszCpaPath);
  131. lstrcat(szPathToPbadmin, c_szPbAdmin);
  132. hr = psl->SetPath(szPathToPbadmin);
  133. if (SUCCEEDED(hr))
  134. {
  135. // Set the Description to Phone Book Administrator
  136. //
  137. hr = psl->SetDescription(SzLoadIds(IDS_OC_PBA_DESC));
  138. if (SUCCEEDED(hr))
  139. {
  140. hr = psl->QueryInterface(IID_IPersistFile,
  141. (LPVOID *)&ppf);
  142. if (SUCCEEDED(hr))
  143. {
  144. WCHAR szAdminTools[MAX_PATH+1] = {0};
  145. if (GetAdminToolsFolder(szAdminTools))
  146. {
  147. // Create the link file.
  148. //
  149. hr = ppf->Save(szAdminTools, TRUE);
  150. }
  151. ReleaseObj(ppf);
  152. }
  153. }
  154. }
  155. }
  156. ReleaseObj(psl);
  157. }
  158. CoUninitialize();
  159. }
  160. return hr;
  161. }
  162. //+---------------------------------------------------------------------------
  163. //
  164. // Function: HrOcCpaPreQueueFiles
  165. //
  166. // Purpose: Called by optional components installer code to handle
  167. // additional installation requirements for PhoneBook Server.
  168. //
  169. // Arguments:
  170. // pnocd [in] Pointer to NETOC data.
  171. //
  172. // Returns: S_OK if successfull, Win32 error otherwise.
  173. //
  174. // Author: quintinb 18 Sep 1998
  175. //
  176. // Notes:
  177. //
  178. HRESULT HrOcCpaPreQueueFiles(PNETOCDATA pnocd)
  179. {
  180. HRESULT hr = S_OK;
  181. switch ( pnocd->eit )
  182. {
  183. case IT_UPGRADE:
  184. WCHAR szPbaInstallPath[MAX_PATH+1];
  185. hr = HrGetPBAPathIfInstalled(szPbaInstallPath, MAX_PATH);
  186. if (S_OK == hr)
  187. {
  188. HrCreatePbaShortcut(szPbaInstallPath);
  189. }
  190. break;
  191. case IT_INSTALL:
  192. case IT_REMOVE:
  193. break;
  194. }
  195. TraceError("HrOcCpaPreQueueFiles", hr);
  196. return hr;
  197. }
  198. /*
  199. //+---------------------------------------------------------------------------
  200. //
  201. // Function: HrOcCpaPreQueueFiles
  202. //
  203. // Purpose: Called by optional components installer code to handle
  204. // additional installation requirements for PhoneBook Server.
  205. //
  206. // Arguments:
  207. // pnocd [in] Pointer to NETOC data.
  208. //
  209. // Returns: S_OK if successfull, Win32 error otherwise.
  210. //
  211. // Author: quintinb 18 Sep 1998
  212. //
  213. // Notes:
  214. //
  215. HRESULT HrOcCpaPreQueueFiles(PNETOCDATA pnocd)
  216. {
  217. HRESULT hr = S_OK;
  218. switch ( pnocd->eit )
  219. {
  220. case IT_UPGRADE:
  221. case IT_INSTALL:
  222. case IT_REMOVE:
  223. //
  224. // Get the PBA install Dir.
  225. //
  226. hr = HrGetPbaInstallPath(g_szCpaPath, celems(g_szCpaPath));
  227. if (SUCCEEDED(hr))
  228. {
  229. // Next Create the CPA Dir ID
  230. //
  231. hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
  232. if (SUCCEEDED(hr))
  233. {
  234. if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCpaDirID, g_szCpaPath))
  235. {
  236. hr = HRESULT_FROM_WIN32(GetLastError());
  237. }
  238. }
  239. }
  240. //
  241. // Now query the system for the DAO350 install path
  242. //
  243. if (SUCCEEDED (hr))
  244. {
  245. hr = HrGetDaoInstallPath(g_szDaoPath, celems(g_szDaoPath));
  246. if (SUCCEEDED(hr))
  247. {
  248. // Next Create the DAO Dir ID
  249. //
  250. hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
  251. if (SUCCEEDED(hr))
  252. {
  253. if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwDaoDirID, g_szDaoPath))
  254. {
  255. hr = HRESULT_FROM_WIN32(GetLastError());
  256. }
  257. }
  258. }
  259. }
  260. break;
  261. }
  262. TraceError("HrOcCpaPreQueueFiles", hr);
  263. return hr;
  264. }
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Function: HrOcCpaOnInstall
  268. //
  269. // Purpose: Called by optional components installer code to handle
  270. // additional installation requirements for PhoneBook Server.
  271. //
  272. // Arguments:
  273. // pnocd [in] Pointer to NETOC data.
  274. //
  275. // Returns: S_OK if successfull, Win32 error otherwise.
  276. //
  277. // Author: quintinb 18 Sep 1998
  278. //
  279. // Notes:
  280. //
  281. HRESULT HrOcCpaOnInstall(PNETOCDATA pnocd)
  282. {
  283. HRESULT hr = S_OK;
  284. switch ( pnocd->eit )
  285. {
  286. case IT_INSTALL:
  287. hr = RefCountPbaSharedDlls(TRUE); // bIncrement = TRUE
  288. break;
  289. case IT_REMOVE:
  290. hr = RefCountPbaSharedDlls(FALSE); // bIncrement = FALSE
  291. break;
  292. case IT_UPGRADE:
  293. DeleteOldNtopLinks();
  294. break;
  295. case IT_UNKNOWN:
  296. case IT_NO_CHANGE:
  297. break;
  298. }
  299. TraceError("HrOcCpaOnInstall", hr);
  300. return hr;
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Function: RefCountPbaSharedDlls
  305. //
  306. // Purpose: Reference count and register/unregister all of the PBAdmin
  307. // shared components.
  308. //
  309. // Arguments: BOOL bIncrement -- if TRUE, then increment the ref count,
  310. // else decrement it
  311. //
  312. //
  313. // Returns: S_OK if successfull, Win32 error otherwise.
  314. //
  315. // Author: quintinb 9 OCT 1998
  316. //
  317. // Notes:
  318. //
  319. HRESULT RefCountPbaSharedDlls(BOOL bIncrement)
  320. {
  321. HRESULT hr = S_OK;
  322. HKEY hKey;
  323. WCHAR szSystemDir[MAX_PATH+1];
  324. DWORD dwSize;
  325. DWORD dwCount;
  326. LONG lResult;
  327. const UINT uNumDlls = 6;
  328. const UINT uStringLen = 12 + 1;
  329. const WCHAR* const c_szSsFmt = L"%s\\%s";
  330. const WCHAR* const c_szSharedDllsPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDlls";
  331. WCHAR mszDlls[uNumDlls][uStringLen] = { L"comctl32.ocx",
  332. L"comdlg32.ocx",
  333. L"msinet.ocx",
  334. L"tabctl32.ocx",
  335. L"dbgrid32.ocx",
  336. L"dao350.dll"
  337. };
  338. WCHAR mszDllPaths[uNumDlls][MAX_PATH];
  339. //
  340. // All of the Dlls that we ref count are in the system directory, except for Dao350.dll.
  341. // Thus we want to append the system directory path to our filenames and handle dao last.
  342. //
  343. if (0 == GetSystemDirectory(szSystemDir, MAX_PATH))
  344. {
  345. return E_UNEXPECTED;
  346. }
  347. for (int i = 0; i < (uNumDlls - 1); i++)
  348. {
  349. wsprintfW(mszDllPaths[i], c_szSsFmt, szSystemDir, mszDlls[i]);
  350. }
  351. //
  352. // Now write out the dao350.dll path.
  353. //
  354. wsprintfW(mszDllPaths[i], c_szSsFmt, g_szDaoPath, mszDlls[i]);
  355. //
  356. // Open the shared DLL key and start enumerating our multi-sz with all of our dll's
  357. // to add.
  358. //
  359. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szSharedDllsPath,
  360. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize)) // using dwSize as a temp to hold the disposition value
  361. {
  362. for (int i=0; i < uNumDlls; i++)
  363. {
  364. dwSize = sizeof(DWORD);
  365. lResult = RegQueryValueExW(hKey, mszDllPaths[i], NULL, NULL, (LPBYTE)&dwCount, &dwSize);
  366. if (ERROR_SUCCESS == lResult)
  367. {
  368. //
  369. // Increment or decrement as appropriate. Make sure not to decrement 0
  370. //
  371. if (0 != dwCount || bIncrement)
  372. {
  373. dwCount = dwCount + (bIncrement ? 1 : -1);
  374. }
  375. }
  376. else if (ERROR_FILE_NOT_FOUND == lResult)
  377. {
  378. if (bIncrement)
  379. {
  380. //
  381. // The the value doesn't yet exist. Set the count to 1.
  382. //
  383. dwCount = 1;
  384. }
  385. else
  386. {
  387. //
  388. // We are decrementing and we couldn't find the DLL, nothing to
  389. // change for the count but we should still delete the dll.
  390. //
  391. dwCount = 0;
  392. }
  393. }
  394. else
  395. {
  396. hr = S_FALSE;
  397. continue;
  398. }
  399. //
  400. // Not that we have determined the ref count, do something about it.
  401. //
  402. if (dwCount == 0)
  403. {
  404. //
  405. // We don't want to delete dao350.dll, but otherwise we need to delete
  406. // the file if it has a zero refcount.
  407. //
  408. if (0 != lstrcmpiW(mszDlls[i], L"dao350.dll"))
  409. {
  410. hr = UnregisterAndDeleteDll(mszDllPaths[i]);
  411. if (FAILED(hr))
  412. {
  413. //
  414. // Don't fail the setup over a file that we couldn't unregister or
  415. // couldn't delete
  416. //
  417. hr = S_FALSE;
  418. }
  419. }
  420. RegDeleteValue(hKey, mszDllPaths[i]);
  421. }
  422. else
  423. {
  424. //
  425. // Set the value to its new count.
  426. //
  427. if (ERROR_SUCCESS != RegSetValueEx(hKey, mszDllPaths[i], 0, REG_DWORD,
  428. (LPBYTE)&dwCount, sizeof(DWORD)))
  429. {
  430. hr = S_FALSE;
  431. }
  432. //
  433. // If we are incrementing the count then we should register the dll.
  434. //
  435. if (bIncrement)
  436. {
  437. hr = RegisterDll(mszDllPaths[i]);
  438. }
  439. }
  440. }
  441. RegCloseKey(hKey);
  442. }
  443. TraceError("RefCountPbaSharedDlls", hr);
  444. return hr;
  445. }
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Function: UnregisterAndDeleteDll
  449. //
  450. // Purpose: Unregister and delete the given COM component
  451. //
  452. // Arguments: pszFile -- The full path to the file to unregister and delete
  453. //
  454. //
  455. // Returns: S_OK if successfull, Win32 error otherwise.
  456. //
  457. // Author: quintinb 9 OCT 1998
  458. //
  459. // Notes:
  460. //
  461. HRESULT UnregisterAndDeleteDll(PCWSTR pszFile)
  462. {
  463. HINSTANCE hLib = NULL;
  464. FARPROC pfncUnRegister;
  465. HRESULT hr = S_OK;
  466. if ((NULL == pszFile) || (L'\0' == pszFile[0]))
  467. {
  468. return E_INVALIDARG;
  469. }
  470. hLib = LoadLibrary(pszFile);
  471. if (NULL != hLib)
  472. {
  473. pfncUnRegister = GetProcAddress(hLib, "DllUnregisterServer");
  474. if (NULL != pfncUnRegister)
  475. {
  476. hr = (pfncUnRegister)();
  477. if (SUCCEEDED(hr))
  478. {
  479. FreeLibrary(hLib);
  480. hLib = NULL;
  481. // This was removed because PBA setup is moving to Value Add and because of bug 323231
  482. // if (!DeleteFile(pszFile))
  483. // {
  484. // hr = S_FALSE;
  485. // }
  486. }
  487. }
  488. else
  489. {
  490. hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
  491. }
  492. }
  493. else
  494. {
  495. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  496. }
  497. if (NULL != hLib)
  498. {
  499. FreeLibrary(hLib);
  500. }
  501. TraceError("UnregisterAndDeleteDll", hr);
  502. return hr;
  503. }
  504. //+---------------------------------------------------------------------------
  505. //
  506. // Function: RegisterDll
  507. //
  508. // Purpose: Register the given COM component
  509. //
  510. // Arguments: pszFile -- The full path to the file to register
  511. //
  512. //
  513. // Returns: S_OK if successfull, Win32 error otherwise.
  514. //
  515. // Author: quintinb 9 OCT 1998
  516. //
  517. // Notes:
  518. //
  519. HRESULT RegisterDll(PCWSTR pszFile)
  520. {
  521. HINSTANCE hLib = NULL;
  522. FARPROC pfncRegister;
  523. HRESULT hr = S_OK;
  524. if ((NULL == pszFile) || (L'\0' == pszFile[0]))
  525. {
  526. return E_INVALIDARG;
  527. }
  528. hLib = LoadLibrary(pszFile);
  529. if (NULL != hLib)
  530. {
  531. pfncRegister = GetProcAddress(hLib, "DllRegisterServer");
  532. if (NULL != pfncRegister)
  533. {
  534. hr = (pfncRegister)();
  535. }
  536. else
  537. {
  538. hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
  539. }
  540. }
  541. else
  542. {
  543. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  544. }
  545. if (NULL != hLib)
  546. {
  547. FreeLibrary(hLib);
  548. }
  549. TraceError("RegisterDll", hr);
  550. return hr;
  551. }
  552. //+---------------------------------------------------------------------------
  553. //
  554. // Function: HrGetPbaInstallPath
  555. //
  556. // Purpose: Get the install path for pbadmin.exe.
  557. //
  558. // Arguments: pszCpaPath -- buffer to hold the install path of PBA.
  559. // dwNumChars -- the number of characters that the buffer can hold.
  560. //
  561. //
  562. // Returns: S_OK if successfull, Win32 error otherwise.
  563. //
  564. // Author: quintinb 19 OCT 1998
  565. //
  566. // Notes:
  567. //
  568. HRESULT HrGetPbaInstallPath(PWSTR pszCpaPath, DWORD dwNumChars)
  569. {
  570. HRESULT hr;
  571. HKEY hKey;
  572. BOOL bFound = FALSE;
  573. // We need to setup the custom DIRID so that CPA will install
  574. // to the correct location. First get the path from the system.
  575. //
  576. ZeroMemory(pszCpaPath, sizeof(WCHAR)*dwNumChars);
  577. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, KEY_READ, &hKey);
  578. if (SUCCEEDED(hr))
  579. {
  580. WCHAR szCurrentValue[MAX_PATH+1];
  581. WCHAR szCurrentData[MAX_PATH+1];
  582. DWORD dwValueSize = MAX_PATH;
  583. DWORD dwDataSize = MAX_PATH;
  584. DWORD dwType;
  585. DWORD dwIndex = 0;
  586. while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType,
  587. (LPBYTE)szCurrentData, &dwDataSize))
  588. {
  589. _wcslwr(szCurrentValue);
  590. if (NULL != wcsstr(szCurrentValue, L"pbadmin.exe"))
  591. {
  592. //
  593. // Then we have found the PBA path
  594. //
  595. WCHAR* pszTemp = wcsrchr(szCurrentValue, L'\\');
  596. if (NULL != pszTemp)
  597. {
  598. *pszTemp = L'\0';
  599. lstrcpyW(pszCpaPath, szCurrentValue);
  600. bFound = TRUE;
  601. break;
  602. }
  603. }
  604. dwValueSize = MAX_PATH;
  605. dwDataSize = MAX_PATH;
  606. dwIndex++;
  607. }
  608. RegCloseKey(hKey);
  609. }
  610. if (!bFound)
  611. {
  612. // This is a fresh install of CPA, don't return an error
  613. //
  614. hr = SHGetSpecialFolderPath(NULL, pszCpaPath, CSIDL_PROGRAM_FILES, FALSE);
  615. if (SUCCEEDED(hr))
  616. {
  617. lstrcatW(pszCpaPath, L"\\PBA");
  618. }
  619. }
  620. return hr;
  621. }
  622. //+---------------------------------------------------------------------------
  623. //
  624. // Function: HrGetDaoInstallPath
  625. //
  626. // Purpose: Get the install path for pbadmin.exe.
  627. //
  628. // Arguments: pszCpaPath -- buffer to hold the install path of PBA.
  629. // dwNumChars -- the number of characters that the buffer can hold.
  630. //
  631. //
  632. // Returns: S_OK if successfull, Win32 error otherwise.
  633. //
  634. // Author: quintinb 19 OCT 1998
  635. //
  636. // Notes:
  637. //
  638. HRESULT HrGetDaoInstallPath(PWSTR pszDaoPath, DWORD dwNumChars)
  639. {
  640. HRESULT hr;
  641. HKEY hKey;
  642. // We need to setup the custom DIRID so that CPA will install
  643. // to the correct location. First get the path from the system.
  644. //
  645. ZeroMemory(pszDaoPath, sizeof(WCHAR)*dwNumChars);
  646. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szCommonFilesPath, KEY_ALL_ACCESS, &hKey);
  647. if (SUCCEEDED(hr))
  648. {
  649. DWORD dwSize = sizeof(WCHAR)*dwNumChars;
  650. //
  651. // Try to get the CommonFilesDir value from the registry, but if it doesn't exist
  652. // then create it.
  653. //
  654. if (ERROR_SUCCESS != RegQueryValueExW(hKey, c_szCommonFilesDirValue, NULL, NULL,
  655. (LPBYTE)pszDaoPath, &dwSize))
  656. {
  657. hr = SHGetSpecialFolderPath(NULL, pszDaoPath, CSIDL_PROGRAM_FILES, FALSE);
  658. if (SUCCEEDED(hr))
  659. {
  660. //
  661. // QBBUG -- Common files is localizable. Make a string resource.
  662. //
  663. lstrcatW(pszDaoPath, (PWSTR)SzLoadIds(IDS_OC_COMMON_FILES));
  664. //
  665. // Now set the regvalue
  666. //
  667. hr = HrRegSetValueEx(hKey, c_szCommonFilesDirValue, REG_SZ,
  668. (const BYTE*)pszDaoPath, sizeof(WCHAR)*dwNumChars);
  669. }
  670. }
  671. RegCloseKey(hKey);
  672. }
  673. if (SUCCEEDED(hr))
  674. {
  675. //
  676. // QBBUG -- should Microsoft shared be a string resource?
  677. //
  678. lstrcatW(g_szDaoPath, (PWSTR)SzLoadIds(IDS_OC_MS_SHARED_DAO));
  679. }
  680. return hr;
  681. }
  682. */