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.

2530 lines
72 KiB

  1. /****
  2. SchmUtil.cpp
  3. Various common utility routines for the Schema Editor Snap-In.
  4. ****/
  5. #include "stdafx.h"
  6. #include "macros.h"
  7. USE_HANDLE_MACROS("SCHMMGMT(schmutil.cpp)")
  8. #include "resource.h"
  9. #include "cache.h"
  10. #include "schmutil.h"
  11. #include "compdata.h"
  12. #include <wincrypt.h> // CryptEncodeObject() and CryptDecodeObject()
  13. //
  14. // Removed from public headers by DS guys
  15. // See bug 454342 XOM will not survive the transition to Win64
  16. //
  17. //#include <xom.h>
  18. //
  19. // Global strings for classes and attributes in the DS.
  20. // These are NOT subject to localization.
  21. //
  22. LPWSTR g_DisplayName = L"ldapDisplayName";
  23. LPWSTR g_ClassFilter = L"classSchema";
  24. LPWSTR g_AttributeFilter = L"attributeSchema";
  25. LPWSTR g_Description = L"adminDescription";
  26. LPWSTR g_MayContain = L"mayContain";
  27. LPWSTR g_MustContain = L"mustContain";
  28. LPWSTR g_SystemMayContain = L"systemMayContain";
  29. LPWSTR g_SystemMustContain = L"systemMustContain";
  30. LPWSTR g_AuxiliaryClass = L"auxiliaryClass";
  31. LPWSTR g_SystemAuxiliaryClass = L"systemAuxiliaryClass";
  32. LPWSTR g_SubclassOf = L"subclassOf";
  33. LPWSTR g_ObjectClassCategory = L"objectClassCategory";
  34. LPWSTR g_ObjectClass = L"objectClass";
  35. LPWSTR g_omObjectClass = L"oMObjectClass";
  36. LPWSTR g_CN = L"CN";
  37. LPWSTR g_omSyntax = L"oMSyntax";
  38. LPWSTR g_AttributeSyntax = L"attributeSyntax";
  39. LPWSTR g_SystemOnly = L"systemOnly";
  40. LPWSTR g_Superiors = L"possSuperiors";
  41. LPWSTR g_SystemSuperiors = L"systemPossSuperiors";
  42. LPWSTR g_GlobalClassID = L"governsID";
  43. LPWSTR g_GlobalAttributeID = L"attributeID";
  44. LPWSTR g_RangeUpper = L"rangeUpper";
  45. LPWSTR g_RangeLower = L"rangeLower";
  46. LPWSTR g_IsSingleValued = L"isSingleValued";
  47. LPWSTR g_IndexFlag = L"searchFlags";
  48. LPWSTR g_ShowInAdvViewOnly = L"showInAdvancedViewOnly";
  49. LPWSTR g_UpdateSchema = LDAP_OPATT_SCHEMA_UPDATE_NOW_W;
  50. LPWSTR g_BecomeFsmo = LDAP_OPATT_BECOME_SCHEMA_MASTER_W;
  51. LPWSTR g_isDefunct = L"isDefunct";
  52. LPWSTR g_GCReplicated = L"isMemberOfPartialAttributeSet";
  53. LPWSTR g_DefaultAcl = L"defaultSecurityDescriptor";
  54. LPWSTR g_DefaultCategory = L"defaultObjectCategory";
  55. LPWSTR g_systemFlags = L"systemFlags";
  56. LPWSTR g_fsmoRoleOwner = L"fsmoRoleOwner";
  57. LPWSTR g_allowedChildClassesEffective = L"allowedChildClassesEffective";
  58. LPWSTR g_allowedAttributesEffective = L"allowedAttributesEffective";
  59. LPWSTR g_ClassSearchRequest = L"objectClass=classSchema";
  60. LPWSTR g_AttribSearchRequest = L"objectClass=attributeSchema";
  61. //
  62. // Syntax values. Not subject to localization.
  63. //
  64. class CSyntaxDescriptor g_Syntax[] =
  65. {
  66. // NTRAID#NTBUG9-540278-2002/05/15-lucios
  67. // Added SYNTAX_CASE_STRING_TYPE
  68. // This list should be kept in alphabetical order since the combo box is not sorted
  69. // so that the index from the combo box can map to an entry in this table
  70. // nResourceID, fIsSigned, fIsANRCapable, pszAttributeSyntax, nOmSyntax, dwOmObjectClass, pOmObjectClass
  71. /*SYNTAX_DISTNAME_STRING_TYPE (Access-Point) */ CSyntaxDescriptor( IDS_SYNTAX_ACCESS_POINT,FALSE, FALSE, _T("2.5.5.14"), /*OM_S_OBJECT */ 127, 9, (LPBYTE)"\x2B\x0C\x02\x87\x73\x1C\x00\x85\x3E" ),
  72. /*SYNTAX_ADDRESS_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_ADDRESS, FALSE, FALSE, _T("2.5.5.13"), /*OM_S_OBJECT */ 127, 9, (LPBYTE)"\x2B\x0C\x02\x87\x73\x1C\x00\x85\x5C" ),
  73. /*SYNTAX_BOOLEAN_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_BOOLEAN, FALSE, FALSE, _T("2.5.5.8") , /*OM_S_BOOLEAN */ 1 , 0, NULL ),
  74. /*SYNTAX_NOCASE_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_NOCASE_STR, FALSE, TRUE, _T("2.5.5.4") , /*OM_S_TELETEX_STRING */ 20 , 0, NULL ),
  75. /*SYNTAX_CASE_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_CASE_STR, FALSE, TRUE , _T("2.5.5.3"), /*OM_S_GENERAL_STRING */ 27 , 0, NULL ),
  76. /*SYNTAX_DISTNAME_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_DN, FALSE, FALSE, _T("2.5.5.1") , /*OM_S_OBJECT */ 127, 9, (LPBYTE)"\x2B\x0C\x02\x87\x73\x1C\x00\x85\x4A" ),
  77. /*SYNTAX_DISTNAME_STRING_TYPE (DN-String) */ CSyntaxDescriptor( IDS_SYNTAX_DNSTRING, FALSE, FALSE, _T("2.5.5.14"), /*OM_S_OBJECT */ 127, 10, (LPBYTE)"\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0C" ),
  78. /*SYNTAX_DISTNAME_BINARY_TYPE (DN-Binary) */ CSyntaxDescriptor( IDS_SYNTAX_DN_BINARY, FALSE, FALSE, _T("2.5.5.7") , /*OM_S_OBJECT */ 127, 10, (LPBYTE)"\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0B" ),
  79. /*SYNTAX_INTEGER_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_ENUMERATION, TRUE, FALSE, _T("2.5.5.9") , /*OM_S_ENUMERATION */ 10 , 0, NULL ),
  80. /*SYNTAX_TIME_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_GEN_TIME, FALSE, FALSE, _T("2.5.5.11"), /*OM_S_GENERALISED_TIME_STRING */ 24 , 0, NULL ),
  81. /*SYNTAX_PRINT_CASE_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_I5_STR, FALSE, TRUE, _T("2.5.5.5") , /*OM_S_IA5_STRING */ 22 , 0, NULL ),
  82. /*SYNTAX_INTEGER_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_INTEGER, TRUE, FALSE, _T("2.5.5.9") , /*OM_S_INTEGER */ 2 , 0, NULL ),
  83. /*SYNTAX_I8_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_LINT, FALSE, FALSE, _T("2.5.5.16"), /*OM_S_I8 */ 65 , 0, NULL ),
  84. /*SYNTAX_NT_SECURITY_DESCRIPTOR_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_SEC_DESC, FALSE, FALSE, _T("2.5.5.15"), /*OM_S_OBJECT_SECURITY_DESCRIPTOR*/ 66 , 0, NULL ),
  85. /*SYNTAX_NUMERIC_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_NUMSTR, FALSE, FALSE, _T("2.5.5.6") , /*OM_S_NUMERIC_STRING */ 18 , 0, NULL ),
  86. /*SYNTAX_OBJECT_ID_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_OID, FALSE, FALSE, _T("2.5.5.2") , /*OM_S_OBJECT_IDENTIFIER_STRING */ 6 , 0, NULL ),
  87. /*SYNTAX_OCTET_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_OCTET, FALSE, FALSE, _T("2.5.5.10"), /*OM_S_OCTET_STRING */ 4 , 0, NULL ),
  88. /*SYNTAX_DISTNAME_BINARY_TYPE (OR-Name) */ CSyntaxDescriptor( IDS_SYNTAX_OR_NAME, FALSE, FALSE, _T("2.5.5.7") , /*OM_S_OBJECT */ 127, 7, (LPBYTE)"\x56\x06\x01\x02\x05\x0B\x1D" ),
  89. /*SYNTAX_PRINT_CASE_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_PRCS_STR, FALSE, TRUE, _T("2.5.5.5") , /*OM_S_PRINTABLE_STRING */ 19 , 0, NULL ),
  90. /*SYNTAX_OCTET_STRING_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_REPLICA_LINK,FALSE, FALSE, _T("2.5.5.10"), /*OM_S_OBJECT */ 127, 10, (LPBYTE)"\x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x06" ),
  91. /*SYNTAX_SID_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_SID, FALSE, FALSE, _T("2.5.5.17"), /*OM_S_OCTET_STRING */ 4 , 0, NULL ),
  92. /*SYNTAX_UNICODE_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_UNICODE, FALSE, TRUE, _T("2.5.5.12"), /*OM_S_UNICODE_STRING */ 64 , 0, NULL ),
  93. /*SYNTAX_TIME_TYPE */ CSyntaxDescriptor( IDS_SYNTAX_UTC, FALSE, FALSE, _T("2.5.5.11"), /*OM_S_UTC_TIME_STRING */ 23 , 0, NULL ),
  94. /* *** unknown -- must be last *** */ CSyntaxDescriptor( IDS_SYNTAX_UNKNOWN, FALSE, TRUE, NULL, 0 , 0, NULL ),
  95. };
  96. const UINT SCHEMA_SYNTAX_UNKNOWN = sizeof( g_Syntax ) / sizeof( g_Syntax[0] ) - 1;
  97. // Number formating printf strings
  98. const LPWSTR g_UINT32_FORMAT = L"%u";
  99. #ifdef ENABLE_NEGATIVE_INT
  100. const LPWSTR g_INT32_FORMAT = L"%d";
  101. #else
  102. // if there is no negative numbers support, format as unsigned
  103. const LPWSTR g_INT32_FORMAT = g_UINT32_FORMAT;
  104. #endif
  105. //
  106. // *******************************************************************
  107. // These are loaded from the resources as they need to be localizable.
  108. // *******************************************************************
  109. //
  110. //
  111. // Global strings for our static nodes.
  112. //
  113. CString g_strSchmMgmt;
  114. CString g_strClasses;
  115. CString g_strAttributes;
  116. //
  117. // Strings for various object types.
  118. //
  119. CString g_88Class;
  120. CString g_StructuralClass;
  121. CString g_AuxClass;
  122. CString g_AbstractClass;
  123. CString g_MandatoryAttribute;
  124. CString g_OptionalAttribute;
  125. CString g_Yes;
  126. CString g_No;
  127. CString g_Unknown;
  128. CString g_Defunct;
  129. CString g_Active;
  130. //
  131. // Message strings.
  132. //
  133. CString g_NoDescription;
  134. CString g_NoName;
  135. CString g_MsgBoxErr;
  136. CString g_MsgBoxWarn;
  137. //
  138. // Menu strings.
  139. //
  140. CString g_MenuStrings[MENU_LAST_COMMAND];
  141. CString g_StatusStrings[MENU_LAST_COMMAND];
  142. BOOL g_fScopeStringsLoaded = FALSE;
  143. //
  144. // Utility functions.
  145. //
  146. void
  147. LoadGlobalCookieStrings(
  148. )
  149. /***
  150. Load the global strings out of our resource table.
  151. ***/
  152. {
  153. if ( !g_fScopeStringsLoaded )
  154. {
  155. //
  156. // Static node strings.
  157. //
  158. VERIFY( g_strSchmMgmt.LoadString(IDS_SCOPE_SCHMMGMT) );
  159. VERIFY( g_strClasses.LoadString(IDS_SCOPE_CLASSES) );
  160. VERIFY( g_strAttributes.LoadString(IDS_SCOPE_ATTRIBUTES) );
  161. //
  162. // Object name strings.
  163. //
  164. VERIFY( g_88Class.LoadString(IDS_CLASS_88) );
  165. VERIFY( g_StructuralClass.LoadString(IDS_CLASS_STRUCTURAL) );
  166. VERIFY( g_AuxClass.LoadString(IDS_CLASS_AUXILIARY) );
  167. VERIFY( g_AbstractClass.LoadString(IDS_CLASS_ABSTRACT) );
  168. VERIFY( g_MandatoryAttribute.LoadString(IDS_ATTRIBUTE_MANDATORY) );
  169. VERIFY( g_OptionalAttribute.LoadString(IDS_ATTRIBUTE_OPTIONAL) );
  170. VERIFY( g_Yes.LoadString(IDS_YES) );
  171. VERIFY( g_No.LoadString(IDS_NO) );
  172. VERIFY( g_Unknown.LoadString(IDS_UNKNOWN) );
  173. VERIFY( g_Defunct.LoadString(IDS_DEFUNCT) );
  174. VERIFY( g_Active.LoadString(IDS_ACTIVE) );
  175. //
  176. // Message strings.
  177. //
  178. VERIFY( g_NoDescription.LoadString(IDS_ERR_NO_DESCRIPTION) );
  179. VERIFY( g_NoName.LoadString(IDS_ERR_NO_NAME) );
  180. VERIFY( g_MsgBoxErr.LoadString(IDS_ERR_ERROR) );
  181. VERIFY( g_MsgBoxWarn.LoadString(IDS_ERR_WARNING) );
  182. //
  183. // Syntax strings.
  184. //
  185. for( UINT i = 0; i <= SCHEMA_SYNTAX_UNKNOWN; i++ )
  186. {
  187. ASSERT( g_Syntax[i].m_nResourceID );
  188. VERIFY( g_Syntax[i].m_strSyntaxName.LoadString( g_Syntax[i].m_nResourceID ) );
  189. }
  190. //
  191. // Menu Strings
  192. //
  193. VERIFY( g_MenuStrings[CLASSES_CREATE_CLASS].LoadString(IDS_MENU_CLASS) );
  194. VERIFY
  195. (
  196. g_MenuStrings[VIEW_DEFUNCT_OBJECTS].LoadString
  197. (
  198. IDS_MENU_VIEW_DEFUNCT_OBJECTS
  199. )
  200. );
  201. VERIFY( g_MenuStrings[NEW_CLASS].LoadString(IDS_MENU_NEW_CLASS) );
  202. VERIFY( g_MenuStrings[ATTRIBUTES_CREATE_ATTRIBUTE].LoadString(
  203. IDS_MENU_ATTRIBUTE) );
  204. VERIFY(g_MenuStrings[NEW_ATTRIBUTE].LoadString(IDS_MENU_NEW_ATTRIBUTE));
  205. VERIFY( g_MenuStrings[SCHEMA_RETARGET].LoadString(IDS_MENU_RETARGET) );
  206. VERIFY( g_MenuStrings[SCHEMA_EDIT_FSMO].LoadString(IDS_MENU_EDIT_FSMO) );
  207. VERIFY( g_MenuStrings[SCHEMA_REFRESH].LoadString(IDS_MENU_REFRESH) );
  208. VERIFY( g_MenuStrings[SCHEMA_SECURITY].LoadString(IDS_MENU_SECURITY) );
  209. VERIFY( g_StatusStrings[CLASSES_CREATE_CLASS].LoadString(
  210. IDS_STATUS_CREATE_CLASS) );
  211. VERIFY
  212. (
  213. g_StatusStrings[VIEW_DEFUNCT_OBJECTS].LoadString
  214. (
  215. IDS_STATUS_VIEW_DEFUNCT_OBJECTS
  216. )
  217. );
  218. VERIFY( g_StatusStrings[ATTRIBUTES_CREATE_ATTRIBUTE].LoadString(
  219. IDS_STATUS_CREATE_ATTRIBUTE) );
  220. VERIFY( g_StatusStrings[NEW_CLASS].LoadString(
  221. IDS_STATUS_CREATE_CLASS) );
  222. VERIFY( g_StatusStrings[NEW_ATTRIBUTE].LoadString(
  223. IDS_STATUS_CREATE_ATTRIBUTE) );
  224. VERIFY( g_StatusStrings[SCHEMA_RETARGET].LoadString(IDS_STATUS_RETARGET) );
  225. VERIFY( g_StatusStrings[SCHEMA_EDIT_FSMO].LoadString(IDS_STATUS_EDIT_FSMO) );
  226. VERIFY( g_StatusStrings[SCHEMA_REFRESH].LoadString(IDS_STATUS_REFRESH) );
  227. VERIFY( g_StatusStrings[SCHEMA_SECURITY].LoadString(IDS_STATUS_SECURITY) );
  228. g_fScopeStringsLoaded = TRUE;
  229. }
  230. }
  231. INT
  232. DoErrMsgBox(
  233. HWND hwndParent, // IN: Parent of the dialog box
  234. BOOL fError, // IN: Is this a warning or an error?
  235. UINT wIdString, // IN: String resource Id of the error.
  236. HRESULT hr // IN: the error code (optional)
  237. )
  238. /***
  239. Display a message box with the error.
  240. ***/
  241. {
  242. CString Error;
  243. VERIFY( Error.LoadString( wIdString ) );
  244. return DoErrMsgBox( hwndParent, fError, Error, hr );
  245. }
  246. INT
  247. DoErrMsgBox(
  248. HWND hwndParent, // IN: Parent of the dialog box
  249. BOOL fError, // IN: Is this a warning or an error?
  250. PCWSTR pszError, // IN: String to display.
  251. HRESULT hr // IN: the error code (optional)
  252. )
  253. /***
  254. Display a message box with the error.
  255. ***/
  256. {
  257. CThemeContextActivator activator;
  258. PTSTR ptzSysMsg = NULL;
  259. int cch = 0;
  260. if (FAILED(hr))
  261. {
  262. cch = cchLoadHrMsg(hr, &ptzSysMsg, TRUE);
  263. }
  264. if (!cch)
  265. {
  266. return MessageBox(
  267. hwndParent,
  268. pszError,
  269. (fError ? g_MsgBoxErr : g_MsgBoxWarn),
  270. (fError ? MB_ICONSTOP : MB_ICONEXCLAMATION) | MB_OK
  271. );
  272. }
  273. CString szError = pszError;
  274. szError += L"\n";
  275. szError += ptzSysMsg;
  276. return MessageBox(
  277. hwndParent,
  278. szError,
  279. (fError ? g_MsgBoxErr : g_MsgBoxWarn),
  280. (fError ? MB_ICONSTOP : MB_ICONEXCLAMATION) | MB_OK
  281. );
  282. }
  283. HRESULT
  284. ComponentData::ForceDsSchemaCacheUpdate(
  285. VOID
  286. )
  287. /***
  288. Force the schema container to reload its interal cache.
  289. If this succeeds, it returns TRUE. Otherwise, it returns
  290. FALSE.
  291. ***/
  292. {
  293. AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
  294. CWaitCursor wait;
  295. CString RootDsePath;
  296. IADs *pSchemaRootDse = NULL;
  297. SAFEARRAYBOUND RootDseBoundary[1];
  298. SAFEARRAY* pSafeArray = NULL;
  299. VARIANT AdsArray, AdsValue;
  300. long ArrayLen = 1;
  301. long ArrayPos = 0;
  302. HRESULT hr = S_OK;
  303. do
  304. {
  305. //
  306. // Open the root DSE on the current focus server.
  307. //
  308. GetBasePathsInfo()->GetRootDSEPath(RootDsePath);
  309. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  310. // NOTE: const_cast not necessary here since ADsGetObject takes a WSTR for the first parameter.
  311. hr = SchemaOpenObject(
  312. ( const_cast<BSTR>((LPCTSTR) RootDsePath ) ),
  313. IID_IADs,
  314. (void **)&pSchemaRootDse );
  315. BREAK_ON_FAILED_HRESULT(hr);
  316. //
  317. // Create the safe array for the PutEx call.
  318. //
  319. RootDseBoundary[0].lLbound = 0;
  320. RootDseBoundary[0].cElements = ArrayLen;
  321. pSafeArray = SafeArrayCreate( VT_VARIANT, ArrayLen, RootDseBoundary );
  322. BREAK_ON_FAILED_HRESULT(hr);
  323. VariantInit( &AdsArray );
  324. V_VT( &AdsArray ) = VT_ARRAY | VT_VARIANT;
  325. V_ARRAY( &AdsArray ) = pSafeArray;
  326. VariantInit( &AdsValue );
  327. V_VT(&AdsValue) = VT_I4;
  328. V_I4(&AdsValue) = 1;
  329. hr = SafeArrayPutElement( pSafeArray, &ArrayPos, &AdsValue );
  330. BREAK_ON_FAILED_HRESULT(hr);
  331. //
  332. // Write the update parameter. This is synchronous
  333. // and when it returns, the cache is up to date.
  334. //
  335. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  336. hr = pSchemaRootDse->PutEx( ADS_PROPERTY_APPEND,
  337. const_cast<BSTR>((LPCTSTR)g_UpdateSchema),
  338. AdsArray );
  339. if(FAILED(hr)) {hr=S_FALSE;break;} // schema is read only
  340. hr = pSchemaRootDse->SetInfo();
  341. if(FAILED(hr)) {hr=S_FALSE;break;} // schema is read only
  342. } while( FALSE );
  343. SafeArrayDestroy( pSafeArray );
  344. if( pSchemaRootDse )
  345. pSchemaRootDse->Release();
  346. return hr;
  347. }
  348. BOOLEAN
  349. ComponentData::AsynchForceDsSchemaCacheUpdate(
  350. VOID
  351. ) {
  352. AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
  353. CWaitCursor wait;
  354. CString szSchemaContainerPath;
  355. IADs *pSchemaContainer;
  356. VARIANT AdsValue;
  357. HRESULT hr;
  358. SYSTEMTIME CurrentTime;
  359. double variant_time;
  360. //
  361. // Get the schema container path.
  362. //
  363. GetBasePathsInfo()->GetSchemaPath(szSchemaContainerPath);
  364. if (szSchemaContainerPath.IsEmpty() ) {
  365. return FALSE;
  366. }
  367. //
  368. // Open the schema container.
  369. //
  370. hr = SchemaOpenObject(
  371. (LPWSTR)(LPCWSTR)szSchemaContainerPath,
  372. IID_IADs,
  373. (void **)&pSchemaContainer );
  374. if ( FAILED(hr) ) {
  375. return FALSE;
  376. }
  377. //
  378. // Write the update parameter.
  379. //
  380. GetSystemTime( &CurrentTime );
  381. BOOL result = SystemTimeToVariantTime( &CurrentTime, &variant_time );
  382. ASSERT( result );
  383. VariantInit( &AdsValue );
  384. V_VT(&AdsValue) = VT_DATE;
  385. V_DATE(&AdsValue) = variant_time;
  386. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  387. hr = pSchemaContainer->Put( const_cast<BSTR>((LPCTSTR)g_UpdateSchema),
  388. AdsValue );
  389. // NTRAID#NTBUG9-542354-2002/02/14-dantra-Errors returned by IADs::Put and PutEx are being masked.
  390. if ( SUCCEEDED( hr ) ) hr = pSchemaContainer->SetInfo();
  391. pSchemaContainer->Release();
  392. if ( FAILED( hr ) ) {
  393. return FALSE;
  394. }
  395. return TRUE;
  396. }
  397. HRESULT
  398. InsertEditItems(
  399. HWND hwnd,
  400. VARIANT *AdsResult
  401. ) {
  402. HRESULT hr;
  403. SAFEARRAY *saAttributes;
  404. long start, end, current;
  405. VARIANT SingleResult;
  406. //
  407. // Check the VARIANT to make sure we have
  408. // an array of variants.
  409. //
  410. ASSERT( V_VT(AdsResult) == ( VT_ARRAY | VT_VARIANT ) );
  411. saAttributes = V_ARRAY( AdsResult );
  412. //
  413. // Figure out the dimensions of the array.
  414. //
  415. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  416. if ( FAILED(hr) ) {
  417. return S_FALSE;
  418. }
  419. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  420. if ( FAILED(hr) ) {
  421. return S_FALSE;
  422. }
  423. VariantInit( &SingleResult );
  424. //
  425. // Process the array elements.
  426. //
  427. for ( current = start ;
  428. current <= end ;
  429. current++ ) {
  430. hr = SafeArrayGetElement( saAttributes, &current, &SingleResult );
  431. if ( SUCCEEDED( hr ) ) {
  432. ASSERT( V_VT(&SingleResult) == VT_BSTR );
  433. ::SendMessage( hwnd, LB_ADDSTRING, 0,
  434. reinterpret_cast<LPARAM>(V_BSTR(&SingleResult)) );
  435. ::SendMessage( hwnd, LB_SETITEMDATA, 0, NULL );
  436. VariantClear( &SingleResult );
  437. }
  438. }
  439. return S_OK;
  440. }
  441. HRESULT
  442. InsertEditItems(
  443. CListBox& refListBox,
  444. CStringList& refstringlist
  445. )
  446. {
  447. POSITION pos = refstringlist.GetHeadPosition();
  448. while (pos != NULL)
  449. {
  450. int iItem = refListBox.AddString( refstringlist.GetNext(pos) );
  451. if (0 > iItem)
  452. {
  453. ASSERT(FALSE);
  454. return E_OUTOFMEMORY;
  455. }
  456. else
  457. {
  458. VERIFY( LB_ERR != refListBox.SetItemDataPtr( iItem, NULL ) );
  459. }
  460. }
  461. return S_OK;
  462. }
  463. inline BOOL
  464. IsEqual( ADS_OCTET_STRING * ostr1, ADS_OCTET_STRING * ostr2 )
  465. {
  466. ASSERT(ostr1);
  467. ASSERT(ostr2);
  468. if( ostr1->dwLength == ostr2->dwLength )
  469. {
  470. if( 0 == ostr1->dwLength )
  471. return TRUE;
  472. else
  473. return !memcmp( ostr1->lpValue, ostr2->lpValue, ostr1->dwLength );
  474. }
  475. else
  476. return FALSE;
  477. }
  478. UINT
  479. GetSyntaxOrdinal( PCTSTR attributeSyntax, UINT omSyntax, ADS_OCTET_STRING * pOmObjectClass )
  480. {
  481. ASSERT( attributeSyntax );
  482. ASSERT( omSyntax );
  483. ASSERT( pOmObjectClass );
  484. //
  485. // Return the syntax ordinal, or the unknown syntax ordinal.
  486. //
  487. UINT Ordinal = 0;
  488. while ( Ordinal < SCHEMA_SYNTAX_UNKNOWN) {
  489. if ( !_tcscmp(g_Syntax[Ordinal].m_pszAttributeSyntax, attributeSyntax))
  490. {
  491. if( omSyntax && g_Syntax[Ordinal].m_nOmSyntax == omSyntax &&
  492. IsEqual( &g_Syntax[Ordinal].m_octstrOmObjectClass, pOmObjectClass ) )
  493. break;
  494. }
  495. Ordinal++;
  496. }
  497. return Ordinal;
  498. }
  499. // Coded to fail on anything suspicious
  500. HRESULT
  501. VariantToStringList(
  502. VARIANT& refvar,
  503. CStringList& refstringlist
  504. )
  505. {
  506. HRESULT hr = S_OK;
  507. long start, end, current;
  508. //
  509. // Check the VARIANT to make sure we have
  510. // an array of variants.
  511. //
  512. if ( V_VT(&refvar) != ( VT_ARRAY | VT_VARIANT ) )
  513. {
  514. ASSERT(FALSE);
  515. return E_UNEXPECTED;
  516. }
  517. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  518. //
  519. // Figure out the dimensions of the array.
  520. //
  521. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  522. if( FAILED(hr) )
  523. return hr;
  524. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  525. if( FAILED(hr) )
  526. return hr;
  527. VARIANT SingleResult;
  528. VariantInit( &SingleResult );
  529. //
  530. // Process the array elements.
  531. //
  532. for ( current = start ;
  533. current <= end ;
  534. current++ ) {
  535. hr = SafeArrayGetElement( saAttributes, &current, &SingleResult );
  536. if( FAILED(hr) )
  537. return hr;
  538. if ( V_VT(&SingleResult) != VT_BSTR )
  539. return E_UNEXPECTED;
  540. refstringlist.AddHead( V_BSTR(&SingleResult) );
  541. VariantClear( &SingleResult );
  542. }
  543. return S_OK;
  544. }
  545. HRESULT
  546. StringListToVariant(
  547. VARIANT& refvar,
  548. CStringList& refstringlist
  549. )
  550. {
  551. HRESULT hr = S_OK;
  552. int cCount = (int) refstringlist.GetCount();
  553. SAFEARRAYBOUND rgsabound[1];
  554. rgsabound[0].lLbound = 0;
  555. rgsabound[0].cElements = cCount;
  556. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
  557. if (NULL == psa)
  558. return E_OUTOFMEMORY;
  559. VariantClear( &refvar );
  560. V_VT(&refvar) = VT_VARIANT|VT_ARRAY;
  561. V_ARRAY(&refvar) = psa;
  562. VARIANT SingleResult;
  563. VariantInit( &SingleResult );
  564. V_VT(&SingleResult) = VT_BSTR;
  565. POSITION pos = refstringlist.GetHeadPosition();
  566. long i;
  567. for (i = 0; i < cCount, pos != NULL; i++)
  568. {
  569. V_BSTR(&SingleResult) = T2BSTR((LPCTSTR)refstringlist.GetNext(pos));
  570. hr = SafeArrayPutElement(psa, &i, &SingleResult);
  571. if( FAILED(hr) )
  572. return hr;
  573. }
  574. if (i != cCount || pos != NULL)
  575. return E_UNEXPECTED;
  576. return hr;
  577. }
  578. HRESULT
  579. StringListToColumnList(
  580. ComponentData* pScopeControl,
  581. CStringList& refstringlist,
  582. ListEntry **ppNewList
  583. ) {
  584. //
  585. // Make a column list from a string list. We use
  586. // this to update the cached attributes lists.
  587. //
  588. int cCount = (int) refstringlist.GetCount();
  589. ListEntry *pHead = NULL;
  590. ListEntry *pCurrent = NULL, *pPrevious = NULL;
  591. POSITION pos = refstringlist.GetHeadPosition();
  592. CString Name;
  593. SchemaObject *pSchemaObject, *pSchemaHead;
  594. BOOLEAN fNameFound;
  595. for ( long i = 0; i < cCount, pos != NULL; i++ ) {
  596. pCurrent = new ListEntry;
  597. if ( !pCurrent ) {
  598. pScopeControl->g_SchemaCache.FreeColumnList( pHead );
  599. return E_OUTOFMEMORY;
  600. }
  601. if ( !pHead ) {
  602. pHead = pPrevious = pCurrent;
  603. } else {
  604. pPrevious->pNext = pCurrent;
  605. pPrevious = pCurrent;
  606. }
  607. //
  608. // We need to list all of these by their ldapDisplayNames,
  609. // so we have to reverse lookup the oid entries.
  610. //
  611. Name = ((LPCTSTR)refstringlist.GetNext(pos));
  612. pSchemaObject = pScopeControl->g_SchemaCache.LookupSchemaObject(
  613. Name,
  614. SCHMMGMT_CLASS );
  615. if ( !pSchemaObject ) {
  616. pSchemaObject = pScopeControl->g_SchemaCache.LookupSchemaObject(
  617. Name,
  618. SCHMMGMT_ATTRIBUTE );
  619. if ( !pSchemaObject) {
  620. //
  621. // We have to look up this oid.
  622. // First try the list of classes.
  623. //
  624. pSchemaHead = pScopeControl->g_SchemaCache.pSortedClasses;
  625. pSchemaObject = pSchemaHead;
  626. fNameFound = FALSE;
  627. do {
  628. if ( pSchemaObject->oid == Name ) {
  629. Name = pSchemaObject->ldapDisplayName;
  630. fNameFound = TRUE;
  631. break;
  632. }
  633. pSchemaObject = pSchemaObject->pSortedListFlink;
  634. } while ( pSchemaObject != pSchemaHead );
  635. //
  636. // Then try the list of attributes.
  637. //
  638. if ( !fNameFound ) {
  639. pSchemaHead = pScopeControl->g_SchemaCache.pSortedAttribs;
  640. pSchemaObject = pSchemaHead;
  641. do {
  642. if ( pSchemaObject->oid == Name ) {
  643. Name = pSchemaObject->ldapDisplayName;
  644. fNameFound = TRUE;
  645. break;
  646. }
  647. pSchemaObject = pSchemaObject->pSortedListFlink;
  648. } while ( pSchemaObject != pSchemaHead );
  649. }
  650. ASSERT( fNameFound );
  651. } else {
  652. pScopeControl->g_SchemaCache.ReleaseRef( pSchemaObject );
  653. }
  654. } else {
  655. pScopeControl->g_SchemaCache.ReleaseRef( pSchemaObject );
  656. }
  657. //
  658. // This is the ldapDisplayName!!
  659. //
  660. pCurrent->Attribute = Name;
  661. }
  662. ASSERT( cCount == i );
  663. ASSERT( pos == NULL );
  664. *ppNewList = pHead;
  665. return S_OK;
  666. }
  667. const UINT MAX_ERROR_BUF = 2048;
  668. VOID
  669. DoExtErrMsgBox(
  670. VOID
  671. )
  672. {
  673. CThemeContextActivator activator;
  674. DWORD dwLastError;
  675. WCHAR szErrorBuf[MAX_ERROR_BUF + 1];
  676. WCHAR szNameBuf[MAX_ERROR_BUF + 1];
  677. // get extended error value
  678. HRESULT hr_return = ADsGetLastError( &dwLastError,
  679. szErrorBuf,
  680. MAX_ERROR_BUF,
  681. szNameBuf,
  682. MAX_ERROR_BUF);
  683. if (SUCCEEDED(hr_return))
  684. {
  685. MessageBox( ::GetActiveWindow(),
  686. szErrorBuf,
  687. szNameBuf,
  688. MB_OK | MB_ICONSTOP );
  689. }
  690. else
  691. ASSERT( FALSE );
  692. }
  693. // INVALID_POINTER is returned by CListBox::GetItemDataPtr() in case of an error.
  694. const VOID * INVALID_POINTER = reinterpret_cast<void *>( LB_ERR );
  695. HRESULT
  696. RetrieveEditItemsWithExclusions(
  697. CListBox& refListBox,
  698. CStringList& refstringlist,
  699. CStringList* pstringlistExclusions)
  700. {
  701. CString str;
  702. CString * pstr = NULL;
  703. int nCount = refListBox.GetCount();
  704. if (LB_ERR == nCount)
  705. {
  706. ASSERT(FALSE);
  707. return E_UNEXPECTED;
  708. }
  709. for (INT i = 0; i < nCount; i++)
  710. {
  711. pstr = static_cast<CString *>( refListBox.GetItemDataPtr(i) );
  712. ASSERT( INVALID_POINTER != pstr );
  713. // don't need to search for pstr because pstr can only be a new item,
  714. // and they are never excluded.
  715. if( pstr && INVALID_POINTER != pstr )
  716. {
  717. refstringlist.AddHead( *pstr );
  718. }
  719. else
  720. {
  721. refListBox.GetText( i, str );
  722. if (NULL != pstringlistExclusions)
  723. {
  724. POSITION pos = pstringlistExclusions->Find( str );
  725. if (NULL != pos)
  726. continue;
  727. }
  728. refstringlist.AddHead( str );
  729. }
  730. }
  731. return S_OK;
  732. }
  733. //
  734. // The global cookie lists for scope and result pane items.
  735. //
  736. VOID
  737. CCookieList::AddCookie(
  738. Cookie *pCookie,
  739. HSCOPEITEM hScope
  740. ) {
  741. CCookieListEntry *pNewEntry = new CCookieListEntry;
  742. //
  743. // If there's no memory, we can't remember this and hence
  744. // our display may get a little out of whack.
  745. //
  746. if ( !pNewEntry ) {
  747. return;
  748. }
  749. pNewEntry->pCookie = pCookie;
  750. pNewEntry->hScopeItem = hScope;
  751. if ( !pHead ) {
  752. //
  753. // If this is the first one, just set the
  754. // head pointer. The constructor for the
  755. // list entry has already set the next and
  756. // back pointers.
  757. //
  758. pHead = pNewEntry;
  759. } else {
  760. //
  761. // Insert this at the end of the circular
  762. // doubly-linked list.
  763. //
  764. pNewEntry->pBack = pHead->pBack;
  765. pNewEntry->pNext = pHead;
  766. pHead->pBack->pNext = pNewEntry;
  767. pHead->pBack = pNewEntry;
  768. }
  769. return;
  770. }
  771. VOID
  772. CCookieList::InsertSortedDisplay(
  773. ComponentData *pScopeControl,
  774. SchemaObject *pNewObject
  775. )
  776. /***
  777. Notes:
  778. This function inserts the object into the
  779. sorted display list.
  780. If the object is a class and the ComponentData
  781. interface pointer is provided, this routine will
  782. also create a cookie for this object and insert
  783. the scope item into the view.
  784. ***/
  785. {
  786. HRESULT hr;
  787. CCookieListEntry *pNewEntry = NULL, *pCurrent = NULL;
  788. // NTRAID#NTBUG9-562405-2002/03/04-dantra-Possible use of uninitalized SCOPEDATAITEM
  789. SCOPEDATAITEM ScopeItem={0};
  790. Cookie *pNewCookie= NULL;
  791. int compare;
  792. //
  793. // If this cookie list is empty, there's nothing
  794. // in the display and we don't need to do anything.
  795. //
  796. if ( !pHead ) {
  797. return;
  798. }
  799. //
  800. // Allocate a new cookie list entry. If we can't
  801. // do nothing. The display will be out of sync
  802. // until the user refreshes.
  803. //
  804. pNewEntry = new CCookieListEntry;
  805. if ( !pNewEntry ) {
  806. return;
  807. }
  808. //
  809. // Prepare the required mmc structures.
  810. //
  811. if ( pNewObject->schemaObjectType == SCHMMGMT_CLASS ) {
  812. if ( !pScopeControl ) {
  813. //
  814. // If there's no scope control, we can't insert anything.
  815. //
  816. delete pNewEntry;
  817. return;
  818. }
  819. // prefix believes that this allocation (or construction) may throw
  820. // an exception, and if an exception is thrown, pNewEntry is
  821. // leaked. After a lot of digging, it's possible that a
  822. // CMemoryException instance may be thrown by one of the base
  823. // classes of one the members of CBaseCookieBlock, which is a base
  824. // clase of Cookie.
  825. // NTRAID#NTBUG9-294879-2001/01/26-sburns
  826. try
  827. {
  828. pNewCookie = new Cookie( SCHMMGMT_CLASS,
  829. pParentCookie->QueryNonNULLMachineName() );
  830. }
  831. catch (...)
  832. {
  833. delete pNewEntry;
  834. return;
  835. }
  836. if ( !pNewCookie ) {
  837. //
  838. // If we can't allocate a cookie, do nothing.
  839. //
  840. delete pNewEntry;
  841. return;
  842. }
  843. pNewCookie->pParentCookie = pParentCookie;
  844. pNewCookie->strSchemaObject = pNewObject->commonName;
  845. pParentCookie->m_listScopeCookieBlocks.AddHead(
  846. (CBaseCookieBlock*)pNewCookie );
  847. pNewEntry->pCookie = pNewCookie;
  848. ::ZeroMemory( &ScopeItem, sizeof(ScopeItem) );
  849. ScopeItem.displayname = MMC_CALLBACK;
  850. ScopeItem.nState = 0;
  851. ScopeItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pNewCookie);
  852. ScopeItem.nImage = pScopeControl->QueryImage( *pNewCookie, FALSE );
  853. ScopeItem.nOpenImage = pScopeControl->QueryImage( *pNewCookie, TRUE );
  854. }
  855. //
  856. // Should this be the new head of the list?
  857. //
  858. compare = pNewObject->ldapDisplayName.CompareNoCase(
  859. pHead->pCookie->strSchemaObject );
  860. if ( compare < 0 ) {
  861. if ( pNewObject->schemaObjectType == SCHMMGMT_CLASS ) {
  862. //
  863. // Insert this into the scope pane.
  864. //
  865. ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_STATE |
  866. SDI_PARAM | SDI_NEXT | SDI_CHILDREN;
  867. ScopeItem.cChildren = 0;
  868. ScopeItem.relativeID = pHead->hScopeItem;
  869. hr = pScopeControl->m_pConsoleNameSpace->InsertItem( &ScopeItem );
  870. pNewEntry->hScopeItem = ScopeItem.ID;
  871. pNewEntry->pCookie->m_hScopeItem = ScopeItem.ID;
  872. } else {
  873. hr = S_OK;
  874. }
  875. if ( SUCCEEDED(hr) ) {
  876. pNewEntry->pNext = pHead;
  877. pNewEntry->pBack = pHead->pBack;
  878. pHead->pBack->pNext = pNewEntry;
  879. pHead->pBack = pNewEntry;
  880. pHead = pNewEntry;
  881. } else {
  882. delete pNewEntry;
  883. delete pNewCookie;
  884. }
  885. return;
  886. }
  887. //
  888. // Determine the sorted insertion point. The sorted list is circular.
  889. //
  890. pCurrent = pHead;
  891. while ( pCurrent->pNext != pHead ) {
  892. compare = pNewObject->ldapDisplayName.CompareNoCase(
  893. pCurrent->pNext->pCookie->strSchemaObject );
  894. if ( compare < 0 ) {
  895. break;
  896. }
  897. pCurrent = pCurrent->pNext;
  898. }
  899. //
  900. // We want to insert the new object after pCurrent.
  901. //
  902. if ( pNewObject->schemaObjectType == SCHMMGMT_CLASS ) {
  903. ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_STATE |
  904. SDI_PARAM | SDI_PREVIOUS | SDI_CHILDREN;
  905. ScopeItem.cChildren = 0;
  906. ScopeItem.relativeID = pCurrent->hScopeItem;
  907. hr = pScopeControl->m_pConsoleNameSpace->InsertItem( &ScopeItem );
  908. pNewEntry->hScopeItem = ScopeItem.ID;
  909. pNewEntry->pCookie->m_hScopeItem = ScopeItem.ID;
  910. } else {
  911. hr = S_OK;
  912. }
  913. if ( SUCCEEDED( hr )) {
  914. pNewEntry->pNext = pCurrent->pNext;
  915. pNewEntry->pBack = pCurrent;
  916. pCurrent->pNext->pBack = pNewEntry;
  917. pCurrent->pNext = pNewEntry;
  918. } else {
  919. delete pNewEntry;
  920. delete pNewCookie;
  921. }
  922. return;
  923. }
  924. bool
  925. CCookieList::DeleteCookie(Cookie* pCookie)
  926. {
  927. bool result = false;
  928. if (!pHead)
  929. {
  930. return result;
  931. }
  932. // walk the links and stop when the scope item matches.
  933. // Since the list is circular,
  934. // we use pHead as the sentinal value instead of null.
  935. CCookieListEntry* pCurrent = pHead;
  936. do
  937. {
  938. ASSERT(pCurrent);
  939. if (pCurrent->pCookie == pCookie)
  940. {
  941. // Remove the node from the list
  942. pCurrent->pBack->pNext = pCurrent->pNext;
  943. pCurrent->pNext->pBack = pCurrent->pBack;
  944. if (pCurrent == pHead)
  945. {
  946. pHead = pCurrent->pNext;
  947. }
  948. result = true;
  949. delete pCurrent;
  950. break;
  951. }
  952. pCurrent = pCurrent->pNext;
  953. } while (pCurrent != pHead);
  954. return result;
  955. }
  956. void
  957. CCookieList::DeleteAll()
  958. {
  959. if (!pHead)
  960. {
  961. return;
  962. }
  963. CCookieListEntry* pCurrent = pHead;
  964. do
  965. {
  966. CCookieListEntry* next = pCurrent->pNext;
  967. delete pCurrent;
  968. pCurrent = next;
  969. }
  970. while (pCurrent != pHead);
  971. pHead = 0;
  972. }
  973. CString
  974. GetHelpFilename()
  975. {
  976. TCHAR buf[MAX_PATH + 1];
  977. UINT result = ::GetSystemWindowsDirectory(buf, MAX_PATH);
  978. ASSERT(result != 0 && result <= MAX_PATH);
  979. CString f(buf);
  980. f += TEXT("\\help\\schmmgmt.hlp");
  981. return f;
  982. }
  983. BOOL
  984. ShowHelp( HWND hParent, WPARAM wParam, LPARAM lParam, const DWORD ids[], BOOL fContextMenuHelp )
  985. {
  986. HWND hWndMain = NULL;
  987. UINT uCommand = 0;
  988. if( !fContextMenuHelp )
  989. {
  990. // The user has clicked ? and the control, or just F1 (if enabled)
  991. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  992. if (pHelpInfo && pHelpInfo->iContextType == HELPINFO_WINDOW)
  993. {
  994. hWndMain = (HWND) pHelpInfo->hItemHandle;
  995. uCommand = HELP_WM_HELP;
  996. }
  997. }
  998. else
  999. {
  1000. hWndMain = (HWND) wParam;
  1001. uCommand = HELP_CONTEXTMENU;
  1002. // Optimization for non-static enabled windows.
  1003. // This way users don't have to do an extra menu click
  1004. // $$ don't know why this call returns NULL all the time
  1005. // HWND hWnd = ChildWindowFromPoint( hParent, CPoint(lParam) );
  1006. // if( hWnd )
  1007. // hWndMain = hWnd;
  1008. if( -1 != GET_X_LPARAM(lParam) &&
  1009. -1 != GET_Y_LPARAM(lParam) &&
  1010. hParent &&
  1011. hWndMain != hParent )
  1012. {
  1013. uCommand = HELP_WM_HELP;
  1014. }
  1015. }
  1016. if( hWndMain && uCommand )
  1017. {
  1018. // Display context help for a control
  1019. ::WinHelp( hWndMain,
  1020. GetHelpFilename(),
  1021. uCommand,
  1022. (DWORD_PTR) ids );
  1023. }
  1024. return TRUE;
  1025. }
  1026. #if 0
  1027. VOID
  1028. DebugTrace(
  1029. LPWSTR Format,
  1030. ...
  1031. ) {
  1032. WCHAR DbgString[1024];
  1033. va_list arglist;
  1034. int Length;
  1035. //
  1036. // Format the output into a buffer and then print it.
  1037. //
  1038. va_start(arglist, Format);
  1039. Length = wvsprintf( DbgString, Format, arglist );
  1040. va_end(arglist);
  1041. ASSERT( Length <= 1024 );
  1042. ASSERT( Length != 0 );
  1043. OutputDebugString( DbgString );
  1044. return;
  1045. }
  1046. #else
  1047. VOID
  1048. DebugTrace(
  1049. LPWSTR,
  1050. ...
  1051. ) {
  1052. ;
  1053. }
  1054. #endif
  1055. // Attempt to locate a message in a given module. Return the message string
  1056. // if found, the empty string if not.
  1057. //
  1058. // flags - FormatMessage flags to use
  1059. //
  1060. // module - module handle of message dll to look in, or 0 to use the system
  1061. // message table.
  1062. //
  1063. // code - message code to look for
  1064. CString
  1065. getMessageHelper(DWORD flags, HMODULE module, HRESULT code)
  1066. {
  1067. ASSERT(code);
  1068. ASSERT(flags & FORMAT_MESSAGE_ALLOCATE_BUFFER);
  1069. CString message;
  1070. TCHAR* sys_message = 0;
  1071. DWORD result =
  1072. ::FormatMessage(
  1073. flags,
  1074. module,
  1075. static_cast<DWORD>(code),
  1076. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1077. reinterpret_cast<LPTSTR>(&sys_message),
  1078. 0,
  1079. 0);
  1080. if (result)
  1081. {
  1082. ASSERT(sys_message);
  1083. if (sys_message)
  1084. {
  1085. message = sys_message;
  1086. ::LocalFree(sys_message);
  1087. }
  1088. }
  1089. return message;
  1090. }
  1091. #define MAX_ERROR_BUF 2048
  1092. HRESULT
  1093. GetLastADsError( HRESULT hr, CString& refErrorMsg, CString& refName )
  1094. {
  1095. ASSERT(FAILED(hr));
  1096. refErrorMsg.Empty();
  1097. refName.Empty();
  1098. if (!FAILED(hr))
  1099. {
  1100. return hr;
  1101. }
  1102. if( FACILITY_WIN32 == HRESULT_FACILITY(hr) )
  1103. {
  1104. DWORD dwLastError = 0;
  1105. WCHAR szErrorBuf[ MAX_ERROR_BUF + 1 ];
  1106. WCHAR szNameBuf[ MAX_ERROR_BUF + 1 ];
  1107. //Get extended error value.
  1108. HRESULT hr_return = ADsGetLastError( &dwLastError,
  1109. szErrorBuf,
  1110. MAX_ERROR_BUF,
  1111. szNameBuf,
  1112. MAX_ERROR_BUF );
  1113. ASSERT( SUCCEEDED(hr_return) );
  1114. if( SUCCEEDED(hr_return) && dwLastError )
  1115. {
  1116. refErrorMsg = szErrorBuf;
  1117. refName = szNameBuf;
  1118. return HRESULT_FROM_WIN32( dwLastError );
  1119. }
  1120. }
  1121. return hr;
  1122. }
  1123. // Attempts to locate message strings for various facility codes in the
  1124. // HRESULT. If fTryADSIExtError is true, check ADsGetLastError() first
  1125. CString
  1126. GetErrorMessage( HRESULT hr, BOOL fTryADSIExtError /* = FALSE */ )
  1127. {
  1128. ASSERT(FAILED(hr));
  1129. if (!FAILED(hr))
  1130. {
  1131. // no messages for success!
  1132. return CString();
  1133. }
  1134. CString strExtMsg;
  1135. if( fTryADSIExtError &&
  1136. FACILITY_WIN32 == HRESULT_FACILITY(hr) )
  1137. {
  1138. DWORD dwLastError = 0;
  1139. WCHAR szErrorBuf[ MAX_ERROR_BUF + 1 ];
  1140. WCHAR szNameBuf[ MAX_ERROR_BUF + 1 ];
  1141. //Get extended error value.
  1142. HRESULT hr_return = ADsGetLastError( &dwLastError,
  1143. szErrorBuf,
  1144. MAX_ERROR_BUF,
  1145. szNameBuf,
  1146. MAX_ERROR_BUF );
  1147. ASSERT( SUCCEEDED(hr_return) );
  1148. if( SUCCEEDED(hr_return) && dwLastError )
  1149. {
  1150. hr = HRESULT_FROM_WIN32( dwLastError );
  1151. strExtMsg = szErrorBuf;
  1152. }
  1153. }
  1154. int code = HRESULT_CODE(hr);
  1155. CString message;
  1156. // default is the system error message table
  1157. HMODULE module = 0;
  1158. DWORD flags =
  1159. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1160. | FORMAT_MESSAGE_IGNORE_INSERTS
  1161. | FORMAT_MESSAGE_FROM_SYSTEM;
  1162. int facility = HRESULT_FACILITY(hr);
  1163. switch (facility)
  1164. {
  1165. case FACILITY_WIN32: // 0x7
  1166. {
  1167. // included here:
  1168. // lanman error codes (in it's own dll)
  1169. // dns
  1170. // winsock
  1171. static HMODULE lm_err_res_dll = 0;
  1172. if (code >= NERR_BASE && code <= MAX_NERR)
  1173. {
  1174. // use the net error message resource dll
  1175. if (lm_err_res_dll == 0)
  1176. {
  1177. lm_err_res_dll =
  1178. ::LoadLibraryEx(
  1179. L"netmsg.dll",
  1180. 0,
  1181. LOAD_LIBRARY_AS_DATAFILE);
  1182. }
  1183. module = lm_err_res_dll;
  1184. flags |= FORMAT_MESSAGE_FROM_HMODULE;
  1185. }
  1186. break;
  1187. }
  1188. case 0x0:
  1189. {
  1190. if (code >= 0x5000 && code <= 0x50FF)
  1191. {
  1192. // It's an ADSI error. They put the facility code (5) in the
  1193. // wrong place!
  1194. static HMODULE adsi_err_res_dll = 0;
  1195. // use the net error message resource dll
  1196. if (adsi_err_res_dll == 0)
  1197. {
  1198. adsi_err_res_dll =
  1199. ::LoadLibraryEx(
  1200. L"activeds.dll",
  1201. 0,
  1202. LOAD_LIBRARY_AS_DATAFILE);
  1203. }
  1204. module = adsi_err_res_dll;
  1205. flags |= FORMAT_MESSAGE_FROM_HMODULE;
  1206. // the message dll expects the entire error code
  1207. code = hr;
  1208. }
  1209. break;
  1210. }
  1211. default:
  1212. {
  1213. // do nothing
  1214. break;
  1215. }
  1216. }
  1217. message = getMessageHelper(flags, module, code);
  1218. #ifdef SHOW_EXT_LDAP_MSG
  1219. if( !strExtMsg.IsEmpty() )
  1220. message += L"\n" + strExtMsg;
  1221. #endif //SHOW_EXT_LDAP_MSG
  1222. if (message.IsEmpty())
  1223. {
  1224. message.LoadString(IDS_UNKNOWN_ERROR_MESSAGE);
  1225. }
  1226. return message;
  1227. }
  1228. //
  1229. // Get range from edit controls, Verify the range, attempt to correct, make sure lower <= upper.
  1230. //
  1231. // an exception will be thrown in case of an error.
  1232. //
  1233. void DDXV_VerifyAttribRange( CDataExchange *pDX, BOOL fIsSigned,
  1234. UINT idcLower, CString & strLower,
  1235. UINT idcUpper, CString & strUpper )
  1236. {
  1237. INT64 llLower = 0;
  1238. INT64 llUpper = 0;
  1239. ASSERT( pDX );
  1240. ASSERT( pDX->m_pDlgWnd );
  1241. // Update the values.
  1242. llLower = DDXV_SigUnsigINT32Value( pDX, fIsSigned, idcLower, strLower );
  1243. llUpper = DDXV_SigUnsigINT32Value( pDX, fIsSigned, idcUpper, strUpper );
  1244. #ifdef ENABLE_NEGATIVE_INT
  1245. // verify that lower <= upper -- only if supporting ENABLE_NEGATIVE_INT
  1246. if ( pDX->m_bSaveAndValidate && !strLower.IsEmpty() && !strUpper.IsEmpty() )
  1247. {
  1248. if( llLower > llUpper )
  1249. {
  1250. DoErrMsgBox( pDX->m_pDlgWnd->m_hWnd, TRUE, IDS_ERR_EDIT_MINMAX );
  1251. pDX->Fail(); // we are still at the second edit control.
  1252. }
  1253. }
  1254. #endif //ENABLE_NEGATIVE_INT
  1255. }
  1256. //
  1257. // Get string from an edit control, verify it attempting to correct
  1258. //
  1259. // an exception will be thrown in case of an error.
  1260. //
  1261. // Returns corrected value
  1262. //
  1263. INT64 DDXV_SigUnsigINT32Value( CDataExchange *pDX, BOOL fIsSigned,
  1264. UINT idc, CString & str )
  1265. {
  1266. INT64 llVal = 0;
  1267. HRESULT hr = S_OK;
  1268. ASSERT( pDX );
  1269. ASSERT( pDX->m_pDlgWnd );
  1270. // Get/Put the string
  1271. DDX_Text( pDX, idc, str );
  1272. if ( pDX->m_bSaveAndValidate )
  1273. {
  1274. if( !str.IsEmpty() )
  1275. {
  1276. hr = GetSafeINT32FromString( pDX->m_pDlgWnd, llVal, str,
  1277. fIsSigned, GETSAFEINT_ALLOW_CANCEL );
  1278. if( FAILED(hr) )
  1279. {
  1280. pDX->Fail();
  1281. }
  1282. else if( S_VALUE_MODIFIED == hr )
  1283. {
  1284. // update the string in case of some conversion things ('010' --> '10')
  1285. // or if the value was changed
  1286. pDX->m_pDlgWnd->SetDlgItemText( idc, str );
  1287. }
  1288. }
  1289. }
  1290. return llVal;
  1291. }
  1292. //
  1293. // Converts a string to a DWORD, asks to correct to be within the range.
  1294. // returns HRESULT:
  1295. // S_OK llDst is the value from string
  1296. // S_VALUE_MODIFIED llDst is the truncated value, strSrc is updated
  1297. // E_ABORT llDst is unchanged; E_ABORT may be returned only if fAllowCancel is TRUE
  1298. //
  1299. HRESULT GetSafeSignedDWORDFromString( CWnd * pwndParent, DWORD & dwDst, CString & strSrc,
  1300. BOOL fIsSigned, BOOL fAllowCancel /* =FALSE */)
  1301. {
  1302. INT64 llDst = 0;
  1303. HRESULT hr = GetSafeINT32FromString( pwndParent, llDst, strSrc, fIsSigned, fAllowCancel );
  1304. if( SUCCEEDED( hr ) )
  1305. dwDst = (DWORD) llDst;
  1306. return hr;
  1307. }
  1308. //
  1309. // *** internal use ***
  1310. // Converts a string to a INT64, asks to correct to be within the range.
  1311. // returns HRESULT:
  1312. // S_OK llDst is the value from string
  1313. // S_VALUE_MODIFIED llDst is the truncated value, strSrc is updated
  1314. // E_ABORT llDst is the truncated value
  1315. // E_ABORT only happens if fAllowCancel is TRUE
  1316. //
  1317. HRESULT GetSafeINT32FromString( CWnd * pwndParent, INT64 & llDst, CString & strSrc,
  1318. BOOL fIsSigned, BOOL fAllowCancel)
  1319. {
  1320. CThemeContextActivator activator;
  1321. HRESULT hr = S_OK;
  1322. UINT nMessageBoxType = 0;
  1323. CString szMsg;
  1324. CString szSugestedNumber;
  1325. BOOL fIsValidNumber = TRUE;
  1326. BOOL fIsValidString = TRUE;
  1327. ASSERT( pwndParent );
  1328. // the string must be limited in length & not empty
  1329. ASSERT( !strSrc.IsEmpty() );
  1330. ASSERT( strSrc.GetLength() <= cchMinMaxRange );
  1331. fIsValidString = IsValidNumberString( strSrc );
  1332. llDst = _wtoi64( (LPCWSTR) strSrc );
  1333. fIsValidNumber = IsValidNumber32( llDst, fIsSigned );
  1334. szSugestedNumber.Format( fIsSigned ? g_INT32_FORMAT : g_UINT32_FORMAT, (DWORD) llDst );
  1335. if( !fIsValidString || !fIsValidNumber )
  1336. {
  1337. szMsg.FormatMessage( !fIsValidString ? IDS_ERR_NUM_IS_ILLIGAL : IDS_ERR_INT_OVERFLOW,
  1338. (LPCWSTR) strSrc, (LPCWSTR) szSugestedNumber );
  1339. // make sure the user wants to do it
  1340. nMessageBoxType = (fAllowCancel ? MB_OKCANCEL : MB_OK) | MB_ICONEXCLAMATION ;
  1341. if( IDOK == pwndParent->MessageBox( szMsg, g_MsgBoxErr, nMessageBoxType ) )
  1342. {
  1343. strSrc = szSugestedNumber;
  1344. hr = S_VALUE_MODIFIED;
  1345. }
  1346. else
  1347. {
  1348. hr = E_ABORT;
  1349. }
  1350. }
  1351. else if( strSrc != szSugestedNumber )
  1352. {
  1353. // fixing number formating
  1354. strSrc = szSugestedNumber;
  1355. hr = S_VALUE_MODIFIED;
  1356. }
  1357. return hr;
  1358. }
  1359. //
  1360. // Verify & correct Min/Max for a signed/unsigned INT64 value
  1361. //
  1362. BOOL IsValidNumber32( INT64 & llVal, BOOL fIsSigned )
  1363. {
  1364. #ifdef ENABLE_NEGATIVE_INT
  1365. const INT64 llMinVal = fIsSigned ? (INT64) _I32_MIN : (INT64) 0 ;
  1366. const INT64 llMaxVal = fIsSigned ? (INT64) _I32_MAX : (INT64) _UI32_MAX ;
  1367. #else
  1368. // if there is no negative numbers support, always use unsigned numbers
  1369. const INT64 llMinVal = (INT64) 0;
  1370. const INT64 llMaxVal = (INT64) _UI32_MAX;
  1371. #endif
  1372. BOOL fIsValid = FALSE;
  1373. // if larger than 32bit number (signed/unsigned), truncate...
  1374. if( llVal < llMinVal )
  1375. {
  1376. llVal = llMinVal;
  1377. }
  1378. else if( llVal > llMaxVal )
  1379. {
  1380. llVal = llMaxVal;
  1381. }
  1382. else
  1383. {
  1384. fIsValid = TRUE;
  1385. }
  1386. return fIsValid;
  1387. }
  1388. //
  1389. // Search number string for illigal characters.
  1390. //
  1391. BOOL IsValidNumberString( CString & str )
  1392. {
  1393. int i = 0;
  1394. #ifdef ENABLE_NEGATIVE_INT
  1395. if( str.GetLength() > 0 && // allow negative sign in front of the number
  1396. g_chNegativeSign == str[ i ] )
  1397. {
  1398. i++; // skip first character
  1399. }
  1400. #endif //ENABLE_NEGATIVE_INT
  1401. for( ; i < str.GetLength(); i++ )
  1402. {
  1403. if( !IsCharNumeric( str[i] ) )
  1404. return FALSE;
  1405. }
  1406. return TRUE;
  1407. }
  1408. /////////////////////////////////////////////////////////////////////////////
  1409. // ParsedEdit
  1410. BEGIN_MESSAGE_MAP(CParsedEdit, CEdit)
  1411. //{{AFX_MSG_MAP(CParsedEdit)
  1412. ON_WM_CHAR()
  1413. //}}AFX_MSG_MAP
  1414. END_MESSAGE_MAP()
  1415. /////////////////////////////////////////////////////////////////////////////
  1416. // Initialize subclassing
  1417. BOOL CParsedEdit::SubclassEdit( UINT nID,
  1418. CWnd* pParent,
  1419. int cchMaxTextSize ) // 0 == unlimited
  1420. {
  1421. ASSERT( IsInitialized() );
  1422. ASSERT( nID );
  1423. ASSERT( pParent );
  1424. ASSERT( pParent->GetDlgItem(nID) );
  1425. ASSERT( cchMaxTextSize >= 0 );
  1426. ( static_cast<CEdit *>( pParent->GetDlgItem(nID) ) ) -> LimitText( cchMaxTextSize ) ;
  1427. if( EDIT_TYPE_GENERIC == GetEditType() )
  1428. {
  1429. return TRUE; // no need to subclass - everything is allowed.
  1430. }
  1431. else
  1432. {
  1433. return SubclassDlgItem(nID, pParent);
  1434. }
  1435. }
  1436. /////////////////////////////////////////////////////////////////////////////
  1437. // Input character filter
  1438. void CParsedEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1439. {
  1440. ASSERT( IsInitialized() ); // initialized?
  1441. BOOL fIsSpecialChar = ( nChar < 0x20 );
  1442. BOOL fAllowChar = FALSE;
  1443. if( fIsSpecialChar )
  1444. {
  1445. fAllowChar = TRUE; // always allow control chars
  1446. }
  1447. else
  1448. {
  1449. // is this a digit?
  1450. BOOL fIsDigit = IsCharNumeric( (TCHAR)nChar );
  1451. switch( GetEditType() )
  1452. {
  1453. default:
  1454. ASSERT( FALSE );
  1455. break;
  1456. case EDIT_TYPE_GENERIC: // everything is allowed
  1457. fAllowChar = TRUE;
  1458. break;
  1459. case EDIT_TYPE_INT32:
  1460. case EDIT_TYPE_UINT32:
  1461. {
  1462. #ifdef ENABLE_NEGATIVE_INT
  1463. const BOOL fAllowNegativeNumbers = TRUE;
  1464. #else
  1465. const BOOL fAllowNegativeNumbers = FALSE;
  1466. #endif
  1467. DWORD dwSel = GetSel();
  1468. // is the caret in the begining of the box
  1469. BOOL fLineFront = ! LOWORD( dwSel );
  1470. // is the first character selected? (thus, typing anything will overide it)
  1471. BOOL fIsSelFirstChar = fLineFront && HIWORD( dwSel );
  1472. BOOL fIsNegSign = ( (TCHAR)nChar == g_chNegativeSign );
  1473. WCHAR szBuf[ 2 ] = {0}; // we only need the first character to check for '-'
  1474. // if the first character is selected, no matter what we type it will be overwritten
  1475. // an empty value is a positive value.
  1476. // rellies on left to right execution.
  1477. BOOL fIsAlreadyNeg = ( !fIsSelFirstChar &&
  1478. GetWindowText( szBuf, 2 ) &&
  1479. g_chNegativeSign == szBuf[0] );
  1480. ASSERT( !fIsDigit || !fIsNegSign ); // cannot be both!
  1481. if (
  1482. ( fIsDigit && // allow numeric if ...
  1483. ( !fAllowNegativeNumbers || // ignore error checking if false
  1484. !fLineFront || // not first position
  1485. (fLineFront && !fIsAlreadyNeg)) // first pos & no '-' sign
  1486. )
  1487. ||
  1488. ( fIsNegSign && // allow '-' if
  1489. fAllowNegativeNumbers && // negatives are allowed
  1490. FIsSigned() && // signed numbers are allowed
  1491. !fIsAlreadyNeg && // the number was positive
  1492. fLineFront // entering as the first character
  1493. )
  1494. )
  1495. {
  1496. fAllowChar = TRUE;
  1497. }
  1498. }
  1499. break;
  1500. case EDIT_TYPE_OID: // do a light checking -- allow digits & periods
  1501. {
  1502. if( fIsDigit ||
  1503. g_chPeriod == (TCHAR)nChar )
  1504. {
  1505. fAllowChar = TRUE;
  1506. }
  1507. }
  1508. break;
  1509. }
  1510. }
  1511. if( fAllowChar )
  1512. {
  1513. CEdit::OnChar(nChar, nRepCnt, nFlags); // permitted
  1514. }
  1515. else
  1516. { // not permitted
  1517. MessageBeep((UINT)-1); // Standard beep
  1518. }
  1519. }
  1520. /////////////////////////////////////////////////////////////////////////////
  1521. //
  1522. // Search a list of PCTSTR for a strValue, returns TRUE if found
  1523. // rgszList[] last element must be NULL
  1524. //
  1525. // puIndex - optional pointer, will be set to the position of the value if found.
  1526. //
  1527. BOOL
  1528. IsInList( PCTSTR rgszList[], const CString & strValue, UINT * puIndex /* = NULL */ )
  1529. {
  1530. UINT uIndex = 0;
  1531. while( rgszList[ uIndex ] )
  1532. {
  1533. if( !strValue.CompareNoCase( rgszList[uIndex] ) )
  1534. {
  1535. if( puIndex )
  1536. *puIndex = uIndex;
  1537. return TRUE;
  1538. }
  1539. else
  1540. uIndex++;
  1541. }
  1542. return FALSE;
  1543. }
  1544. #define ADS_SYSTEMFLAG_SCHEMA_CONSTRUCTED 0x04
  1545. #define ADS_SYSTEMFLAG_SCHEMA_BASE_OBJECT 0x10
  1546. //
  1547. // Determine if the object pointed to by pIADsObject is a constructed object.
  1548. //
  1549. HRESULT
  1550. IsConstructedObject( IADs *pIADsObject, BOOL & fIsConstructed )
  1551. {
  1552. LONG fSysAttribs = 0;
  1553. HRESULT hr = GetSystemAttributes( pIADsObject, fSysAttribs );
  1554. if( SUCCEEDED(hr) )
  1555. fIsConstructed = ADS_SYSTEMFLAG_SCHEMA_CONSTRUCTED & fSysAttribs;
  1556. return hr;
  1557. }
  1558. //
  1559. // Determine if the object pointed to by pIADsObject is category 1 object.
  1560. //
  1561. HRESULT
  1562. IsCategory1Object( IADs *pIADsObject, BOOL & fIsCategory1 )
  1563. {
  1564. LONG fSysAttribs = 0;
  1565. HRESULT hr = GetSystemAttributes( pIADsObject, fSysAttribs );
  1566. if( SUCCEEDED(hr) )
  1567. fIsCategory1 = ADS_SYSTEMFLAG_SCHEMA_BASE_OBJECT & fSysAttribs;
  1568. return hr;
  1569. }
  1570. //
  1571. // Read object's System Attribute
  1572. //
  1573. HRESULT
  1574. GetSystemAttributes( IADs *pIADsObject, LONG &fSysAttribs )
  1575. {
  1576. HRESULT hr = E_FAIL;
  1577. VARIANT AdsResult;
  1578. if( !pIADsObject )
  1579. ASSERT( FALSE );
  1580. else
  1581. {
  1582. VariantInit( &AdsResult );
  1583. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  1584. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_systemFlags), &AdsResult );
  1585. if ( SUCCEEDED( hr ) )
  1586. {
  1587. ASSERT(AdsResult.vt == VT_I4);
  1588. fSysAttribs = V_I4(&AdsResult);
  1589. }
  1590. else if( E_ADS_PROPERTY_NOT_FOUND == hr )
  1591. {
  1592. fSysAttribs = 0;
  1593. hr = S_OK;
  1594. }
  1595. VariantClear( &AdsResult );
  1596. }
  1597. return hr;
  1598. }
  1599. HRESULT
  1600. DissableReadOnlyAttributes( CWnd * pwnd, IADs *pIADsObject, const CDialogControlsInfo * pCtrls, UINT cCtrls )
  1601. {
  1602. ASSERT( pwnd );
  1603. ASSERT( pIADsObject );
  1604. ASSERT( pCtrls );
  1605. ASSERT( cCtrls );
  1606. HRESULT hr = S_OK;
  1607. CStringList strlist;
  1608. do
  1609. {
  1610. // extract the list of allowed attributes
  1611. hr = GetStringListElement( pIADsObject, &g_allowedAttributesEffective, strlist );
  1612. BREAK_ON_FAILED_HRESULT(hr);
  1613. for( UINT ind = 0; ind < cCtrls; ind++ )
  1614. {
  1615. BOOL fFound = FALSE;
  1616. // search for needed attributes
  1617. for( POSITION pos = strlist.GetHeadPosition(); !fFound && pos != NULL; )
  1618. {
  1619. CString * pstr = &strlist.GetNext( pos );
  1620. if( !pstr->CompareNoCase( pCtrls[ind].m_pszAttributeName ) )
  1621. {
  1622. fFound = TRUE;
  1623. }
  1624. }
  1625. if( !fFound )
  1626. {
  1627. ASSERT( pwnd->GetDlgItem( pCtrls[ind].m_nID ) );
  1628. if( pCtrls[ind].m_fIsEditBox )
  1629. reinterpret_cast<CEdit *>( pwnd->GetDlgItem(pCtrls[ind].m_nID) )->SetReadOnly();
  1630. else
  1631. pwnd->GetDlgItem(pCtrls[ind].m_nID)->EnableWindow( FALSE );
  1632. }
  1633. }
  1634. } while( FALSE );
  1635. return hr;
  1636. }
  1637. HRESULT GetStringListElement( IADs *pIADsObject, LPWSTR *lppPathNames, CStringList &strlist )
  1638. {
  1639. ASSERT( pIADsObject );
  1640. ASSERT( lppPathNames );
  1641. ASSERT( *lppPathNames );
  1642. HRESULT hr = S_OK;
  1643. VARIANT varAttributes;
  1644. VariantInit( &varAttributes );
  1645. strlist.RemoveAll();
  1646. do
  1647. {
  1648. // build an array of one element
  1649. hr = ADsBuildVarArrayStr( lppPathNames, 1, &varAttributes );
  1650. ASSERT_BREAK_ON_FAILED_HRESULT(hr);
  1651. hr = pIADsObject->GetInfoEx( varAttributes, 0 );
  1652. BREAK_ON_FAILED_HRESULT(hr);
  1653. hr = VariantClear( &varAttributes );
  1654. ASSERT_BREAK_ON_FAILED_HRESULT(hr);
  1655. // Get all allowed attributes
  1656. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  1657. hr = pIADsObject->GetEx( CComBSTR(*lppPathNames), &varAttributes );
  1658. BREAK_ON_FAILED_HRESULT(hr);
  1659. // Convert result to a string list
  1660. hr = VariantToStringList( varAttributes, strlist );
  1661. ASSERT( SUCCEEDED(hr) || E_ADS_PROPERTY_NOT_FOUND == hr );
  1662. BREAK_ON_FAILED_HRESULT(hr);
  1663. } while( FALSE );
  1664. VariantClear( &varAttributes );
  1665. return hr;
  1666. }
  1667. // FUTURE-2002-03/94/2002-dantra-Needs comments
  1668. // NTRAID#NTBUG9-567089-2002/03/06-dantra-OIDHasValidFormat should use the safe string functions.
  1669. bool OIDHasValidFormat (PCWSTR pszOidValue, int& rErrorTypeStrID)
  1670. {
  1671. rErrorTypeStrID = 0;
  1672. bool bFormatIsValid = false;
  1673. // NOTE: Safe Use - query length including NULL terminator
  1674. int nLen = WideCharToMultiByte(
  1675. CP_ACP, // code page
  1676. 0, // performance and mapping flags
  1677. pszOidValue, // wide-character string
  1678. (int) wcslen (pszOidValue), // number of chars in string
  1679. 0, // buffer for new string
  1680. 0, // size of buffer
  1681. 0, // default for unmappable chars
  1682. 0); // set when default char used
  1683. if ( nLen > 0 )
  1684. {
  1685. nLen++; // account for Null terminator
  1686. PSTR pszAnsiBuf = new CHAR[nLen];
  1687. if ( pszAnsiBuf )
  1688. {
  1689. // NOTE: Safe Use
  1690. ZeroMemory (pszAnsiBuf, nLen*sizeof(CHAR));
  1691. // NOTE: Safe Use - nLen obtained from first call to WideCharToMultiByte
  1692. nLen = WideCharToMultiByte(
  1693. CP_ACP, // code page
  1694. 0, // performance and mapping flags
  1695. pszOidValue, // wide-character string
  1696. (int) wcslen (pszOidValue), // number of chars in string
  1697. pszAnsiBuf, // buffer for new string
  1698. nLen, // size of buffer
  1699. 0, // default for unmappable chars
  1700. 0); // set when default char used
  1701. if ( nLen )
  1702. {
  1703. // According to PhilH:
  1704. // The first number is limited to
  1705. // 0,1 or 2. The second number is
  1706. // limited to 0 - 39 when the first
  1707. // number is 0 or 1. Otherwise, any
  1708. // number.
  1709. // Also, according to X.208, there
  1710. // must be at least 2 numbers.
  1711. bFormatIsValid = true;
  1712. size_t cbAnsiBufLen = strlen (pszAnsiBuf);
  1713. // check for only digits and "."
  1714. size_t nIdx = strspn (pszAnsiBuf, "0123456789.\0");
  1715. if ( nIdx > 0 && nIdx < cbAnsiBufLen )
  1716. {
  1717. bFormatIsValid = false;
  1718. rErrorTypeStrID = IDS_OID_CONTAINS_NON_DIGITS;
  1719. }
  1720. // check for consecutive "."s - string not valid if present
  1721. if ( bFormatIsValid && strstr (pszAnsiBuf, "..") )
  1722. {
  1723. bFormatIsValid = false;
  1724. rErrorTypeStrID = IDS_OID_CONTAINS_CONSECUTIVE_DOTS;
  1725. }
  1726. // must begin with "0." or "1." or "2."
  1727. bool bFirstNumberIs0 = false;
  1728. bool bFirstNumberIs1 = false;
  1729. bool bFirstNumberIs2 = false;
  1730. if ( bFormatIsValid )
  1731. {
  1732. if ( !strncmp (pszAnsiBuf, "0.", 2) )
  1733. bFirstNumberIs0 = true;
  1734. else if ( !strncmp (pszAnsiBuf, "1.", 2) )
  1735. bFirstNumberIs1 = true;
  1736. else if ( !strncmp (pszAnsiBuf, "2.", 2) )
  1737. bFirstNumberIs2 = true;
  1738. if ( !bFirstNumberIs0 && !bFirstNumberIs1 && !bFirstNumberIs2 )
  1739. {
  1740. bFormatIsValid = false;
  1741. rErrorTypeStrID = IDS_OID_MUST_START_WITH_0_1_2;
  1742. }
  1743. }
  1744. if ( bFormatIsValid && ( bFirstNumberIs0 || bFirstNumberIs1 ) )
  1745. {
  1746. PSTR pszBuf = pszAnsiBuf;
  1747. pszBuf += 2;
  1748. // there must be a number after the dot
  1749. if ( strlen (pszBuf) )
  1750. {
  1751. // truncate the string at the next dot, if any
  1752. PSTR pszDot = strstr (pszBuf, ".");
  1753. if ( pszDot )
  1754. pszDot[0] = 0;
  1755. // convert the string to a number and check for range 0-39
  1756. int nValue = atoi (pszBuf);
  1757. if ( nValue < 0 || nValue > 39 )
  1758. {
  1759. bFormatIsValid = false;
  1760. rErrorTypeStrID = IDS_OID_0_1_MUST_BE_0_TO_39;
  1761. }
  1762. }
  1763. else
  1764. {
  1765. bFormatIsValid = false;
  1766. rErrorTypeStrID = IDS_OID_MUST_HAVE_TWO_NUMBERS;
  1767. }
  1768. }
  1769. // ensure no trailing "."
  1770. if ( bFormatIsValid )
  1771. {
  1772. if ( '.' == pszAnsiBuf[cbAnsiBufLen - 1] )
  1773. {
  1774. bFormatIsValid = false;
  1775. rErrorTypeStrID = IDS_OID_CANNOT_END_WITH_DOT;
  1776. }
  1777. }
  1778. if ( bFormatIsValid )
  1779. {
  1780. bFormatIsValid = false;
  1781. CRYPT_ATTRIBUTE cryptAttr;
  1782. // FUTURE-2002-03/94/2002-dantra-Although this is a safe usage of ZeroMemory, suggest changing
  1783. // the definition CRYPT_ATTRIBUTE cryptAttr = {0} and removing the ZeroMemory call.
  1784. ::ZeroMemory (&cryptAttr, sizeof (CRYPT_ATTRIBUTE));
  1785. cryptAttr.cValue = 0;
  1786. cryptAttr.pszObjId = pszAnsiBuf;
  1787. cryptAttr.rgValue = 0;
  1788. DWORD cbEncoded = 0;
  1789. BOOL bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1790. PKCS_ATTRIBUTE,
  1791. &cryptAttr,
  1792. NULL,
  1793. &cbEncoded);
  1794. if ( cbEncoded > 0 )
  1795. {
  1796. BYTE* pBuffer = new BYTE[cbEncoded];
  1797. if ( pBuffer )
  1798. {
  1799. bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1800. PKCS_ATTRIBUTE,
  1801. &cryptAttr,
  1802. pBuffer,
  1803. &cbEncoded);
  1804. if ( bResult )
  1805. {
  1806. DWORD cbStructInfo = 0;
  1807. bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1808. PKCS_ATTRIBUTE,
  1809. pBuffer,
  1810. cbEncoded,
  1811. 0,
  1812. 0,
  1813. &cbStructInfo);
  1814. if ( cbStructInfo > 0 )
  1815. {
  1816. BYTE* pStructBuf = new BYTE[cbStructInfo];
  1817. if ( pStructBuf )
  1818. {
  1819. bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1820. PKCS_ATTRIBUTE,
  1821. pBuffer,
  1822. cbEncoded,
  1823. 0,
  1824. pStructBuf,
  1825. &cbStructInfo);
  1826. if ( bResult )
  1827. {
  1828. CRYPT_ATTRIBUTE* pCryptAttr = (CRYPT_ATTRIBUTE*) pStructBuf;
  1829. if ( !strcmp (pszAnsiBuf, pCryptAttr->pszObjId) )
  1830. {
  1831. bFormatIsValid = true;
  1832. }
  1833. }
  1834. delete [] pStructBuf;
  1835. }
  1836. }
  1837. }
  1838. delete [] pBuffer;
  1839. }
  1840. }
  1841. }
  1842. }
  1843. else
  1844. {
  1845. DebugTrace(L"WideCharToMultiByte (%s) failed: 0x%x\n", pszOidValue,
  1846. GetLastError ());
  1847. }
  1848. delete [] pszAnsiBuf;
  1849. }
  1850. }
  1851. else
  1852. {
  1853. rErrorTypeStrID = IDS_OID_MUST_NOT_BE_EMPTY;
  1854. DebugTrace(L"WideCharToMultiByte (%s) return: 0x%x\n", pszOidValue,
  1855. GetLastError ());
  1856. }
  1857. return bFormatIsValid;
  1858. }
  1859. HRESULT
  1860. DeleteObject(
  1861. const CString& path,
  1862. Cookie* pcookie,
  1863. PCWSTR pszClass
  1864. )
  1865. /***
  1866. This deletes an attribute from the schema
  1867. ***/
  1868. {
  1869. HRESULT hr = S_OK;
  1870. do
  1871. {
  1872. if ( !pcookie )
  1873. {
  1874. hr = E_INVALIDARG;
  1875. break;
  1876. }
  1877. CComPtr<IADsPathname> spIADsPathname;
  1878. hr = ::CoCreateInstance( CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  1879. IID_IADsPathname, (void**)&spIADsPathname);
  1880. if ( FAILED(hr) )
  1881. {
  1882. break;
  1883. }
  1884. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  1885. hr = spIADsPathname->Set( CComBSTR(path), ADS_SETTYPE_FULL );
  1886. if ( FAILED(hr) )
  1887. {
  1888. break;
  1889. }
  1890. // Get the RDN so that we have it for deleting
  1891. CComBSTR sbstrRDN;
  1892. hr = spIADsPathname->Retrieve( ADS_FORMAT_LEAF, &sbstrRDN );
  1893. if ( FAILED(hr) )
  1894. {
  1895. break;
  1896. }
  1897. // Get the path to the parent container
  1898. hr = spIADsPathname->RemoveLeafElement();
  1899. if ( FAILED(hr) )
  1900. {
  1901. break;
  1902. }
  1903. CComBSTR sbstrParentPath;
  1904. hr = spIADsPathname->Retrieve( ADS_FORMAT_X500, &sbstrParentPath );
  1905. if ( FAILED(hr) )
  1906. {
  1907. break;
  1908. }
  1909. // Now open the parent object
  1910. CComPtr<IADsContainer> spContainer;
  1911. hr = ::AdminToolsOpenObject( sbstrParentPath, NULL, NULL, ADS_SECURE_AUTHENTICATION,
  1912. IID_IADsContainer, (void**)&spContainer);
  1913. if ( FAILED(hr) )
  1914. {
  1915. break;
  1916. }
  1917. // NTRAID#NTBUG9-540866-2002/02/13-dantra-Schema Manager: passing WCHAR * instead of BSTR to method requiring a BSTR
  1918. hr = spContainer->Delete( CComBSTR(pszClass), sbstrRDN );
  1919. if ( FAILED(hr) )
  1920. {
  1921. break;
  1922. }
  1923. } while (false);
  1924. return hr;
  1925. }
  1926. //////////////////////////////////////////////////////////////////
  1927. // Theming support
  1928. HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
  1929. {
  1930. PROPSHEETPAGE_V3 sp_v3 = {0};
  1931. // NTRAID#NTBUG9-567166-2002/03/06-dantra-Possible buffer overrun in MyCreatePropertySheetPage
  1932. CopyMemory (&sp_v3, psp, psp->dwSize);
  1933. sp_v3.dwSize = sizeof(sp_v3);
  1934. return (::CreatePropertySheetPage(&sp_v3));
  1935. }
  1936. // Menu Helper
  1937. HRESULT
  1938. _InsertMenuHelper(
  1939. LPCONTEXTMENUCALLBACK piCallback,
  1940. long lInsertionPointID,
  1941. int index,
  1942. BOOL fEnabled, /* = TRUE */
  1943. BOOL fChecked /* = FALSE */)
  1944. {
  1945. CONTEXTMENUITEM MenuItem;
  1946. MenuItem.lInsertionPointID = lInsertionPointID;
  1947. MenuItem.fFlags = (fEnabled ? 0 : MF_GRAYED) |
  1948. (fChecked ? MF_CHECKED : 0);
  1949. MenuItem.fSpecialFlags = 0;
  1950. MenuItem.strName = const_cast<BSTR>(
  1951. (LPCTSTR)g_MenuStrings[index] );
  1952. MenuItem.strStatusBarText = const_cast<BSTR>(
  1953. (LPCTSTR)g_StatusStrings[index] );
  1954. MenuItem.lCommandID = index;
  1955. return piCallback->AddItem( &MenuItem );
  1956. }
  1957. HRESULT
  1958. SchemaOpenObject
  1959. (
  1960. PCWSTR pathName,
  1961. REFIID riid,
  1962. void** object
  1963. )
  1964. {
  1965. return
  1966. (
  1967. AdminToolsOpenObject
  1968. (
  1969. const_cast<LPWSTR>((LPCWSTR) pathName),
  1970. NULL,
  1971. NULL,
  1972. ADS_SECURE_AUTHENTICATION,
  1973. riid,
  1974. object
  1975. )
  1976. );
  1977. }