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.

1316 lines
37 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 2001
  7. //
  8. // File: misc.cxx, this file is #include'd into the two dllmisc.cxx files.
  9. //
  10. // Contents: DS property pages class objects handler DLL fcns. Also, error
  11. // reporting, message, and miscelaneous functions.
  12. //
  13. // History: 10-May-01 EricB created
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #include "proppage.h"
  18. #include "objlist.h"
  19. #if defined(DSPROP_ADMIN)
  20. # include "chklist.h"
  21. # include "fpnw.h"
  22. #endif
  23. #include <time.h>
  24. DECLARE_INFOLEVEL(DsProp);
  25. HINSTANCE g_hInstance = NULL;
  26. ULONG CDll::s_cObjs = 0;
  27. ULONG CDll::s_cLocks = 0;
  28. UINT g_uChangeMsg = 0;
  29. int g_iInstance = 0;
  30. #ifndef DSPROP_ADMIN
  31. CRITICAL_SECTION g_csNotifyCreate;
  32. #endif
  33. ULONG g_ulMemberFilterCount = DSPROP_MEMBER_FILTER_COUNT_DEFAULT;
  34. ULONG g_ulMemberQueryLimit = DSPROP_MEMBER_QUERY_LIMIT_DEFAULT;
  35. #define DIRECTORY_UI_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\Directory UI")
  36. #define MEMBER_QUERY_VALUE TEXT("GroupMemberFilterCount")
  37. #define MEMBER_LIMIT_VALUE TEXT("GroupMemberQueryLimit")
  38. #if defined(DSPROP_ADMIN)
  39. Cache g_FPNWCache;
  40. #endif
  41. HRESULT GlobalInit(void);
  42. void GlobalUnInit(void);
  43. void ReportErrorFallback(HWND hWndMsg, HRESULT hr = ERROR_SUCCESS)
  44. { ReportError( hr, 0, hWndMsg ); }
  45. //+----------------------------------------------------------------------------
  46. // To set a non-default debug info level outside of the debugger, create the
  47. // below registry key and in it create a value whose name is the component's
  48. // debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and
  49. // whose data is the desired infolevel in REG_DWORD format.
  50. //-----------------------------------------------------------------------------
  51. #define SMDEBUGKEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AdminDebug"
  52. #ifndef DSPROP_ADMIN
  53. //+----------------------------------------------------------------------------
  54. //
  55. // Class: CNotifyCreateCriticalSection
  56. //
  57. // Purpose: Prevents creation race conditions. Without this protection,
  58. // a second call to CNotifyObj::Create that comes in before the
  59. // first has created the hidden window will get NULL back from
  60. // FindSheetNoSetFocus and then go on to create a second hidden
  61. // window.
  62. //
  63. //-----------------------------------------------------------------------------
  64. CNotifyCreateCriticalSection::CNotifyCreateCriticalSection()
  65. {
  66. TRACE(CNotifyCreateCriticalSection, CNotifyCreateCriticalSection);
  67. EnterCriticalSection(&g_csNotifyCreate);
  68. };
  69. CNotifyCreateCriticalSection::~CNotifyCreateCriticalSection()
  70. {
  71. TRACE(CNotifyCreateCriticalSection, ~CNotifyCreateCriticalSection);
  72. LeaveCriticalSection(&g_csNotifyCreate);
  73. };
  74. #endif
  75. #define MAX_STRING 1024
  76. //+----------------------------------------------------------------------------
  77. //
  78. // Function: LoadStringToTchar
  79. //
  80. // Synopsis: Loads the given string into an allocated buffer that must be
  81. // caller freed using delete.
  82. //
  83. //-----------------------------------------------------------------------------
  84. BOOL LoadStringToTchar(int ids, PTSTR * pptstr)
  85. {
  86. TCHAR szBuf[MAX_STRING];
  87. if (!LoadString(g_hInstance, ids, szBuf, MAX_STRING - 1))
  88. {
  89. return FALSE;
  90. }
  91. *pptstr = new TCHAR[_tcslen(szBuf) + 1];
  92. CHECK_NULL(*pptstr, return FALSE);
  93. _tcscpy(*pptstr, szBuf);
  94. return TRUE;
  95. }
  96. //+----------------------------------------------------------------------------
  97. // Function: LoadStringReport
  98. // Purpose: attempts to load a string, returns FALSE and gives error message
  99. // if a failure occurs.
  100. //-----------------------------------------------------------------------------
  101. BOOL LoadStringReport(int ids, PTSTR ptz, int len, HWND hwnd)
  102. {
  103. if (!LoadString(g_hInstance, ids, ptz, len - 1))
  104. {
  105. DWORD dwErr = GetLastError();
  106. dspDebugOut((DEB_ERROR, "LoadString of %d failed with error %lu\n",
  107. ids, dwErr));
  108. ReportError(dwErr, 0, hwnd);
  109. return FALSE;
  110. }
  111. return TRUE;
  112. }
  113. //+----------------------------------------------------------------------------
  114. //
  115. // Function: LoadErrorMessage
  116. //
  117. // Synopsis: Attempts to get a user-friendly error message from the system.
  118. //
  119. //-----------------------------------------------------------------------------
  120. void LoadErrorMessage(HRESULT hr, int nStr, PTSTR* pptsz) // free with delete[]
  121. {
  122. dspAssert( NULL != pptsz && NULL == *pptsz );
  123. PTSTR ptzFormat = NULL, ptzSysMsg;
  124. int cch;
  125. if (nStr)
  126. {
  127. LoadStringToTchar(nStr, &ptzFormat);
  128. }
  129. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  130. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr,
  131. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  132. (PTSTR)&ptzSysMsg, 0, NULL);
  133. if (!cch)
  134. {
  135. // Try ADSI errors.
  136. //
  137. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  138. | FORMAT_MESSAGE_FROM_HMODULE,
  139. GetModuleHandle(TEXT("activeds.dll")), hr,
  140. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  141. (PTSTR)&ptzSysMsg, 0, NULL);
  142. }
  143. if (!cch)
  144. {
  145. PTSTR ptzMsgTemplate = NULL;
  146. BOOL fDelMsgTemplate = TRUE;
  147. LoadStringToTchar(IDS_DEFAULT_ERROR_MSG, &ptzMsgTemplate);
  148. if (NULL == ptzMsgTemplate)
  149. {
  150. ptzMsgTemplate = TEXT("The operation failed with error code %d (0x%08x)");
  151. fDelMsgTemplate = FALSE;
  152. }
  153. *pptsz = new TCHAR[ lstrlen(ptzMsgTemplate)+10 ];
  154. dspAssert( NULL != *pptsz );
  155. if (NULL != *pptsz)
  156. {
  157. wsprintf(*pptsz, ptzMsgTemplate, hr, hr);
  158. }
  159. if (fDelMsgTemplate)
  160. {
  161. delete ptzMsgTemplate;
  162. }
  163. }
  164. else
  165. {
  166. PTSTR ptzMsg;
  167. BOOL fDelMsg = FALSE;
  168. if (ptzFormat)
  169. {
  170. ptzMsg = new TCHAR[lstrlen(ptzFormat) + lstrlen(ptzSysMsg) + 1];
  171. if (ptzMsg)
  172. {
  173. wsprintf(ptzMsg, ptzFormat, ptzSysMsg);
  174. fDelMsg = TRUE;
  175. }
  176. else
  177. {
  178. ptzMsg = ptzSysMsg;
  179. }
  180. }
  181. else
  182. {
  183. ptzMsg = ptzSysMsg;
  184. }
  185. *pptsz = new TCHAR[ lstrlen(ptzMsg)+1 ];
  186. if (NULL != *pptsz)
  187. {
  188. lstrcpy( *pptsz, ptzMsg );
  189. }
  190. dspAssert( NULL != *pptsz );
  191. LocalFree(ptzSysMsg);
  192. if (fDelMsg)
  193. {
  194. delete[] ptzMsg;
  195. }
  196. if (ptzFormat)
  197. {
  198. delete ptzFormat;
  199. }
  200. }
  201. }
  202. //+----------------------------------------------------------------------------
  203. //
  204. // Function: CheckADsError
  205. //
  206. // Synopsis: Checks the result code from an ADSI call.
  207. //
  208. // Returns: TRUE if no error.
  209. //
  210. //-----------------------------------------------------------------------------
  211. BOOL CheckADsError(HRESULT * phr, BOOL fIgnoreAttrNotFound, PSTR file,
  212. int line, HWND hWnd)
  213. {
  214. if (SUCCEEDED(*phr))
  215. {
  216. return TRUE;
  217. }
  218. if (((E_ADS_PROPERTY_NOT_FOUND == *phr) ||
  219. (HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) == *phr)) &&
  220. fIgnoreAttrNotFound)
  221. {
  222. *phr = S_OK;
  223. return TRUE;
  224. }
  225. HWND hWndMsg = hWnd;
  226. if (!hWndMsg)
  227. {
  228. hWndMsg = GetDesktopWindow();
  229. }
  230. DWORD dwErr;
  231. WCHAR wszErrBuf[MAX_PATH+1];
  232. WCHAR wszNameBuf[MAX_PATH+1];
  233. ADsGetLastError(&dwErr, wszErrBuf, MAX_PATH, wszNameBuf, MAX_PATH);
  234. if ((LDAP_RETCODE)dwErr == LDAP_NO_SUCH_ATTRIBUTE && fIgnoreAttrNotFound)
  235. {
  236. *phr = S_OK;
  237. return TRUE;
  238. }
  239. if (dwErr)
  240. {
  241. dspDebugOut((DEB_ERROR,
  242. "Extended Error 0x%x: %ws %ws <%s @line %d>.\n", dwErr,
  243. wszErrBuf, wszNameBuf, file, line));
  244. ReportError(dwErr, IDS_ADS_ERROR_FORMAT, hWndMsg);
  245. }
  246. else
  247. {
  248. dspDebugOut((DEB_ERROR, "Error %08lx <%s @line %d>\n", *phr, file, line));
  249. ReportError(*phr, IDS_ADS_ERROR_FORMAT, hWndMsg);
  250. }
  251. return FALSE;
  252. }
  253. //+----------------------------------------------------------------------------
  254. //
  255. // Function: ReportError
  256. //
  257. // Synopsis: Displays an error using a user-friendly error message from the
  258. // system.
  259. //
  260. //-----------------------------------------------------------------------------
  261. void ReportErrorWorker(HWND hWnd, PTSTR ptzMsg)
  262. {
  263. HWND hWndMsg = hWnd;
  264. if (!hWndMsg)
  265. {
  266. hWndMsg = GetDesktopWindow();
  267. }
  268. PTSTR ptzTitle = NULL;
  269. if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle))
  270. {
  271. MessageBox(hWndMsg, ptzMsg, TEXT("Active Directory"), MB_OK | MB_ICONEXCLAMATION);
  272. return;
  273. }
  274. MessageBox(hWndMsg, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION);
  275. delete ptzTitle;
  276. }
  277. void ReportError(HRESULT hr, int nStr, HWND hWnd)
  278. {
  279. PTSTR ptzMsg = NULL;
  280. LoadErrorMessage(hr, nStr, &ptzMsg);
  281. if (NULL == ptzMsg)
  282. {
  283. TCHAR tzBuf[80];
  284. wsprintf(tzBuf, TEXT("Active Directory failure with code '0x%08x'!"), hr);
  285. ReportErrorWorker( hWnd, tzBuf );
  286. return;
  287. }
  288. ReportErrorWorker( hWnd, ptzMsg );
  289. delete ptzMsg;
  290. }
  291. #if defined(DSADMIN)
  292. //+----------------------------------------------------------------------------
  293. //
  294. // Function: SuperMsgBox
  295. //
  296. // Synopsis: Displays a message obtained from a string resource with
  297. // the parameters expanded. The error param, dwErr, if
  298. // non-zero, is converted to a string and becomes the first
  299. // replaceable param.
  300. //
  301. // Note: this function is UNICODE-only.
  302. //
  303. //-----------------------------------------------------------------------------
  304. int SuperMsgBox(
  305. HWND hWnd, // owning window.
  306. int nMessageId, // string resource ID of message. Must have replacable params to match nArguments.
  307. int nTitleId, // string resource ID of the title. If zero, uses IDS_MSG_TITLE.
  308. UINT ufStyle, // MessageBox flags.
  309. DWORD dwErr, // Error code, or zero if not needed.
  310. PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string.
  311. int nArguments, // count of pointers in string array.
  312. BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error.
  313. PSTR szFile, // use the __FILE__ macro. ignored in retail build.
  314. int nLine // use the __LINE__ macro. ignored in retail build.
  315. )
  316. {
  317. CStrW strTitle;
  318. PWSTR pwzMsg = NULL;
  319. strTitle.LoadString(g_hInstance, (nTitleId) ? nTitleId : IDS_MSG_TITLE);
  320. if (0 == strTitle.GetLength())
  321. {
  322. ReportErrorFallback(hWnd, dwErr);
  323. return 0;
  324. }
  325. DspFormatMessage(nMessageId, dwErr, rgpvArgs, nArguments,
  326. fTryADSiErrors, &pwzMsg, hWnd);
  327. if (!pwzMsg)
  328. {
  329. return 0;
  330. }
  331. if (dwErr)
  332. {
  333. dspDebugOut((DEB_ERROR,
  334. "*+*+*+*+* Error <%s @line %d> -> 0x%08x, with message:\n\t%ws\n",
  335. szFile, nLine, dwErr, pwzMsg));
  336. }
  337. else
  338. {
  339. dspDebugOut((DEB_ERROR,
  340. "*+*+*+*+* Message <%s @line %d>:\n\t%ws\n",
  341. szFile, nLine, pwzMsg));
  342. }
  343. int retval = MessageBox(hWnd, pwzMsg, strTitle, ufStyle);
  344. LocalFree(pwzMsg);
  345. return retval;
  346. }
  347. //+----------------------------------------------------------------------------
  348. //
  349. // Function: DspFormatMessage
  350. //
  351. // Synopsis: Loads a string resource with replaceable parameters and uses
  352. // FormatMessage to populate the replaceable params from the
  353. // argument array. If dwErr is non-zero, will load the system
  354. // description for that error and include it in the argument array.
  355. //
  356. //-----------------------------------------------------------------------------
  357. void
  358. DspFormatMessage(
  359. int nMessageId, // string resource ID of message. Must have replacable params to match nArguments.
  360. DWORD dwErr, // Error code, or zero if not needed.
  361. PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string.
  362. int nArguments, // count of pointers in string array.
  363. BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error.
  364. PWSTR * ppwzMsg, // The returned error string, free with LocalFree.
  365. HWND hWnd // owning window, defaults to NULL.
  366. )
  367. {
  368. int cch;
  369. PWSTR pwzSysErr = NULL;
  370. if (dwErr)
  371. {
  372. if (fTryADSiErrors)
  373. {
  374. DWORD dwStatus;
  375. WCHAR Buf1[256], Buf2[256];
  376. ADsGetLastError(&dwStatus, Buf1, 256, Buf2, 256);
  377. dspDebugOut((DEB_ERROR,
  378. "ADsGetLastError returned status of %lx, error: %s, name %s\n",
  379. dwStatus, Buf1, Buf2));
  380. if ((ERROR_INVALID_DATA != dwStatus) && (0 != dwStatus))
  381. {
  382. dwErr = dwStatus;
  383. }
  384. }
  385. cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  386. FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
  387. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  388. (PWSTR)&pwzSysErr, 0, NULL);
  389. if (!cch)
  390. {
  391. ReportErrorFallback(hWnd, dwErr);
  392. return;
  393. }
  394. }
  395. PWSTR * rgpvArguments = new PWSTR[nArguments + 1];
  396. if (!rgpvArguments)
  397. {
  398. ReportErrorFallback(hWnd, dwErr);
  399. return;
  400. }
  401. int nOffset = 0;
  402. if (dwErr)
  403. {
  404. rgpvArguments[0] = pwzSysErr;
  405. nOffset = 1;
  406. }
  407. if (0 != nArguments)
  408. {
  409. CopyMemory(rgpvArguments + nOffset, rgpvArgs, nArguments * sizeof(PVOID));
  410. }
  411. CStrW strFormat;
  412. strFormat.LoadString(g_hInstance, nMessageId);
  413. if (0 == strFormat.GetLength())
  414. {
  415. ReportErrorFallback(hWnd, dwErr);
  416. return;
  417. }
  418. cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  419. FORMAT_MESSAGE_FROM_STRING |
  420. FORMAT_MESSAGE_ARGUMENT_ARRAY, strFormat, 0, 0,
  421. (PWSTR)ppwzMsg, 0, (va_list *)rgpvArguments);
  422. if (pwzSysErr) LocalFree(pwzSysErr);
  423. if (!cch)
  424. {
  425. ReportErrorFallback(hWnd, dwErr);
  426. }
  427. delete[] rgpvArguments;
  428. return;
  429. }
  430. #endif // defined(DSADMIN)
  431. //+----------------------------------------------------------------------------
  432. //
  433. // Function: ErrMsg
  434. //
  435. // Synopsis: Displays an error message obtained from a string resource.
  436. //
  437. //-----------------------------------------------------------------------------
  438. void ErrMsg(UINT MsgID, HWND hWndParam)
  439. {
  440. PTSTR ptz = TEXT("");
  441. ErrMsgParam(MsgID, (LPARAM)ptz, hWndParam);
  442. }
  443. //+----------------------------------------------------------------------------
  444. //
  445. // Function: ErrMsgParam
  446. //
  447. // Synopsis: Displays an error message obtained from a string resource with
  448. // an insertion parameter.
  449. //
  450. // Note: fixed-size stack buffers are used for the strings because trying to
  451. // report an allocation failure using dynamically allocated string
  452. // buffers is not a good idea.
  453. //-----------------------------------------------------------------------------
  454. void ErrMsgParam(UINT MsgID, LPARAM param, HWND hWndParam)
  455. {
  456. HWND hWnd;
  457. if (hWndParam == NULL)
  458. {
  459. hWnd = GetDesktopWindow();
  460. }
  461. else
  462. {
  463. hWnd = hWndParam;
  464. }
  465. TCHAR szTitle[MAX_TITLE+1];
  466. TCHAR szFormat[MAX_ERRORMSG+1];
  467. TCHAR szMsg[MAX_ERRORMSG+1];
  468. LOAD_STRING(IDS_MSG_TITLE, szTitle, MAX_TITLE, MessageBeep(MB_ICONEXCLAMATION); return);
  469. LOAD_STRING(MsgID, szFormat, MAX_ERRORMSG, MessageBeep(MB_ICONEXCLAMATION); return);
  470. wsprintf(szMsg, szFormat, param);
  471. MessageBox(hWnd, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION);
  472. }
  473. //+----------------------------------------------------------------------------
  474. //
  475. // Function: MsgBox
  476. //
  477. // Synopsis: Displays a message obtained from a string resource.
  478. //
  479. //-----------------------------------------------------------------------------
  480. void MsgBox(UINT MsgID, HWND hWnd)
  481. {
  482. MsgBox2(MsgID, 0, hWnd);
  483. }
  484. //+----------------------------------------------------------------------------
  485. //
  486. // Function: MsgBox2
  487. //
  488. // Synopsis: Displays a message obtained from a string resource which is
  489. // assumed to have a replacable parameter where the InsertID
  490. // string is inserted.
  491. //
  492. //-----------------------------------------------------------------------------
  493. void MsgBox2(UINT MsgID, UINT InsertID, HWND hWnd)
  494. {
  495. CStr strMsg, strFormat, strInsert, strTitle;
  496. if (!strTitle.LoadString(g_hInstance, IDS_MSG_TITLE))
  497. {
  498. REPORT_ERROR(GetLastError(), hWnd);
  499. return;
  500. }
  501. if (!strFormat.LoadString(g_hInstance, MsgID))
  502. {
  503. REPORT_ERROR(GetLastError(), hWnd);
  504. return;
  505. }
  506. if (InsertID)
  507. {
  508. if (!strInsert.LoadString(g_hInstance, InsertID))
  509. {
  510. REPORT_ERROR(GetLastError(), hWnd);
  511. return;
  512. }
  513. strMsg.Format(strFormat, strInsert);
  514. }
  515. else
  516. {
  517. strMsg = strFormat;
  518. }
  519. MessageBox(hWnd, strMsg, strTitle, MB_OK | MB_ICONINFORMATION);
  520. }
  521. //+----------------------------------------------------------------------------
  522. //
  523. // DLL functions
  524. //
  525. //-----------------------------------------------------------------------------
  526. //+----------------------------------------------------------------------------
  527. //
  528. // Function: DllMain
  529. //
  530. // Synopsis: Provide a DllMain for Win32
  531. //
  532. // Arguments: hInstance - HANDLE to this dll
  533. // dwReason - Reason this function was called. Can be
  534. // Process/Thread Attach/Detach.
  535. //
  536. // Returns: BOOL - TRUE if no error, FALSE otherwise
  537. //
  538. // History: 24-May-95 EricB created.
  539. //
  540. //-----------------------------------------------------------------------------
  541. extern "C" BOOL
  542. DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID)
  543. {
  544. switch (dwReason)
  545. {
  546. case DLL_PROCESS_ATTACH:
  547. dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_ATTACH\n"));
  548. //
  549. // Get instance handle
  550. //
  551. g_hInstance = hInstance;
  552. //
  553. // Disable thread notification from OS
  554. //
  555. //DisableThreadLibraryCalls(hInstance);
  556. HRESULT hr;
  557. //
  558. // Initialize the global values.
  559. //
  560. hr = GlobalInit();
  561. if (FAILED(hr))
  562. {
  563. ERR_OUT("GlobalInit", hr);
  564. return FALSE;
  565. }
  566. break;
  567. case DLL_PROCESS_DETACH:
  568. dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_DETACH\n"));
  569. GlobalUnInit();
  570. break;
  571. }
  572. return(TRUE);
  573. }
  574. //+----------------------------------------------------------------------------
  575. //
  576. // Function: DllGetClassObject
  577. //
  578. // Synopsis: Creates a class factory for the requested object.
  579. //
  580. // Arguments: [cid] - the requested class object
  581. // [iid] - the requested interface
  582. // [ppvObj] - returned pointer to class object
  583. //
  584. // Returns: HRESULTS
  585. //
  586. //-----------------------------------------------------------------------------
  587. STDAPI
  588. DllGetClassObject(REFCLSID cid, REFIID iid, void **ppvObj)
  589. {
  590. IUnknown *pUnk = NULL;
  591. HRESULT hr = S_OK;
  592. for (int i = 0; i < g_DsPPClasses.cClasses; i++)
  593. {
  594. if (cid == *g_DsPPClasses.rgpClass[i]->pcid)
  595. {
  596. pUnk = CDsPropPagesHostCF::Create(g_DsPPClasses.rgpClass[i]);
  597. if (pUnk != NULL)
  598. {
  599. hr = pUnk->QueryInterface(iid, ppvObj);
  600. pUnk->Release();
  601. }
  602. else
  603. {
  604. return E_OUTOFMEMORY;
  605. }
  606. return hr;
  607. }
  608. }
  609. return E_NOINTERFACE;
  610. }
  611. //+----------------------------------------------------------------------------
  612. //
  613. // Function: DllCanUnloadNow
  614. //
  615. // Synopsis: Indicates whether the DLL can be removed if there are no
  616. // objects in existence.
  617. //
  618. // Returns: S_OK or S_FALSE
  619. //
  620. //-----------------------------------------------------------------------------
  621. STDAPI
  622. DllCanUnloadNow(void)
  623. {
  624. dspDebugOut((DEB_ITRACE, "DllCanUnloadNow: CDll::CanUnloadNow()? %s\n",
  625. (CDll::CanUnloadNow() == S_OK) ? "TRUE" : "FALSE"));
  626. return CDll::CanUnloadNow();
  627. }
  628. TCHAR const c_szServerType[] = TEXT("InProcServer32");
  629. TCHAR const c_szThreadModel[] = TEXT("ThreadingModel");
  630. TCHAR const c_szThreadModelValue[] = TEXT("Apartment");
  631. //+----------------------------------------------------------------------------
  632. //
  633. // Function: DllRegisterServer
  634. //
  635. // Synopsis: Adds entries to the system registry.
  636. //
  637. // Returns: S_OK or error code.
  638. //
  639. // Notes: The keys look like this:
  640. //
  641. // HKC\CLSID\clsid <No Name> REG_SZ name.progid
  642. // \InPropServer32 <No Name> : REG_SZ : adprop.dll/dsprop.dll
  643. // ThreadingModel : REG_SZ : Apartment
  644. //-----------------------------------------------------------------------------
  645. STDAPI
  646. DllRegisterServer(void)
  647. {
  648. HRESULT hr = S_OK;
  649. HKEY hKeyCLSID, hKeyDsPPClass, hKeySvr;
  650. long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0,
  651. KEY_WRITE, &hKeyCLSID);
  652. if (lRet != ERROR_SUCCESS)
  653. {
  654. dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet));
  655. return (HRESULT_FROM_WIN32(lRet));
  656. }
  657. LPOLESTR pszCLSID;
  658. PTSTR ptzCLSID;
  659. DWORD dwDisposition;
  660. for (int i = 0; i < g_DsPPClasses.cClasses; i++)
  661. {
  662. hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID);
  663. if (FAILED(hr))
  664. {
  665. DBG_OUT("StringFromCLSID failed");
  666. continue;
  667. }
  668. if (!UnicodeToTchar(pszCLSID, &ptzCLSID))
  669. {
  670. DBG_OUT("Memory Allocation failure!");
  671. CoTaskMemFree(pszCLSID);
  672. hr = E_OUTOFMEMORY;
  673. continue;
  674. }
  675. CoTaskMemFree(pszCLSID);
  676. lRet = RegCreateKeyEx(hKeyCLSID, ptzCLSID, 0, NULL,
  677. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
  678. &hKeyDsPPClass, &dwDisposition);
  679. delete ptzCLSID;
  680. if (lRet != ERROR_SUCCESS)
  681. {
  682. dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet));
  683. hr = HRESULT_FROM_WIN32(lRet);
  684. continue;
  685. }
  686. TCHAR szProgID[MAX_PATH];
  687. _tcscpy(szProgID, c_szDsProppagesProgID);
  688. _tcscat(szProgID, g_DsPPClasses.rgpClass[i]->szProgID);
  689. lRet = RegSetValueEx(hKeyDsPPClass, NULL, 0, REG_SZ,
  690. (CONST BYTE *)szProgID,
  691. sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(szProgID) + 1)));
  692. if (lRet != ERROR_SUCCESS)
  693. {
  694. RegCloseKey(hKeyDsPPClass);
  695. dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
  696. hr = HRESULT_FROM_WIN32(lRet);
  697. continue;
  698. }
  699. lRet = RegCreateKeyEx(hKeyDsPPClass, c_szServerType, 0, NULL,
  700. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
  701. &hKeySvr, &dwDisposition);
  702. RegCloseKey(hKeyDsPPClass);
  703. if (lRet != ERROR_SUCCESS)
  704. {
  705. dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet));
  706. hr = HRESULT_FROM_WIN32(lRet);
  707. continue;
  708. }
  709. lRet = RegSetValueEx(hKeySvr, NULL, 0, REG_SZ,
  710. (CONST BYTE *)c_szDsProppagesDllName,
  711. sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(c_szDsProppagesDllName) + 1)));
  712. if (lRet != ERROR_SUCCESS)
  713. {
  714. dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
  715. hr = HRESULT_FROM_WIN32(lRet);
  716. }
  717. lRet = RegSetValueEx(hKeySvr, c_szThreadModel, 0, REG_SZ,
  718. (CONST BYTE *)c_szThreadModelValue,
  719. sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(c_szThreadModelValue) + 1)));
  720. if (lRet != ERROR_SUCCESS)
  721. {
  722. dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
  723. hr = HRESULT_FROM_WIN32(lRet);
  724. }
  725. RegCloseKey(hKeySvr);
  726. }
  727. RegCloseKey(hKeyCLSID);
  728. return hr;
  729. }
  730. //+----------------------------------------------------------------------------
  731. //
  732. // Function: DllUnregisterServer
  733. //
  734. // Synopsis: Removes the entries from the system registry.
  735. //
  736. // Returns: S_OK or S_FALSE
  737. //
  738. // Notes: The keys look like this:
  739. //
  740. // HKC\CLSID\clsid <No Name> REG_SZ name.progid
  741. // \InPropServer32 <No Name> : REG_SZ : dsprop.dll
  742. // ThreadingModel : REG_SZ : Apartment
  743. //-----------------------------------------------------------------------------
  744. STDAPI
  745. DllUnregisterServer(void)
  746. {
  747. HRESULT hr = S_OK;
  748. HKEY hKeyCLSID, hKeyClass;
  749. long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0,
  750. KEY_ALL_ACCESS, &hKeyCLSID);
  751. if (lRet != ERROR_SUCCESS)
  752. {
  753. dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet));
  754. return (HRESULT_FROM_WIN32(lRet));
  755. }
  756. LPOLESTR pszCLSID;
  757. PTSTR ptzCLSID;
  758. for (int i = 0; i < g_DsPPClasses.cClasses; i++)
  759. {
  760. hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID);
  761. if (FAILED(hr))
  762. {
  763. DBG_OUT("StringFromCLSID failed");
  764. continue;
  765. }
  766. if (!UnicodeToTchar(pszCLSID, &ptzCLSID))
  767. {
  768. DBG_OUT("CLSID string memory allocation failure!");
  769. CoTaskMemFree(pszCLSID);
  770. hr = E_OUTOFMEMORY;
  771. continue;
  772. }
  773. CoTaskMemFree(pszCLSID);
  774. lRet = RegOpenKeyEx(hKeyCLSID, ptzCLSID, 0, KEY_ALL_ACCESS, &hKeyClass);
  775. if (lRet != ERROR_SUCCESS)
  776. {
  777. dspDebugOut((DEB_ITRACE, "Failed to open key %S\n", ptzCLSID));
  778. lRet = ERROR_SUCCESS;
  779. hr = S_FALSE;
  780. }
  781. else
  782. {
  783. lRet = RegDeleteKey(hKeyClass, c_szServerType);
  784. RegCloseKey(hKeyClass);
  785. dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n",
  786. c_szServerType, lRet));
  787. if (lRet != ERROR_SUCCESS)
  788. {
  789. lRet = ERROR_SUCCESS;
  790. hr = S_FALSE;
  791. }
  792. }
  793. lRet = RegDeleteKey(hKeyCLSID, ptzCLSID);
  794. dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n",
  795. ptzCLSID, lRet));
  796. delete ptzCLSID;
  797. if (lRet != ERROR_SUCCESS)
  798. {
  799. lRet = ERROR_SUCCESS;
  800. hr = S_FALSE;
  801. }
  802. }
  803. RegCloseKey(hKeyCLSID);
  804. return hr;
  805. }
  806. //+----------------------------------------------------------------------------
  807. //
  808. // Function: GlobalInit
  809. //
  810. // Synopsis: Sets up the global environment.
  811. //
  812. // Returns: S_OK or S_FALSE
  813. //
  814. //-----------------------------------------------------------------------------
  815. inline HRESULT
  816. GlobalInit(void)
  817. {
  818. //
  819. // Initialize common controls
  820. //
  821. InitCommonControls();
  822. INITCOMMONCONTROLSEX icce;
  823. icce.dwSize = sizeof(icce);
  824. icce.dwICC = ICC_DATE_CLASSES;
  825. InitCommonControlsEx(&icce);
  826. #if defined(DSPROP_ADMIN)
  827. //
  828. // Register the "CHECKLIST" control
  829. //
  830. RegisterCheckListWndClass();
  831. #endif
  832. #ifndef DSPROP_ADMIN
  833. //
  834. // Register the window class for the notification window.
  835. //
  836. RegisterNotifyClass();
  837. #endif
  838. //
  839. // Register the attribute-changed message.
  840. //
  841. g_uChangeMsg = RegisterWindowMessage(DSPROP_ATTRCHANGED_MSG);
  842. CHECK_NULL(g_uChangeMsg, ;);
  843. //
  844. // Major cheesy hack to allow locating windows that are unique to this
  845. // instance (since hInstance is invariant).
  846. //
  847. srand((unsigned)time(NULL));
  848. g_iInstance = rand();
  849. #ifndef DSPROP_ADMIN
  850. ExceptionPropagatingInitializeCriticalSection(&g_csNotifyCreate);
  851. #endif
  852. HRESULT hr = CheckRegisterClipFormats();
  853. dspAssert( SUCCEEDED(hr) );
  854. // If found, read the value of the Member class query clause count and
  855. // number-of-members limit.
  856. //
  857. HKEY hKey;
  858. LONG lRet;
  859. lRet = RegOpenKeyEx(HKEY_CURRENT_USER, DIRECTORY_UI_KEY, 0, KEY_READ, &hKey);
  860. if (lRet == ERROR_SUCCESS)
  861. {
  862. DWORD dwSize = sizeof(ULONG);
  863. RegQueryValueEx(hKey, MEMBER_QUERY_VALUE, NULL, NULL,
  864. (LPBYTE)&g_ulMemberFilterCount, &dwSize);
  865. RegQueryValueEx(hKey, MEMBER_LIMIT_VALUE, NULL, NULL,
  866. (LPBYTE)&g_ulMemberQueryLimit, &dwSize);
  867. RegCloseKey(hKey);
  868. }
  869. dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberFilterCount set to %d\n", g_ulMemberFilterCount));
  870. dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberQueryLimit set to %d\n", g_ulMemberQueryLimit));
  871. return S_OK;
  872. }
  873. //+----------------------------------------------------------------------------
  874. //
  875. // Function: GlobalUnInit
  876. //
  877. // Synopsis: Do resource freeing.
  878. //
  879. //-----------------------------------------------------------------------------
  880. inline void
  881. GlobalUnInit(void)
  882. {
  883. #if defined(DSPROP_ADMIN)
  884. if (!g_FPNWCache.empty())
  885. {
  886. for (Cache::iterator i = g_FPNWCache.begin(); i != g_FPNWCache.end(); i++)
  887. {
  888. if ((*i).second)
  889. LocalFree((*i).second);
  890. }
  891. g_FPNWCache.clear();
  892. }
  893. #endif
  894. g_ClassIconCache.ClearAll();
  895. #ifndef DSPROP_ADMIN
  896. DeleteCriticalSection(&g_csNotifyCreate);
  897. #endif
  898. }
  899. //+----------------------------------------------------------------------------
  900. //
  901. // Debugging routines.
  902. //
  903. //-----------------------------------------------------------------------------
  904. #if DBG == 1
  905. //////////////////////////////////////////////////////////////////////////////
  906. unsigned long SmAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
  907. BOOL fInfoLevelInit = FALSE;
  908. //////////////////////////////////////////////////////////////////////////////
  909. static int _cdecl w4dprintf(const char *format, ...);
  910. static int _cdecl w4smprintf(const char *format, va_list arglist);
  911. //////////////////////////////////////////////////////////////////////////////
  912. static int _cdecl w4dprintf(const char *format, ...)
  913. {
  914. int ret;
  915. va_list va;
  916. va_start(va, format);
  917. ret = w4smprintf(format, va);
  918. va_end(va);
  919. return ret;
  920. }
  921. static int _cdecl w4smprintf(const char *format, va_list arglist)
  922. {
  923. int ret;
  924. char szMessageBuf[DSP_DEBUG_BUF_SIZE];
  925. ret = wvnsprintfA(szMessageBuf, DSP_DEBUG_BUF_SIZE - 1, format, arglist);
  926. OutputDebugStringA(szMessageBuf);
  927. return ret;
  928. }
  929. //+---------------------------------------------------------------------------
  930. //
  931. // Function: _asdprintf
  932. //
  933. // Synopsis: Calls smprintf to output a formatted message.
  934. //
  935. // History: 18-Oct-91 vich Created
  936. //
  937. //----------------------------------------------------------------------------
  938. inline void __cdecl
  939. _asdprintf(
  940. char const *pszfmt, ...)
  941. {
  942. va_list va;
  943. va_start(va, pszfmt);
  944. smprintf(DEB_FORCE, "Assert", pszfmt, va);
  945. va_end(va);
  946. }
  947. //+---------------------------------------------------------------------------
  948. //
  949. // Function: SmAssertEx, private
  950. //
  951. // Synopsis: Display assertion information
  952. //
  953. // Effects: Called when an assertion is hit.
  954. //
  955. //----------------------------------------------------------------------------
  956. void APINOT
  957. SmAssertEx(
  958. char const * szFile,
  959. int iLine,
  960. char const * szMessage)
  961. {
  962. if (SmAssertLevel & ASSRT_MESSAGE)
  963. {
  964. DWORD tid = GetCurrentThreadId();
  965. _asdprintf("%s File: %s Line: %u, thread id %d\n",
  966. szMessage, szFile, iLine, tid);
  967. }
  968. if (SmAssertLevel & ASSRT_POPUP)
  969. {
  970. int id = PopUpError(szMessage,iLine,szFile);
  971. if (id == IDCANCEL)
  972. {
  973. DebugBreak();
  974. }
  975. }
  976. else if (SmAssertLevel & ASSRT_BREAK)
  977. {
  978. DebugBreak();
  979. }
  980. }
  981. //+------------------------------------------------------------
  982. // Function: PopUpError
  983. //
  984. // Synopsis: Displays a dialog box using provided text,
  985. // and presents the user with the option to
  986. // continue or cancel.
  987. //
  988. // Arguments:
  989. // szMsg -- The string to display in main body of dialog
  990. // iLine -- Line number of file in error
  991. // szFile -- Filename of file in error
  992. //
  993. // Returns:
  994. // IDCANCEL -- User selected the CANCEL button
  995. // IDOK -- User selected the OK button
  996. //-------------------------------------------------------------
  997. int APINOT
  998. PopUpError(
  999. char const *szMsg,
  1000. int iLine,
  1001. char const *szFile)
  1002. {
  1003. int id;
  1004. static char szAssertCaption[128];
  1005. static char szModuleName[128];
  1006. DWORD tid = GetCurrentThreadId();
  1007. DWORD pid = GetCurrentProcessId();
  1008. char * pszModuleName;
  1009. if (GetModuleFileNameA(NULL, szModuleName, 128))
  1010. {
  1011. pszModuleName = szModuleName;
  1012. }
  1013. else
  1014. {
  1015. pszModuleName = "Unknown";
  1016. }
  1017. wsprintfA(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
  1018. pszModuleName, szFile, iLine, pid, tid);
  1019. id = MessageBoxA(NULL,
  1020. szMsg,
  1021. szAssertCaption,
  1022. MB_SETFOREGROUND
  1023. | MB_DEFAULT_DESKTOP_ONLY
  1024. | MB_TASKMODAL
  1025. | MB_ICONEXCLAMATION
  1026. | MB_OKCANCEL);
  1027. //
  1028. // If id == 0, then an error occurred. There are two possibilities
  1029. // that can cause the error: Access Denied, which means that this
  1030. // process does not have access to the default desktop, and everything
  1031. // else (usually out of memory).
  1032. //
  1033. #ifdef DSPROP_ADMIN
  1034. if (0 == id)
  1035. {
  1036. if (GetLastError() == ERROR_ACCESS_DENIED)
  1037. {
  1038. //
  1039. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  1040. // should get us to the right desktop.
  1041. //
  1042. id = MessageBoxA(NULL,
  1043. szMsg,
  1044. szAssertCaption,
  1045. MB_SETFOREGROUND
  1046. | MB_SERVICE_NOTIFICATION
  1047. | MB_TASKMODAL
  1048. | MB_ICONEXCLAMATION
  1049. | MB_OKCANCEL);
  1050. }
  1051. }
  1052. #endif
  1053. return id;
  1054. }
  1055. //+------------------------------------------------------------
  1056. // Function: smprintf
  1057. //
  1058. // Synopsis: Prints debug output using a pointer to the
  1059. // variable information. Used primarily by the
  1060. // xxDebugOut macros
  1061. //
  1062. // Arguements:
  1063. // ulCompMask -- Component level mask used to determine
  1064. // output ability
  1065. // pszComp -- String const of component prefix.
  1066. // ppszfmt -- Pointer to output format and data
  1067. //
  1068. //-------------------------------------------------------------
  1069. void APINOT
  1070. smprintf(
  1071. unsigned long ulCompMask,
  1072. char const *pszComp,
  1073. char const *ppszfmt,
  1074. va_list pargs)
  1075. {
  1076. if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
  1077. (ulCompMask | DEF_INFOLEVEL))
  1078. {
  1079. DWORD tid = GetCurrentThreadId();
  1080. DWORD pid = GetCurrentProcessId();
  1081. if ((DEF_INFOLEVEL & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
  1082. {
  1083. if (! (ulCompMask & DEB_NOCOMPNAME))
  1084. {
  1085. w4dprintf("%x.%03x> %s: ", pid, tid, pszComp);
  1086. }
  1087. SYSTEMTIME st;
  1088. GetLocalTime(&st);
  1089. w4dprintf("%02d:%02d:%02d ", st.wHour, st.wMinute, st.wSecond);
  1090. w4smprintf(ppszfmt, pargs);
  1091. }
  1092. }
  1093. }
  1094. //+----------------------------------------------------------------------------
  1095. // Function: CheckInit
  1096. //
  1097. // Synopsis: Performs debugging library initialization
  1098. // including reading the registry for the desired infolevel
  1099. //
  1100. //-----------------------------------------------------------------------------
  1101. void APINOT
  1102. CheckInit(char * pInfoLevelString, unsigned long * pulInfoLevel)
  1103. {
  1104. HKEY hKey;
  1105. LONG lRet;
  1106. DWORD dwSize;
  1107. if (fInfoLevelInit) return;
  1108. fInfoLevelInit = TRUE;
  1109. lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, SMDEBUGKEY, 0, KEY_READ, &hKey);
  1110. if (lRet == ERROR_SUCCESS)
  1111. {
  1112. dwSize = sizeof(unsigned long);
  1113. lRet = RegQueryValueExA(hKey, pInfoLevelString, NULL, NULL,
  1114. (LPBYTE)pulInfoLevel, &dwSize);
  1115. if (lRet != ERROR_SUCCESS)
  1116. {
  1117. *pulInfoLevel = DEF_INFOLEVEL;
  1118. }
  1119. RegCloseKey(hKey);
  1120. }
  1121. }
  1122. #endif // DBG == 1
  1123. // This wrapper function required to make prefast shut up when we are
  1124. // initializing a critical section in a constructor.
  1125. void
  1126. ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec)
  1127. {
  1128. __try
  1129. {
  1130. ::InitializeCriticalSection(critsec);
  1131. }
  1132. //
  1133. // propagate the exception to our caller.
  1134. //
  1135. __except (EXCEPTION_CONTINUE_SEARCH)
  1136. {
  1137. }
  1138. }