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.

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