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.

2287 lines
62 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: common.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #include <SnapBase.h>
  12. #include "common.h"
  13. #include "editor.h"
  14. #include "connection.h"
  15. #include "credui.h"
  16. #include "attrres.h"
  17. #ifdef DEBUG_ALLOCATOR
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. #endif
  24. ////////////////////////////////////////////////////////////////////////////////////////
  25. extern LPCWSTR g_lpszRootDSE;
  26. ////////////////////////////////////////////////////////////////////////////////////////
  27. // FUTURE-2002/03/06-artm Comment differences b/w 2 OpenObjecctWithCredentials().
  28. // It also wouldn't hurt to have a comment explaining why there are two
  29. // HRESULT's for these functions.
  30. // NTRAID#NTBUG9-563093-2002/03/06-artm Need to validate parms before using.
  31. // All pointers are either dereferenced or passed to ADsI w/out checking for NULL.
  32. HRESULT OpenObjectWithCredentials(
  33. CConnectionData* pConnectData,
  34. const BOOL bUseCredentials,
  35. LPCWSTR lpszPath,
  36. const IID& iid,
  37. LPVOID* ppObject,
  38. HWND hWnd,
  39. HRESULT& hResult
  40. )
  41. {
  42. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  43. CThemeContextActivator activator;
  44. HRESULT hr = S_OK;
  45. hResult = S_OK;
  46. CWaitCursor cursor;
  47. CWnd* pCWnd = CWnd::FromHandle(hWnd);
  48. CCredentialObject* pCredObject = pConnectData->GetCredentialObject();
  49. if (bUseCredentials)
  50. {
  51. CString sUserName;
  52. EncryptedString password;
  53. WCHAR* cleartext = NULL;
  54. UINT uiDialogResult = IDOK;
  55. // NOTICE-NTRAID#NTBUG9-563071-2002/04/17-artm Should not store pwd on stack.
  56. // Rewrote to use encrypted string class, which handles the memory management
  57. // of the clear text copies.
  58. while (uiDialogResult != IDCANCEL)
  59. {
  60. pCredObject->GetUsername(sUserName);
  61. password = pCredObject->GetPassword();
  62. // This shouldn't happen, but let's be paranoid.
  63. ASSERT(password.GetLength() <= MAX_PASSWORD_LENGTH);
  64. cleartext = password.GetClearTextCopy();
  65. // If we are out of memory return error code.
  66. if (cleartext == NULL)
  67. {
  68. // We need to clean up copy of password before returning.
  69. password.DestroyClearTextCopy(cleartext);
  70. hr = E_OUTOFMEMORY;
  71. return hr;
  72. }
  73. hr = AdminToolsOpenObject(lpszPath,
  74. sUserName,
  75. cleartext,
  76. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  77. iid,
  78. ppObject);
  79. // NOTICE-NTRAID#NTBUG9-553646-2002/04/17-artm Replace with SecureZeroMemory().
  80. // FIXED: this is a non-issue when using encrypted strings
  81. // (just be sure to call DestroyClearTextCopy() regardless of whether or not
  82. // the copy is null)
  83. // Clean up the clear text copy of password.
  84. password.DestroyClearTextCopy(cleartext);
  85. // If logon fails pop up the credentials dialog box
  86. //
  87. if (HRESULT_CODE(hr) == ERROR_LOGON_FAILURE ||
  88. HRESULT_CODE(hr) == ERROR_NOT_AUTHENTICATED ||
  89. HRESULT_CODE(hr) == ERROR_INVALID_PASSWORD ||
  90. HRESULT_CODE(hr) == ERROR_PASSWORD_EXPIRED ||
  91. HRESULT_CODE(hr) == ERROR_ACCOUNT_DISABLED ||
  92. HRESULT_CODE(hr) == ERROR_ACCOUNT_LOCKED_OUT ||
  93. hr == E_ADS_BAD_PATHNAME)
  94. {
  95. CString sConnectName;
  96. // GetConnectionNode() is NULL when the connection is first being
  97. // create, but since it is the connection node we can get the name
  98. // directly from the CConnectionData.
  99. //
  100. ASSERT(pConnectData != NULL);
  101. // FUTURE-2002/03/06-artm This ASSERT() seems to be useless here.
  102. if (pConnectData->GetConnectionNode() == NULL)
  103. {
  104. pConnectData->GetName(sConnectName);
  105. }
  106. else
  107. {
  108. sConnectName = pConnectData->GetConnectionNode()->GetDisplayName();
  109. }
  110. // NTRAID#NTBUG9-546168-2002/02/26-artm Do not use custom rolled credential dialog.
  111. // Use CredManager dialog instead.
  112. CCredentialDialog credDialog(pCredObject, sConnectName, pCWnd);
  113. uiDialogResult = credDialog.DoModal();
  114. cursor.Restore();
  115. if (uiDialogResult == IDCANCEL)
  116. {
  117. hResult = E_FAIL;
  118. }
  119. else
  120. {
  121. hResult = S_OK;
  122. }
  123. }
  124. else
  125. {
  126. break;
  127. }
  128. } // end while loop
  129. }
  130. else
  131. {
  132. hr = AdminToolsOpenObject(
  133. lpszPath,
  134. NULL,
  135. NULL,
  136. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  137. iid,
  138. ppObject);
  139. }
  140. return hr;
  141. }
  142. // NTRAID#NTBUG9-563093-2002/03/06-artm Need to validate parms before using.
  143. // All pointers are either dereferenced or passed to ADsI w/out checking for NULL.
  144. HRESULT OpenObjectWithCredentials(
  145. CCredentialObject* pCredObject,
  146. LPCWSTR lpszPath,
  147. const IID& iid,
  148. LPVOID* ppObject)
  149. {
  150. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  151. HRESULT hr;
  152. if (pCredObject->UseCredentials())
  153. {
  154. CString sUserName;
  155. EncryptedString password;
  156. WCHAR* cleartext = NULL;
  157. UINT uiDialogResult = IDOK;
  158. // NOTICE-NTRAID#NTBUG9-563071-2002/04/17-artm Should not store pwd on stack.
  159. // Rewrote to use encrypted string which manages memory of clear text copies.
  160. pCredObject->GetUsername(sUserName);
  161. password = pCredObject->GetPassword();
  162. // This shouldn't happen, but let's be paranoid.
  163. ASSERT(password.GetLength() <= MAX_PASSWORD_LENGTH);
  164. cleartext = password.GetClearTextCopy();
  165. if (NULL != cleartext)
  166. {
  167. hr = AdminToolsOpenObject(lpszPath,
  168. sUserName,
  169. cleartext,
  170. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  171. iid,
  172. ppObject);
  173. }
  174. else
  175. {
  176. // We ran out of memory! Report the error.
  177. hr = E_OUTOFMEMORY;
  178. }
  179. // NOTICE-NTRAID#NTBUG9-553646-2002/04/17-artm Replace with SecureZeroMemory().
  180. // FIXED: this is non-issue when using encrypted strings. Just be sure to call
  181. // DestroyClearTextCopy() on all clear text copies.
  182. password.DestroyClearTextCopy(cleartext);
  183. }
  184. else
  185. {
  186. hr = AdminToolsOpenObject(lpszPath,
  187. NULL,
  188. NULL,
  189. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  190. iid,
  191. ppObject);
  192. }
  193. return hr;
  194. }
  195. HRESULT CALLBACK BindingCallbackFunction(LPCWSTR lpszPathName,
  196. DWORD dwReserved,
  197. REFIID riid,
  198. void FAR * FAR * ppObject,
  199. LPARAM lParam)
  200. {
  201. CCredentialObject* pCredObject = reinterpret_cast<CCredentialObject*>(lParam);
  202. if (pCredObject == NULL)
  203. {
  204. return E_FAIL;
  205. }
  206. HRESULT hr = OpenObjectWithCredentials(pCredObject,
  207. lpszPathName,
  208. riid,
  209. ppObject);
  210. return hr;
  211. }
  212. HRESULT GetRootDSEObject(CConnectionData* pConnectData,
  213. IADs** ppDirObject)
  214. {
  215. // Get data from connection node
  216. //
  217. CString sRootDSE, sServer, sPort, sLDAP;
  218. pConnectData->GetDomainServer(sServer);
  219. pConnectData->GetLDAP(sLDAP);
  220. pConnectData->GetPort(sPort);
  221. if (sServer != _T(""))
  222. {
  223. sRootDSE = sLDAP + sServer;
  224. if (sPort != _T(""))
  225. {
  226. sRootDSE = sRootDSE + _T(":") + sPort + _T("/");
  227. }
  228. else
  229. {
  230. sRootDSE = sRootDSE + _T("/");
  231. }
  232. sRootDSE = sRootDSE + g_lpszRootDSE;
  233. }
  234. else
  235. {
  236. sRootDSE = sLDAP + g_lpszRootDSE;
  237. }
  238. HRESULT hr, hCredResult;
  239. hr = OpenObjectWithCredentials(
  240. pConnectData,
  241. pConnectData->GetCredentialObject()->UseCredentials(),
  242. sRootDSE,
  243. IID_IADs,
  244. (LPVOID*) ppDirObject,
  245. NULL,
  246. hCredResult
  247. );
  248. if ( FAILED(hr) )
  249. {
  250. if (SUCCEEDED(hCredResult))
  251. {
  252. ADSIEditErrorMessage(hr);
  253. }
  254. return hr;
  255. }
  256. return hr;
  257. }
  258. HRESULT GetItemFromRootDSE(LPCWSTR lpszRootDSEItem,
  259. CString& sItem,
  260. CConnectionData* pConnectData)
  261. {
  262. // Get data from connection node
  263. //
  264. CString sRootDSE, sServer, sPort, sLDAP;
  265. pConnectData->GetDomainServer(sServer);
  266. pConnectData->GetLDAP(sLDAP);
  267. pConnectData->GetPort(sPort);
  268. if (sServer != _T(""))
  269. {
  270. sRootDSE = sLDAP + sServer;
  271. if (sPort != _T(""))
  272. {
  273. sRootDSE = sRootDSE + _T(":") + sPort + _T("/");
  274. }
  275. else
  276. {
  277. sRootDSE = sRootDSE + _T("/");
  278. }
  279. sRootDSE = sRootDSE + g_lpszRootDSE;
  280. }
  281. else
  282. {
  283. sRootDSE = sLDAP + g_lpszRootDSE;
  284. }
  285. CComPtr<IADs> pADs;
  286. HRESULT hr, hCredResult;
  287. hr = OpenObjectWithCredentials(
  288. pConnectData,
  289. pConnectData->GetCredentialObject()->UseCredentials(),
  290. sRootDSE,
  291. IID_IADs,
  292. (LPVOID*) &pADs,
  293. NULL,
  294. hCredResult
  295. );
  296. if ( FAILED(hr) )
  297. {
  298. if (SUCCEEDED(hCredResult))
  299. {
  300. ADSIEditErrorMessage(hr);
  301. }
  302. return hr;
  303. }
  304. VARIANT var;
  305. VariantInit(&var);
  306. hr = pADs->Get( CComBSTR(lpszRootDSEItem), &var );
  307. if ( FAILED(hr) )
  308. {
  309. VariantClear(&var);
  310. return hr;
  311. }
  312. BSTR bstrItem = V_BSTR(&var);
  313. sItem = bstrItem;
  314. VariantClear(&var);
  315. return S_OK;
  316. }
  317. HRESULT VariantToStringList( VARIANT& refvar, CStringList& refstringlist)
  318. {
  319. HRESULT hr = S_OK;
  320. long start, end;
  321. if ( !(V_VT(&refvar) & VT_ARRAY) )
  322. {
  323. if ( V_VT(&refvar) != VT_BSTR )
  324. {
  325. hr = VariantChangeType( &refvar, &refvar,0, VT_BSTR );
  326. if( FAILED(hr) )
  327. {
  328. return hr;
  329. }
  330. }
  331. refstringlist.AddHead( V_BSTR(&refvar) );
  332. return hr;
  333. }
  334. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  335. //
  336. // Figure out the dimensions of the array.
  337. //
  338. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  339. if( FAILED(hr) )
  340. return hr;
  341. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  342. if( FAILED(hr) )
  343. return hr;
  344. VARIANT SingleResult;
  345. VariantInit( &SingleResult );
  346. //
  347. // Process the array elements.
  348. //
  349. for ( long idx = start; idx <= end; idx++ )
  350. {
  351. hr = SafeArrayGetElement( saAttributes, &idx, &SingleResult );
  352. if( FAILED(hr) )
  353. {
  354. return hr;
  355. }
  356. if ( V_VT(&SingleResult) != VT_BSTR )
  357. {
  358. if ( V_VT(&SingleResult) == VT_NULL )
  359. {
  360. V_VT(&SingleResult ) = VT_BSTR;
  361. V_BSTR(&SingleResult ) = SysAllocString(L"0");
  362. }
  363. else
  364. {
  365. hr = VariantChangeType( &SingleResult, &SingleResult,0, VT_BSTR );
  366. if( FAILED(hr) )
  367. {
  368. return hr;
  369. }
  370. }
  371. }
  372. //if ( V_VT(&SingleResult) != VT_BSTR )
  373. // return E_UNEXPECTED;
  374. refstringlist.AddHead( V_BSTR(&SingleResult) );
  375. VariantClear( &SingleResult );
  376. }
  377. return S_OK;
  378. } // VariantToStringList()
  379. /////////////////////////////////////////////////////////////////////
  380. HRESULT StringListToVariant( VARIANT& refvar, const CStringList& refstringlist)
  381. {
  382. HRESULT hr = S_OK;
  383. int cCount = refstringlist.GetCount();
  384. SAFEARRAYBOUND rgsabound[1];
  385. rgsabound[0].lLbound = 0;
  386. rgsabound[0].cElements = cCount;
  387. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
  388. if (NULL == psa)
  389. return E_OUTOFMEMORY;
  390. VariantClear( &refvar );
  391. V_VT(&refvar) = VT_VARIANT|VT_ARRAY;
  392. V_ARRAY(&refvar) = psa;
  393. VARIANT SingleResult;
  394. VariantInit( &SingleResult );
  395. V_VT(&SingleResult) = VT_BSTR;
  396. POSITION pos = refstringlist.GetHeadPosition();
  397. long i;
  398. for (i = 0; i < cCount, pos != NULL; i++)
  399. {
  400. V_BSTR(&SingleResult) = T2BSTR((LPCTSTR)refstringlist.GetNext(pos));
  401. hr = SafeArrayPutElement(psa, &i, &SingleResult);
  402. if( FAILED(hr) )
  403. return hr;
  404. }
  405. if (i != cCount || pos != NULL)
  406. return E_UNEXPECTED;
  407. return hr;
  408. } // StringListToVariant()
  409. ///////////////////////////////////////////////////////////////////////////////////////
  410. BOOL GetErrorMessage(HRESULT hr, CString& szErrorString, BOOL bTryADsIErrors)
  411. {
  412. HRESULT hrGetLast = S_OK;
  413. DWORD status;
  414. PTSTR ptzSysMsg = NULL;
  415. // first check if we have extended ADs errors
  416. if ((hr != S_OK) && bTryADsIErrors)
  417. {
  418. // FUTURE-2002/02/27-artm Replace magic '256' w/ named constant.
  419. // Better maintenance and readability.
  420. WCHAR Buf1[256], Buf2[256];
  421. hrGetLast = ::ADsGetLastError(&status, Buf1, 256, Buf2, 256);
  422. TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
  423. status, Buf1, Buf2);
  424. if ((status != ERROR_INVALID_DATA) && (status != 0))
  425. {
  426. hr = status;
  427. }
  428. }
  429. // try the system first
  430. // NOTICE-2002/02/27-artm FormatMessage() not dangerous b/c uses FORMAT_MESSAGE_ALLOCATE_BUFFER.
  431. int nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  432. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr,
  433. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  434. (PTSTR)&ptzSysMsg, 0, NULL);
  435. if (nChars == 0)
  436. {
  437. //try ads errors
  438. static HMODULE g_adsMod = 0;
  439. if (0 == g_adsMod)
  440. g_adsMod = GetModuleHandle (L"activeds.dll");
  441. // NOTICE-2002/02/27-artm FormatMessage() not dangerous b/c uses FORMAT_MESSAGE_ALLOCATE_BUFFER.
  442. nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  443. | FORMAT_MESSAGE_FROM_HMODULE, g_adsMod, hr,
  444. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  445. (PTSTR)&ptzSysMsg, 0, NULL);
  446. }
  447. if (nChars > 0)
  448. {
  449. szErrorString = ptzSysMsg;
  450. ::LocalFree(ptzSysMsg);
  451. }
  452. else
  453. {
  454. szErrorString.Format(L"Error code: X%x", hr);
  455. }
  456. return (nChars > 0);
  457. }
  458. ////////////////////////////////////////////////////////////////////////////////////
  459. typedef struct tagSYNTAXMAP
  460. {
  461. LPCWSTR lpszAttr;
  462. VARTYPE type;
  463. } SYNTAXMAP;
  464. SYNTAXMAP ldapSyntax[] =
  465. {
  466. _T("DN"), VT_BSTR,
  467. _T("DIRECTORYSTRING"), VT_BSTR,
  468. _T("IA5STRING"), VT_BSTR,
  469. _T("CASEIGNORESTRING"), VT_BSTR,
  470. _T("PRINTABLESTRING"), VT_BSTR,
  471. _T("NUMERICSTRING"), VT_BSTR,
  472. _T("UTCTIME"), VT_DATE,
  473. _T("ORNAME"), VT_BSTR,
  474. _T("OCTETSTRING"), VT_BSTR,
  475. _T("BOOLEAN"), VT_BOOL,
  476. _T("INTEGER"), VT_I4,
  477. _T("OID"), VT_BSTR,
  478. _T("INTEGER8"), VT_I8,
  479. _T("OBJECTSECURITYDESCRIPTOR"), VT_BSTR,
  480. NULL, 0,
  481. };
  482. #define MAX_ATTR_STRING_LENGTH 30
  483. VARTYPE VariantTypeFromSyntax(LPCWSTR lpszProp )
  484. {
  485. int idx=0;
  486. while( ldapSyntax[idx].lpszAttr )
  487. {
  488. if ( _wcsnicmp(lpszProp, ldapSyntax[idx].lpszAttr, MAX_ATTR_STRING_LENGTH) )
  489. {
  490. return ldapSyntax[idx].type;
  491. }
  492. idx++;
  493. }
  494. // NOTICE-2002/02/27-artm If the syntax specified in lpszProp does
  495. // not match any of the expected values, stop execution in debug build (probably a bug).
  496. // In a release build, return string type since there is no conversion
  497. // involved in displaying a string.
  498. ASSERT(FALSE);
  499. return VT_BSTR;
  500. }
  501. //////////////////////////////////////////////////////////////////////////////////////////////////
  502. //
  503. // Function : GetStringFromADsValue
  504. //
  505. // Formats an ADSVALUE struct into a string
  506. //
  507. ///////////////////////////////////////////////////////////////////////////////////////////////////
  508. void GetStringFromADsValue(const PADSVALUE pADsValue, CString& szValue, DWORD dwMaxCharCount)
  509. {
  510. szValue.Empty();
  511. if (!pADsValue)
  512. {
  513. ASSERT(pADsValue);
  514. return;
  515. }
  516. CString sTemp;
  517. switch( pADsValue->dwType )
  518. {
  519. case ADSTYPE_DN_STRING :
  520. sTemp.Format(L"%s", pADsValue->DNString);
  521. break;
  522. case ADSTYPE_CASE_EXACT_STRING :
  523. sTemp.Format(L"%s", pADsValue->CaseExactString);
  524. break;
  525. case ADSTYPE_CASE_IGNORE_STRING:
  526. sTemp.Format(L"%s", pADsValue->CaseIgnoreString);
  527. break;
  528. case ADSTYPE_PRINTABLE_STRING :
  529. sTemp.Format(L"%s", pADsValue->PrintableString);
  530. break;
  531. case ADSTYPE_NUMERIC_STRING :
  532. sTemp.Format(L"%s", pADsValue->NumericString);
  533. break;
  534. case ADSTYPE_OBJECT_CLASS :
  535. sTemp.Format(L"%s", pADsValue->ClassName);
  536. break;
  537. case ADSTYPE_BOOLEAN :
  538. sTemp.Format(L"%s", ((DWORD)pADsValue->Boolean) ? L"TRUE" : L"FALSE");
  539. break;
  540. case ADSTYPE_INTEGER :
  541. sTemp.Format(L"%d", (DWORD) pADsValue->Integer);
  542. break;
  543. case ADSTYPE_OCTET_STRING :
  544. {
  545. CString sOctet;
  546. BYTE b;
  547. for ( DWORD idx=0; idx<pADsValue->OctetString.dwLength; idx++)
  548. {
  549. b = ((BYTE *)pADsValue->OctetString.lpValue)[idx];
  550. sOctet.Format(L"0x%02x ", b);
  551. sTemp += sOctet;
  552. if (dwMaxCharCount != 0 && sTemp.GetLength() > dwMaxCharCount)
  553. {
  554. break;
  555. }
  556. }
  557. }
  558. break;
  559. case ADSTYPE_LARGE_INTEGER :
  560. litow(pADsValue->LargeInteger, sTemp);
  561. break;
  562. case ADSTYPE_UTC_TIME :
  563. sTemp = GetStringValueFromSystemTime(&pADsValue->UTCTime);
  564. break;
  565. case ADSTYPE_NT_SECURITY_DESCRIPTOR: // I use the ACLEditor instead
  566. {
  567. }
  568. break;
  569. default :
  570. break;
  571. }
  572. szValue = sTemp;
  573. }
  574. //////////////////////////////////////////////////////////////////////////////////////////////////
  575. //
  576. // Function : GetStringFromADs
  577. //
  578. // Formats an ADS_ATTR_INFO structs values into strings and APPENDS them to a CStringList that is
  579. // passed in as a parameter.
  580. //
  581. ///////////////////////////////////////////////////////////////////////////////////////////////////
  582. void GetStringFromADs(const ADS_ATTR_INFO* pInfo, CStringList& sList, DWORD dwMaxCharCount)
  583. {
  584. CString sTemp;
  585. if ( pInfo == NULL )
  586. {
  587. return;
  588. }
  589. ADSVALUE *pValues = pInfo->pADsValues;
  590. for (DWORD x=0; x < pInfo->dwNumValues; x++)
  591. {
  592. if ( pInfo->dwADsType == ADSTYPE_INVALID )
  593. {
  594. continue;
  595. }
  596. sTemp.Empty();
  597. GetStringFromADsValue(pValues, sTemp, dwMaxCharCount);
  598. pValues++;
  599. sList.AddTail( sTemp );
  600. }
  601. }
  602. //////////////////////////////////////////////////////////////////////
  603. typedef struct tagSYNTAXTOADSMAP
  604. {
  605. LPCWSTR lpszAttr;
  606. ADSTYPE type;
  607. UINT nSyntaxResID;
  608. } SYNTAXTOADSMAP;
  609. SYNTAXTOADSMAP adsType[] =
  610. {
  611. L"2.5.5.0", ADSTYPE_INVALID, IDS_SYNTAX_UNKNOWN,
  612. L"2.5.5.1", ADSTYPE_DN_STRING, IDS_SYNTAX_DN,
  613. L"2.5.5.2", ADSTYPE_CASE_IGNORE_STRING, IDS_SYNTAX_OID,
  614. L"2.5.5.3", ADSTYPE_CASE_EXACT_STRING, IDS_SYNTAX_DNSTRING,
  615. L"2.5.5.4", ADSTYPE_CASE_IGNORE_STRING, IDS_SYNTAX_NOCASE_STR,
  616. L"2.5.5.5", ADSTYPE_PRINTABLE_STRING, IDS_SYNTAX_I5_STR,
  617. L"2.5.5.6", ADSTYPE_NUMERIC_STRING, IDS_SYNTAX_NUMSTR,
  618. L"2.5.5.7", ADSTYPE_CASE_IGNORE_STRING, IDS_SYNTAX_DN_BINARY,
  619. L"2.5.5.8", ADSTYPE_BOOLEAN, IDS_SYNTAX_BOOLEAN,
  620. L"2.5.5.9", ADSTYPE_INTEGER, IDS_SYNTAX_INTEGER,
  621. L"2.5.5.10", ADSTYPE_OCTET_STRING, IDS_SYNTAX_OCTET,
  622. L"2.5.5.11", ADSTYPE_UTC_TIME, IDS_SYNTAX_UTC,
  623. L"2.5.5.12", ADSTYPE_CASE_IGNORE_STRING, IDS_SYNTAX_UNICODE,
  624. L"2.5.5.13", ADSTYPE_CASE_IGNORE_STRING, IDS_SYNTAX_ADDRESS,
  625. L"2.5.5.14", ADSTYPE_INVALID, IDS_SYNTAX_DNSTRING,
  626. L"2.5.5.15", ADSTYPE_NT_SECURITY_DESCRIPTOR, IDS_SYNTAX_SEC_DESC,
  627. L"2.5.5.16", ADSTYPE_LARGE_INTEGER, IDS_SYNTAX_LINT,
  628. L"2.5.5.17", ADSTYPE_OCTET_STRING, IDS_SYNTAX_SID,
  629. NULL, ADSTYPE_INVALID, IDS_SYNTAX_UNKNOWN
  630. };
  631. // This length should be set to be the longest number of characters
  632. // in the adsType table. It should include the space for the terminating
  633. // null.
  634. const unsigned int MAX_ADS_TYPE_STRLEN = 9;
  635. ADSTYPE GetADsTypeFromString(LPCWSTR lps, CString& szSyntaxName)
  636. {
  637. int idx=0;
  638. BOOL loaded = 0;
  639. // NOTICE-NTRAID#NTBUG9-559260-2002/02/28-artm Should validate input string.
  640. // 1) Check that lps != NULL.
  641. // 2) Instead of wcscmp() use wcsncmp() since the maximum length of
  642. // valid strings is known (see adsType[] declared above).
  643. while( adsType[idx].lpszAttr && lps != NULL )
  644. {
  645. if ( wcsncmp(lps, adsType[idx].lpszAttr, MAX_ADS_TYPE_STRLEN) == 0 )
  646. {
  647. loaded = szSyntaxName.LoadString(adsType[idx].nSyntaxResID);
  648. ASSERT(loaded != FALSE);
  649. return adsType[idx].type;
  650. }
  651. idx++;
  652. }
  653. return ADSTYPE_INVALID;
  654. }
  655. //////////////////////////////////////////////////////////////////////////////////////////////////
  656. //
  657. // Function : GetStringValueFromSystemTime
  658. //
  659. // Builds a locale/timezone specific display string from a SYSTEMTIME structure
  660. //
  661. ///////////////////////////////////////////////////////////////////////////////////////////////////
  662. CString GetStringValueFromSystemTime(const SYSTEMTIME* pTime)
  663. {
  664. CString szResult;
  665. do
  666. {
  667. if (!pTime)
  668. {
  669. break;
  670. }
  671. // Format the string with respect to locale
  672. PWSTR pwszDate = NULL;
  673. int cchDate = 0;
  674. cchDate = GetDateFormat(LOCALE_USER_DEFAULT,
  675. 0,
  676. const_cast<SYSTEMTIME*>(pTime),
  677. NULL,
  678. pwszDate,
  679. 0);
  680. pwszDate = new WCHAR[cchDate];
  681. if (pwszDate == NULL)
  682. {
  683. break;
  684. }
  685. ZeroMemory(pwszDate, cchDate * sizeof(WCHAR));
  686. if (GetDateFormat(LOCALE_USER_DEFAULT,
  687. 0,
  688. const_cast<SYSTEMTIME*>(pTime),
  689. NULL,
  690. pwszDate,
  691. cchDate))
  692. {
  693. szResult = pwszDate;
  694. }
  695. else
  696. {
  697. szResult = L"";
  698. }
  699. delete[] pwszDate;
  700. PWSTR pwszTime = NULL;
  701. cchDate = GetTimeFormat(LOCALE_USER_DEFAULT,
  702. 0,
  703. const_cast<SYSTEMTIME*>(pTime),
  704. NULL,
  705. pwszTime,
  706. 0);
  707. pwszTime = new WCHAR[cchDate];
  708. if (!pwszTime)
  709. {
  710. break;
  711. }
  712. ZeroMemory(pwszTime, cchDate * sizeof(WCHAR));
  713. if (GetTimeFormat(LOCALE_USER_DEFAULT,
  714. 0,
  715. const_cast<SYSTEMTIME*>(pTime),
  716. NULL,
  717. pwszTime,
  718. cchDate))
  719. {
  720. szResult += _T(" ") + CString(pwszTime);
  721. }
  722. delete[] pwszTime;
  723. } while (false);
  724. return szResult;
  725. }
  726. ////////////////////////////////////////////////////////////////
  727. // Type conversions for LARGE_INTEGERs
  728. void wtoli(LPCWSTR p, LARGE_INTEGER& liOut)
  729. {
  730. liOut.QuadPart = 0;
  731. BOOL bNeg = FALSE;
  732. if (*p == L'-')
  733. {
  734. bNeg = TRUE;
  735. p++;
  736. }
  737. while (*p != L'\0')
  738. {
  739. liOut.QuadPart = 10 * liOut.QuadPart + (*p-L'0');
  740. p++;
  741. }
  742. if (bNeg)
  743. {
  744. liOut.QuadPart *= -1;
  745. }
  746. }
  747. void litow(LARGE_INTEGER& li, CString& sResult)
  748. {
  749. LARGE_INTEGER n;
  750. n.QuadPart = li.QuadPart;
  751. if (n.QuadPart == 0)
  752. {
  753. sResult = L"0";
  754. }
  755. else
  756. {
  757. CString sNeg;
  758. sResult = L"";
  759. if (n.QuadPart < 0)
  760. {
  761. sNeg = CString(L'-');
  762. n.QuadPart *= -1;
  763. }
  764. while (n.QuadPart > 0)
  765. {
  766. sResult += CString(L'0' + (n.QuadPart % 10));
  767. n.QuadPart = n.QuadPart / 10;
  768. }
  769. sResult = sResult + sNeg;
  770. }
  771. sResult.MakeReverse();
  772. }
  773. void ultow(ULONG ul, CString& sResult)
  774. {
  775. ULONG n;
  776. n = ul;
  777. if (n == 0)
  778. {
  779. sResult = L"0";
  780. }
  781. else
  782. {
  783. sResult = L"";
  784. while (n > 0)
  785. {
  786. sResult += CString(L'0' + (n % 10));
  787. n = n / 10;
  788. }
  789. }
  790. sResult.MakeReverse();
  791. }
  792. /////////////////////////////////////////////////////////////////////
  793. // IO to/from Streams
  794. HRESULT SaveStringToStream(IStream* pStm, const CString& sString)
  795. {
  796. HRESULT err = S_OK;
  797. ULONG cbWrite;
  798. ULONG nLen;
  799. if (pStm == NULL)
  800. {
  801. return E_POINTER;
  802. }
  803. // sString cannot be null since it is passed as a reference
  804. nLen = sString.GetLength() + 1; // Include the NULL in length.
  805. // Write the length of the string to the stream.
  806. err = pStm->Write((void*)&nLen, sizeof(UINT), &cbWrite);
  807. if (FAILED(err))
  808. {
  809. ASSERT(false);
  810. return err;
  811. }
  812. ASSERT(cbWrite == sizeof(UINT));
  813. // Write the contents of the string to the stream.
  814. err = pStm->Write(
  815. (void*)static_cast<LPCWSTR>(sString),
  816. sizeof(WCHAR) * nLen,
  817. &cbWrite);
  818. if (SUCCEEDED(err))
  819. {
  820. ASSERT(cbWrite == sizeof(WCHAR) * nLen);
  821. }
  822. return err;
  823. }
  824. HRESULT SaveStringListToStream(IStream* pStm, CStringList& sList)
  825. {
  826. HRESULT err = S_OK;
  827. // for each string in the list, write # of chars+NULL, and then the string
  828. ULONG cbWrite;
  829. ULONG nLen;
  830. UINT nCount;
  831. // write # of strings in list
  832. nCount = (UINT)sList.GetCount();
  833. err = pStm->Write((void*)&nCount, sizeof(UINT), &cbWrite);
  834. // NOTICE-NTRAID#NTBUG9-559560-2002/02/28-artm If unable to write # of strings, return an error code.
  835. // What is the point in returning S_OK if the first write to stream failed?
  836. // Worse, don't need to try to write any of the strings to the stream...
  837. if (FAILED(err))
  838. {
  839. ASSERT(false);
  840. return err;
  841. }
  842. ASSERT(cbWrite == sizeof(UINT));
  843. // Write the list of strings to the stream.
  844. CString s;
  845. POSITION pos = sList.GetHeadPosition();
  846. while ( SUCCEEDED(err) && pos != NULL )
  847. {
  848. s = sList.GetNext(pos);
  849. err = SaveStringToStream(pStm, s);
  850. }
  851. ASSERT( SUCCEEDED(err) );
  852. return err;
  853. }
  854. HRESULT LoadStringFromStream(IStream* pStm, CString& sString)
  855. {
  856. HRESULT err = S_OK;
  857. ULONG nLen; // WCHAR counting NULL
  858. ULONG cbRead;
  859. if (pStm == NULL)
  860. {
  861. return E_POINTER;
  862. }
  863. // NOTICE-NTRAID#NTBUG9--2002/04/26-artm Possible buffer overrun in stack buffer.
  864. // Rewrote function to first read the length of the string, and then allocate
  865. // a dynamically sized buffer large enough to hold the string.
  866. // Read string length from stream (including null).
  867. err = pStm->Read((void*)&nLen, sizeof(UINT), &cbRead);
  868. if (FAILED(err))
  869. {
  870. ASSERT(false);
  871. return err;
  872. }
  873. ASSERT(cbRead == sizeof(UINT));
  874. //
  875. // Read the string from the stream.
  876. //
  877. WCHAR* szBuffer = new WCHAR[nLen];
  878. if (szBuffer == NULL)
  879. {
  880. return E_OUTOFMEMORY;
  881. }
  882. err = pStm->Read((void*)szBuffer, sizeof(WCHAR)*nLen, &cbRead);
  883. if (SUCCEEDED(err))
  884. {
  885. ASSERT(cbRead == sizeof(WCHAR) * nLen);
  886. // Who knows what might have happened to the persisted data
  887. // between the time we wrote and now. We'll be extra careful
  888. // and guarantee that our string is null terminated at the correct
  889. // place.
  890. ASSERT(szBuffer[nLen - 1] == NULL);
  891. szBuffer[nLen - 1] = NULL;
  892. sString = szBuffer;
  893. }
  894. else
  895. {
  896. ASSERT(false);
  897. }
  898. // Free temporary buffer.
  899. delete [] szBuffer;
  900. return err;
  901. }
  902. HRESULT LoadStringListFromStream(IStream* pStm, CStringList& sList)
  903. {
  904. HRESULT err = S_OK;
  905. ULONG cbRead;
  906. UINT nCount;
  907. if (NULL == pStm)
  908. {
  909. return E_POINTER;
  910. }
  911. // NOTICE-NTRAID#NTBUG9-559560-2002/02/28-artm If unable to read # of strings, return an error code.
  912. // What is the point in returning S_OK if the first write to stream failed?
  913. // Worse, don't need to try to write any of the strings to the stream...
  914. // Read the number of strings in the list.
  915. err = pStm->Read((void*)&nCount, sizeof(ULONG), &cbRead);
  916. if (FAILED(err))
  917. {
  918. ASSERT(false);
  919. return err;
  920. }
  921. ASSERT(cbRead == sizeof(ULONG));
  922. // Read the strings from the stream into the list.
  923. CString sString;
  924. for (UINT k = 0; k < nCount && SUCCEEDED(err); k++)
  925. {
  926. err = LoadStringFromStream(pStm, sString);
  927. sList.AddTail(sString);
  928. }
  929. // Double check that, if we had no errors loading strings,
  930. // all of the strings were correctly added to the list.
  931. if (SUCCEEDED(err) && sList.GetCount() != nCount)
  932. {
  933. err = E_FAIL;
  934. }
  935. return err;
  936. }
  937. /////////////////////////////////////////////////////////////////////
  938. /////////////////////// Message Boxes ///////////////////////////////
  939. /////////////////////////////////////////////////////////////////////
  940. int ADSIEditMessageBox(LPCTSTR lpszText, UINT nType)
  941. {
  942. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  943. CThemeContextActivator activator;
  944. return ::AfxMessageBox(lpszText, nType);
  945. }
  946. int ADSIEditMessageBox(UINT nIDPrompt, UINT nType)
  947. {
  948. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  949. CThemeContextActivator activator;
  950. return ::AfxMessageBox(nIDPrompt, nType);
  951. }
  952. void ADSIEditErrorMessage(PCWSTR pszMessage)
  953. {
  954. ADSIEditMessageBox(pszMessage, MB_OK);
  955. }
  956. void ADSIEditErrorMessage(HRESULT hr)
  957. {
  958. CString s;
  959. GetErrorMessage(hr, s);
  960. ADSIEditMessageBox(s, MB_OK);
  961. }
  962. void ADSIEditErrorMessage(HRESULT hr, UINT nIDPrompt, UINT nType)
  963. {
  964. CString s;
  965. GetErrorMessage(hr, s);
  966. CString szMessage;
  967. szMessage.Format(nIDPrompt, s);
  968. ADSIEditMessageBox(szMessage, MB_OK);
  969. }
  970. /////////////////////////////////////////////////////////////////////
  971. BOOL LoadStringsToComboBox(HINSTANCE hInstance, CComboBox* pCombo,
  972. UINT nStringID, UINT nMaxLen, UINT nMaxAddCount)
  973. {
  974. pCombo->ResetContent();
  975. ASSERT(hInstance != NULL);
  976. WCHAR* szBuf = (WCHAR*)malloc(sizeof(WCHAR)*nMaxLen);
  977. if (!szBuf)
  978. {
  979. return FALSE;
  980. }
  981. // NOTICE-2002/02/28-artm LoadString() used correctly.
  982. // nMaxLen is the length in WCHAR's of szBuf.
  983. if ( ::LoadString(hInstance, nStringID, szBuf, nMaxLen) == 0)
  984. {
  985. free(szBuf);
  986. return FALSE;
  987. }
  988. LPWSTR* lpszArr = (LPWSTR*)malloc(sizeof(LPWSTR*)*nMaxLen);
  989. if (lpszArr)
  990. {
  991. int nArrEntries = 0;
  992. ParseNewLineSeparatedString(szBuf,lpszArr, &nArrEntries);
  993. if (nMaxAddCount < nArrEntries) nArrEntries = nMaxAddCount;
  994. for (int k=0; k<nArrEntries; k++)
  995. pCombo->AddString(lpszArr[k]);
  996. }
  997. if (szBuf)
  998. {
  999. free(szBuf);
  1000. }
  1001. if (lpszArr)
  1002. {
  1003. free(lpszArr);
  1004. }
  1005. return TRUE;
  1006. }
  1007. void ParseNewLineSeparatedString(LPWSTR lpsz,
  1008. LPWSTR* lpszArr,
  1009. int* pnArrEntries)
  1010. {
  1011. static WCHAR lpszSep[] = L"\n";
  1012. *pnArrEntries = 0;
  1013. int k = 0;
  1014. lpszArr[k] = wcstok(lpsz, lpszSep);
  1015. if (lpszArr[k] == NULL)
  1016. return;
  1017. while (TRUE)
  1018. {
  1019. WCHAR* lpszToken = wcstok(NULL, lpszSep);
  1020. if (lpszToken != NULL)
  1021. lpszArr[++k] = lpszToken;
  1022. else
  1023. break;
  1024. }
  1025. *pnArrEntries = k+1;
  1026. }
  1027. void LoadStringArrayFromResource(LPWSTR* lpszArr,
  1028. UINT* nStringIDs,
  1029. int nArrEntries,
  1030. int* pnSuccessEntries)
  1031. {
  1032. CString szTemp;
  1033. *pnSuccessEntries = 0;
  1034. for (int k = 0;k < nArrEntries; k++)
  1035. {
  1036. if (!szTemp.LoadString(nStringIDs[k]))
  1037. {
  1038. lpszArr[k] = NULL;
  1039. continue;
  1040. }
  1041. int iLength = szTemp.GetLength() + 1;
  1042. lpszArr[k] = (LPWSTR)malloc(sizeof(WCHAR)*iLength);
  1043. if (lpszArr[k] != NULL)
  1044. {
  1045. // NOTICE-2002/02/28-artm Using wcscpy() here relies on CString
  1046. // always being null terminated (which it should be).
  1047. wcscpy(lpszArr[k], (LPWSTR)(LPCWSTR)szTemp);
  1048. (*pnSuccessEntries)++;
  1049. }
  1050. }
  1051. }
  1052. ///////////////////////////////////////////////////////////////
  1053. void GetStringArrayFromStringList(CStringList& sList, LPWSTR** ppStrArr, UINT* nCount)
  1054. {
  1055. *nCount = sList.GetCount();
  1056. *ppStrArr = new LPWSTR[*nCount];
  1057. UINT idx = 0;
  1058. POSITION pos = sList.GetHeadPosition();
  1059. while (pos != NULL)
  1060. {
  1061. CString szString = sList.GetNext(pos);
  1062. (*ppStrArr)[idx] = new WCHAR[szString.GetLength() + 1];
  1063. ASSERT((*ppStrArr)[idx] != NULL);
  1064. // NTRAID#NTBUG9--2002/02/28-artm Need to check that mem. allocation succeeded.
  1065. // If memory allocation failed, should not call wcscpy().
  1066. // NOTICE-2002/02/28-artm As long as the memory allocation succeeded for
  1067. // (*ppStrArr)[idx], the copy will succeed correctly (all CStrings are
  1068. // null terminated).
  1069. wcscpy((*ppStrArr)[idx], szString);
  1070. idx++;
  1071. }
  1072. *nCount = idx;
  1073. }
  1074. ////////////////////////////////////////////////////////////////
  1075. ////////////////////////////////////////////////////////////////
  1076. ////////////////////////////////////////////////////////////////
  1077. BEGIN_MESSAGE_MAP(CByteArrayComboBox, CComboBox)
  1078. ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelChange)
  1079. END_MESSAGE_MAP()
  1080. BOOL CByteArrayComboBox::Initialize(CByteArrayDisplay* pDisplay,
  1081. DWORD dwDisplayFlags)
  1082. {
  1083. ASSERT(pDisplay != NULL);
  1084. m_pDisplay = pDisplay;
  1085. //
  1086. // Load the combo box based on the flags given
  1087. //
  1088. if (dwDisplayFlags & BYTE_ARRAY_DISPLAY_HEX)
  1089. {
  1090. CString szHex;
  1091. VERIFY(szHex.LoadString(IDS_HEXADECIMAL));
  1092. int idx = AddString(szHex);
  1093. if (idx != CB_ERR)
  1094. {
  1095. SetItemData(idx, BYTE_ARRAY_DISPLAY_HEX);
  1096. }
  1097. }
  1098. if (dwDisplayFlags & BYTE_ARRAY_DISPLAY_OCT)
  1099. {
  1100. CString szOct;
  1101. VERIFY(szOct.LoadString(IDS_OCTAL));
  1102. int idx = AddString(szOct);
  1103. if (idx != CB_ERR)
  1104. {
  1105. SetItemData(idx, BYTE_ARRAY_DISPLAY_OCT);
  1106. }
  1107. }
  1108. if (dwDisplayFlags & BYTE_ARRAY_DISPLAY_DEC)
  1109. {
  1110. CString szDec;
  1111. VERIFY(szDec.LoadString(IDS_DECIMAL));
  1112. int idx = AddString(szDec);
  1113. if (idx != CB_ERR)
  1114. {
  1115. SetItemData(idx, BYTE_ARRAY_DISPLAY_DEC);
  1116. }
  1117. }
  1118. if (dwDisplayFlags & BYTE_ARRAY_DISPLAY_BIN)
  1119. {
  1120. CString szBin;
  1121. VERIFY(szBin.LoadString(IDS_BINARY));
  1122. int idx = AddString(szBin);
  1123. if (idx != CB_ERR)
  1124. {
  1125. SetItemData(idx, BYTE_ARRAY_DISPLAY_BIN);
  1126. }
  1127. }
  1128. return TRUE;
  1129. }
  1130. DWORD CByteArrayComboBox::GetCurrentDisplay()
  1131. {
  1132. DWORD dwRet = 0;
  1133. int iSel = GetCurSel();
  1134. if (iSel != CB_ERR)
  1135. {
  1136. dwRet = GetItemData(iSel);
  1137. }
  1138. return dwRet;
  1139. }
  1140. void CByteArrayComboBox::SetCurrentDisplay(DWORD dwSel)
  1141. {
  1142. int iCount = GetCount();
  1143. for (int idx = 0; idx < iCount; idx++)
  1144. {
  1145. DWORD dwData = GetItemData(idx);
  1146. if (dwData == dwSel)
  1147. {
  1148. SetCurSel(idx);
  1149. return;
  1150. }
  1151. }
  1152. }
  1153. void CByteArrayComboBox::OnSelChange()
  1154. {
  1155. if (m_pDisplay != NULL)
  1156. {
  1157. int iSel = GetCurSel();
  1158. if (iSel != CB_ERR)
  1159. {
  1160. DWORD dwData = GetItemData(iSel);
  1161. m_pDisplay->OnTypeChange(dwData);
  1162. }
  1163. }
  1164. }
  1165. ////////////////////////////////////////////////////////////////
  1166. CByteArrayEdit::CByteArrayEdit()
  1167. : m_pData(NULL),
  1168. m_dwLength(0),
  1169. CEdit()
  1170. {
  1171. }
  1172. CByteArrayEdit::~CByteArrayEdit()
  1173. {
  1174. }
  1175. BEGIN_MESSAGE_MAP(CByteArrayEdit, CEdit)
  1176. ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
  1177. END_MESSAGE_MAP()
  1178. BOOL CByteArrayEdit::Initialize(CByteArrayDisplay* pDisplay)
  1179. {
  1180. ASSERT(pDisplay != NULL);
  1181. m_pDisplay = pDisplay;
  1182. ConvertToFixedPitchFont(GetSafeHwnd());
  1183. return TRUE;
  1184. }
  1185. DWORD CByteArrayEdit::GetLength()
  1186. {
  1187. return m_dwLength;
  1188. }
  1189. BYTE* CByteArrayEdit::GetDataPtr()
  1190. {
  1191. return m_pData;
  1192. }
  1193. //Pre: ppData != NULL
  1194. //Post: Allocates space for a copy of the byte array at *ppData and
  1195. // copies it. Returns the size of *ppData in bytes. Note that
  1196. // the copied byte array can be NULL (e.g. *ppData will equal NULL).
  1197. DWORD CByteArrayEdit::GetDataCopy(BYTE** ppData)
  1198. {
  1199. if (m_pData != NULL && m_dwLength > 0)
  1200. {
  1201. *ppData = new BYTE[m_dwLength];
  1202. if (*ppData != NULL)
  1203. {
  1204. memcpy(*ppData, m_pData, m_dwLength);
  1205. return m_dwLength;
  1206. }
  1207. }
  1208. *ppData = NULL;
  1209. return 0;
  1210. }
  1211. void CByteArrayEdit::SetData(BYTE* pData, DWORD dwLength)
  1212. {
  1213. if (m_pData != NULL)
  1214. {
  1215. delete[] m_pData;
  1216. m_pData = NULL;
  1217. m_dwLength = 0;
  1218. }
  1219. if (dwLength > 0 && pData != NULL)
  1220. {
  1221. //
  1222. // Set the new data
  1223. //
  1224. m_pData = new BYTE[dwLength];
  1225. if (m_pData != NULL)
  1226. {
  1227. memcpy(m_pData, pData, dwLength);
  1228. m_dwLength = dwLength;
  1229. }
  1230. }
  1231. }
  1232. void CByteArrayEdit::OnChangeDisplay()
  1233. {
  1234. CString szOldDisplay;
  1235. GetWindowText(szOldDisplay);
  1236. if (!szOldDisplay.IsEmpty())
  1237. {
  1238. BYTE* pByte = NULL;
  1239. DWORD dwLength = 0;
  1240. switch (m_pDisplay->GetPreviousDisplay())
  1241. {
  1242. case BYTE_ARRAY_DISPLAY_HEX :
  1243. dwLength = HexStringToByteArray(szOldDisplay, &pByte);
  1244. break;
  1245. case BYTE_ARRAY_DISPLAY_OCT :
  1246. dwLength = OctalStringToByteArray(szOldDisplay, &pByte);
  1247. break;
  1248. case BYTE_ARRAY_DISPLAY_DEC :
  1249. dwLength = DecimalStringToByteArray(szOldDisplay, &pByte);
  1250. break;
  1251. case BYTE_ARRAY_DISPLAY_BIN :
  1252. dwLength = BinaryStringToByteArray(szOldDisplay, &pByte);
  1253. break;
  1254. default :
  1255. ASSERT(FALSE);
  1256. break;
  1257. }
  1258. if (pByte != NULL && dwLength != (DWORD)-1)
  1259. {
  1260. SetData(pByte, dwLength);
  1261. delete[] pByte;
  1262. pByte = 0;
  1263. }
  1264. }
  1265. CString szDisplayValue;
  1266. switch (m_pDisplay->GetCurrentDisplay())
  1267. {
  1268. case BYTE_ARRAY_DISPLAY_HEX :
  1269. ByteArrayToHexString(GetDataPtr(), GetLength(), szDisplayValue);
  1270. break;
  1271. case BYTE_ARRAY_DISPLAY_OCT :
  1272. ByteArrayToOctalString(GetDataPtr(), GetLength(), szDisplayValue);
  1273. break;
  1274. case BYTE_ARRAY_DISPLAY_DEC :
  1275. ByteArrayToDecimalString(GetDataPtr(), GetLength(), szDisplayValue);
  1276. break;
  1277. case BYTE_ARRAY_DISPLAY_BIN :
  1278. ByteArrayToBinaryString(GetDataPtr(), GetLength(), szDisplayValue);
  1279. break;
  1280. default :
  1281. ASSERT(FALSE);
  1282. break;
  1283. }
  1284. SetWindowText(szDisplayValue);
  1285. }
  1286. void CByteArrayEdit::OnChange()
  1287. {
  1288. if (m_pDisplay != NULL)
  1289. {
  1290. m_pDisplay->OnEditChange();
  1291. }
  1292. }
  1293. ////////////////////////////////////////////////////////////////
  1294. BOOL CByteArrayDisplay::Initialize(UINT nEditCtrl,
  1295. UINT nComboCtrl,
  1296. DWORD dwDisplayFlags,
  1297. DWORD dwDefaultDisplay,
  1298. CWnd* pParent,
  1299. DWORD dwMaxSizeLimit,
  1300. UINT nMaxSizeMessageID)
  1301. {
  1302. //
  1303. // Initialize the edit control
  1304. //
  1305. VERIFY(m_edit.SubclassDlgItem(nEditCtrl, pParent));
  1306. VERIFY(m_edit.Initialize(this));
  1307. //
  1308. // Initialize the combo box
  1309. //
  1310. VERIFY(m_combo.SubclassDlgItem(nComboCtrl, pParent));
  1311. VERIFY(m_combo.Initialize(this, dwDisplayFlags));
  1312. m_dwMaxSizeBytes = dwMaxSizeLimit;
  1313. m_nMaxSizeMessage = nMaxSizeMessageID;
  1314. //
  1315. // Selects the default display in the combo box and
  1316. // populates the edit field
  1317. //
  1318. SetCurrentDisplay(dwDefaultDisplay);
  1319. m_dwPreviousDisplay = dwDefaultDisplay;
  1320. m_combo.SetCurrentDisplay(dwDefaultDisplay);
  1321. m_edit.OnChangeDisplay();
  1322. return TRUE;
  1323. }
  1324. void CByteArrayDisplay::OnEditChange()
  1325. {
  1326. }
  1327. void CByteArrayDisplay::OnTypeChange(DWORD dwDisplayType)
  1328. {
  1329. SetCurrentDisplay(dwDisplayType);
  1330. // NOTICE-2002/05/01-artm ntraid#ntbug9-598051
  1331. // Only need to change the value displayed if the underlying
  1332. // byte array is beneath our maximum display size. Otherwise,
  1333. // the current message will be that the value is too large for
  1334. // this editor (and we should keep it that way).
  1335. if (m_edit.GetLength() <= m_dwMaxSizeBytes)
  1336. {
  1337. m_edit.OnChangeDisplay();
  1338. }
  1339. }
  1340. void CByteArrayDisplay::ClearData()
  1341. {
  1342. m_edit.SetData(NULL, 0);
  1343. m_edit.OnChangeDisplay();
  1344. }
  1345. void CByteArrayDisplay::SetData(BYTE* pData, DWORD dwLength)
  1346. {
  1347. if (dwLength > m_dwMaxSizeBytes)
  1348. {
  1349. //
  1350. // If the data is too large to load into the edit box
  1351. // load the provided message and set the edit box to read only
  1352. //
  1353. CString szMessage;
  1354. VERIFY(szMessage.LoadString(m_nMaxSizeMessage));
  1355. m_edit.SetWindowText(szMessage);
  1356. m_edit.SetReadOnly();
  1357. //
  1358. // Still need to set the data in the edit box even though we are not going to show it
  1359. //
  1360. m_edit.SetData(pData, dwLength);
  1361. }
  1362. else
  1363. {
  1364. m_edit.SetReadOnly(FALSE);
  1365. m_edit.SetData(pData, dwLength);
  1366. m_edit.OnChangeDisplay();
  1367. }
  1368. }
  1369. DWORD CByteArrayDisplay::GetData(BYTE** ppData)
  1370. {
  1371. CString szDisplay;
  1372. m_edit.GetWindowText(szDisplay);
  1373. if (!szDisplay.IsEmpty())
  1374. {
  1375. BYTE* pByte = NULL;
  1376. DWORD dwLength = 0;
  1377. switch (GetCurrentDisplay())
  1378. {
  1379. case BYTE_ARRAY_DISPLAY_HEX :
  1380. dwLength = HexStringToByteArray(szDisplay, &pByte);
  1381. break;
  1382. case BYTE_ARRAY_DISPLAY_OCT :
  1383. dwLength = OctalStringToByteArray(szDisplay, &pByte);
  1384. break;
  1385. case BYTE_ARRAY_DISPLAY_DEC :
  1386. dwLength = DecimalStringToByteArray(szDisplay, &pByte);
  1387. break;
  1388. case BYTE_ARRAY_DISPLAY_BIN :
  1389. dwLength = BinaryStringToByteArray(szDisplay, &pByte);
  1390. break;
  1391. default :
  1392. ASSERT(FALSE);
  1393. break;
  1394. }
  1395. if (pByte != NULL && dwLength != (DWORD)-1)
  1396. {
  1397. m_edit.SetData(pByte, dwLength);
  1398. delete[] pByte;
  1399. pByte = 0;
  1400. }
  1401. }
  1402. return m_edit.GetDataCopy(ppData);
  1403. }
  1404. void CByteArrayDisplay::SetCurrentDisplay(DWORD dwCurrentDisplay)
  1405. {
  1406. m_dwPreviousDisplay = m_dwCurrentDisplay;
  1407. m_dwCurrentDisplay = dwCurrentDisplay;
  1408. }
  1409. ////////////////////////////////////////////////////////////////////////////////
  1410. // String to byte array conversion routines
  1411. //
  1412. // HexStringToByteArray_0x():
  1413. //
  1414. // Conversion function for hex strings in format 0x00 to byte arrays.
  1415. //
  1416. // Return Values:
  1417. // E_POINTER --- bad pointer passed as parameter
  1418. // E_FAIL --- the hex string had an invalid format, conversion failed
  1419. // S_OK --- conversion succeeded
  1420. //
  1421. HRESULT HexStringToByteArray_0x(PCWSTR pszHexString, BYTE** ppByte, DWORD &nCount)
  1422. {
  1423. HRESULT hr = S_OK;
  1424. nCount = 0;
  1425. // Should never happen . . .
  1426. ASSERT(ppByte);
  1427. ASSERT(pszHexString);
  1428. if (!pszHexString || !ppByte)
  1429. {
  1430. return E_POINTER;
  1431. }
  1432. *ppByte = NULL;
  1433. DWORD count = 0;
  1434. int index = 0, result = 0;
  1435. int max = 0;
  1436. // Flag to mark the string as having non-whitespace characters.
  1437. bool isEmpty = true;
  1438. // Determine the maximum number of octet sequences (0x00 format) the string
  1439. // contains.
  1440. for (index = 0; pszHexString[index] != NULL; ++index)
  1441. {
  1442. switch (pszHexString[index])
  1443. {
  1444. case L' ':
  1445. case L'\t':
  1446. // Whitespace, do nothing.
  1447. break;
  1448. case L'x':
  1449. // Increase count of possible octet sequences.
  1450. ++max;
  1451. break;
  1452. default:
  1453. isEmpty = false;
  1454. break;
  1455. }// end switch
  1456. }
  1457. if (max == 0 && !isEmpty)
  1458. {
  1459. // Bad format for string.
  1460. return E_FAIL;
  1461. }
  1462. // Convert any octet sequences to bytes.
  1463. while (max > 0) // false loop, only executed once
  1464. {
  1465. *ppByte = new BYTE[max];
  1466. if (NULL == *ppByte)
  1467. {
  1468. hr = E_OUTOFMEMORY;
  1469. break;
  1470. }
  1471. ZeroMemory(*ppByte, max);
  1472. index = 0;
  1473. // This is a little weird. Originally I was using BYTE's for
  1474. // high and low, figuring that hex characters easily fit in a byte.
  1475. // However, swscanf() wrote to the high and low as if they were USHORT,
  1476. // maybe because it is the wide version of the function (and the string
  1477. // is wide). Consequently, swscanf() converted high, then converted low
  1478. // with the side effect of overwriting high to be 0. Declaring them as
  1479. // USHORT's makes everything work as intended.
  1480. USHORT high, low;
  1481. do
  1482. {
  1483. ASSERT(count <= max);
  1484. high = 0;
  1485. low = 0;
  1486. // Skip white space.
  1487. while (pszHexString[index] == ' ' || pszHexString[index] == '\t')
  1488. {
  1489. ++index;
  1490. }
  1491. // If we're at the end of the string, we converted it w/out problem.
  1492. if (pszHexString[index] == NULL)
  1493. {
  1494. hr = S_OK;
  1495. break;
  1496. }
  1497. // Try to convert an octet sequence to a byte.
  1498. // Enforce having exactly 0x00 or 0x0 format.
  1499. result = swscanf(
  1500. &(pszHexString[index]),
  1501. L"0x%1x%1x",
  1502. &high,
  1503. &low);
  1504. if (result == 2)
  1505. {
  1506. // Conversion was successful, combine high and low bits of byte.
  1507. // Since high and low are USHORT, convert them to a BYTE.
  1508. (*ppByte)[count] = static_cast<BYTE>((high << 4) + low);
  1509. ++count;
  1510. // Move past the 0x00.
  1511. index += 4;
  1512. }
  1513. else if(result == 1)
  1514. {
  1515. // Conversion was successful, but only read single character (always in low bits).
  1516. (*ppByte)[count] = static_cast<BYTE>(high);
  1517. ++count;
  1518. // Move past the 0x0.
  1519. index += 3;
  1520. }
  1521. else
  1522. {
  1523. hr = E_FAIL;
  1524. }
  1525. } while (SUCCEEDED(hr));
  1526. // Always break out of loop.
  1527. break;
  1528. }
  1529. if (SUCCEEDED(hr))
  1530. {
  1531. nCount = count;
  1532. }
  1533. else
  1534. {
  1535. delete [] *ppByte;
  1536. *ppByte = NULL;
  1537. }
  1538. return hr;
  1539. }
  1540. //
  1541. // HexStringToByteArray():
  1542. //
  1543. // Conversion function for hex strings in format FF BC to byte arrays.
  1544. //
  1545. DWORD HexStringToByteArray(PCWSTR pszHexString, BYTE** ppByte)
  1546. {
  1547. CString szHexString = pszHexString;
  1548. BYTE* pToLargeArray = new BYTE[szHexString.GetLength()];
  1549. if (pToLargeArray == NULL)
  1550. {
  1551. *ppByte = NULL;
  1552. return (DWORD)-1;
  1553. }
  1554. UINT nByteCount = 0;
  1555. while (!szHexString.IsEmpty())
  1556. {
  1557. //
  1558. // Hex strings should always come 2 characters per byte
  1559. //
  1560. CString szTemp = szHexString.Left(2);
  1561. int iTempByte = 0;
  1562. // NOTICE-NTRAID#NTBUG9-560778-2002/03/01-artm Check the return value of swscanf().
  1563. // Function could fail if characters are in szTemp
  1564. // that are out of range (e.g. letters > f).
  1565. int result = swscanf(szTemp, L"%X", &iTempByte);
  1566. if (result == 1 &&
  1567. iTempByte <= 0xff)
  1568. {
  1569. pToLargeArray[nByteCount++] = iTempByte & 0xff;
  1570. }
  1571. else
  1572. {
  1573. //
  1574. // Format hex error
  1575. //
  1576. ADSIEditMessageBox(IDS_FORMAT_HEX_ERROR, MB_OK);
  1577. delete[] pToLargeArray;
  1578. pToLargeArray = NULL;
  1579. return (DWORD)-1;
  1580. }
  1581. //
  1582. // Take off the value retrieved and the trailing space
  1583. //
  1584. szHexString = szHexString.Right(szHexString.GetLength() - 3);
  1585. }
  1586. *ppByte = new BYTE[nByteCount];
  1587. if (*ppByte == NULL)
  1588. {
  1589. delete[] pToLargeArray;
  1590. pToLargeArray = NULL;
  1591. return (DWORD)-1;
  1592. }
  1593. // NOTICE-2002/03/01-artm The size of pToLargeArray is
  1594. // always > nByteCount; size of ppByte == nByteCount.
  1595. memcpy(*ppByte, pToLargeArray, nByteCount);
  1596. delete[] pToLargeArray;
  1597. pToLargeArray = NULL;
  1598. return nByteCount;
  1599. }
  1600. void ByteArrayToHexString(BYTE* pByte, DWORD dwLength, CString& szHexString)
  1601. {
  1602. szHexString.Empty();
  1603. for (DWORD dwIdx = 0; dwIdx < dwLength; dwIdx++)
  1604. {
  1605. CString szTempString;
  1606. szTempString.Format(L"%2.2X", pByte[dwIdx]);
  1607. if (dwIdx != 0)
  1608. {
  1609. szHexString += L" ";
  1610. }
  1611. szHexString += szTempString;
  1612. }
  1613. }
  1614. DWORD OctalStringToByteArray(PCWSTR pszOctString, BYTE** ppByte)
  1615. {
  1616. CString szOctString = pszOctString;
  1617. BYTE* pToLargeArray = new BYTE[szOctString.GetLength()];
  1618. if (pToLargeArray == NULL)
  1619. {
  1620. *ppByte = NULL;
  1621. return (DWORD)-1;
  1622. }
  1623. UINT nByteCount = 0;
  1624. while (!szOctString.IsEmpty())
  1625. {
  1626. //
  1627. // Octal strings should always come 2 characters per byte
  1628. //
  1629. CString szTemp = szOctString.Left(3);
  1630. int iTempByte = 0;
  1631. // NOTICE-NTRAID#NTBUG9-560778-2002/03/01-artm Check the return value of swscanf().
  1632. // Function could fail if characters are in szTemp
  1633. // that are out of range (e.g. letters > f).
  1634. int result = swscanf(szTemp, L"%o", &iTempByte);
  1635. if (result == 1 &&
  1636. iTempByte <= 0xff)
  1637. {
  1638. pToLargeArray[nByteCount++] = iTempByte & 0xff;
  1639. }
  1640. else
  1641. {
  1642. //
  1643. // Format octal error
  1644. //
  1645. ADSIEditMessageBox(IDS_FORMAT_OCTAL_ERROR, MB_OK);
  1646. delete[] pToLargeArray;
  1647. pToLargeArray = NULL;
  1648. return (DWORD)-1;
  1649. }
  1650. //
  1651. // Take off the value retrieved and the trailing space
  1652. //
  1653. szOctString = szOctString.Right(szOctString.GetLength() - 4);
  1654. }
  1655. *ppByte = new BYTE[nByteCount];
  1656. if (*ppByte == NULL)
  1657. {
  1658. delete[] pToLargeArray;
  1659. pToLargeArray = NULL;
  1660. return (DWORD)-1;
  1661. }
  1662. // NOTICE-2002/03/01-artm The size of pToLargeArray is
  1663. // always > nByteCount; size of ppByte == nByteCount.
  1664. memcpy(*ppByte, pToLargeArray, nByteCount);
  1665. delete[] pToLargeArray;
  1666. pToLargeArray = NULL;
  1667. return nByteCount;
  1668. }
  1669. void ByteArrayToOctalString(BYTE* pByte, DWORD dwLength, CString& szOctString)
  1670. {
  1671. szOctString.Empty();
  1672. for (DWORD dwIdx = 0; dwIdx < dwLength; dwIdx++)
  1673. {
  1674. CString szTempString;
  1675. szTempString.Format(L"%3.3o", pByte[dwIdx]);
  1676. if (dwIdx != 0)
  1677. {
  1678. szOctString += L" ";
  1679. }
  1680. szOctString += szTempString;
  1681. }
  1682. }
  1683. DWORD DecimalStringToByteArray(PCWSTR pszDecString, BYTE** ppByte)
  1684. {
  1685. CString szDecString = pszDecString;
  1686. BYTE* pToLargeArray = new BYTE[szDecString.GetLength()];
  1687. if (pToLargeArray == NULL)
  1688. {
  1689. *ppByte = NULL;
  1690. return 0;
  1691. }
  1692. UINT nByteCount = 0;
  1693. while (!szDecString.IsEmpty())
  1694. {
  1695. //
  1696. // Hex strings should always come 2 characters per byte
  1697. //
  1698. CString szTemp = szDecString.Left(3);
  1699. int iTempByte = 0;
  1700. // NOTICE-NTRAID#NTBUG9-560778-2002/03/01-artm Check the return value of swscanf().
  1701. // Function could fail if characters are in szTemp
  1702. // that are out of range (e.g. letters > f).
  1703. int result = swscanf(szTemp, L"%d", &iTempByte);
  1704. if (result == 1 &&
  1705. iTempByte <= 0xff)
  1706. {
  1707. pToLargeArray[nByteCount++] = iTempByte & 0xff;
  1708. }
  1709. else
  1710. {
  1711. //
  1712. // Format decimal error
  1713. //
  1714. ADSIEditMessageBox(IDS_FORMAT_DECIMAL_ERROR, MB_OK);
  1715. delete[] pToLargeArray;
  1716. pToLargeArray = NULL;
  1717. return (DWORD)-1;
  1718. }
  1719. //
  1720. // Take off the value retrieved and the trailing space
  1721. //
  1722. szDecString = szDecString.Right(szDecString.GetLength() - 4);
  1723. }
  1724. *ppByte = new BYTE[nByteCount];
  1725. if (*ppByte == NULL)
  1726. {
  1727. delete[] pToLargeArray;
  1728. pToLargeArray = NULL;
  1729. return (DWORD)-1;
  1730. }
  1731. // NOTICE-2002/03/01-artm The size of pToLargeArray is
  1732. // always > nByteCount; size of ppByte == nByteCount.
  1733. memcpy(*ppByte, pToLargeArray, nByteCount);
  1734. delete[] pToLargeArray;
  1735. pToLargeArray = NULL;
  1736. return nByteCount;
  1737. }
  1738. void ByteArrayToDecimalString(BYTE* pByte, DWORD dwLength, CString& szDecString)
  1739. {
  1740. szDecString.Empty();
  1741. for (DWORD dwIdx = 0; dwIdx < dwLength; dwIdx++)
  1742. {
  1743. CString szTempString;
  1744. szTempString.Format(L"%3.3d", pByte[dwIdx]);
  1745. if (dwIdx != 0)
  1746. {
  1747. szDecString += L" ";
  1748. }
  1749. szDecString += szTempString;
  1750. }
  1751. }
  1752. // REVIEW-ARTM This function (and maybe all the conversion functions) needs a rewrite.
  1753. // It makes a bunch of assumptions about the format of the string w/out checking said
  1754. // assumptions, and it does not behave the same way as editing in hex mode.
  1755. DWORD BinaryStringToByteArray(PCWSTR pszBinString, BYTE** ppByte)
  1756. {
  1757. ASSERT(ppByte);
  1758. *ppByte = NULL;
  1759. CString szBinString = pszBinString;
  1760. BYTE* pToLargeArray = new BYTE[szBinString.GetLength()];
  1761. if (pToLargeArray == NULL)
  1762. {
  1763. return (DWORD)-1;
  1764. }
  1765. UINT nByteCount = 0;
  1766. bool format_error = false;
  1767. // Remove leading white space.
  1768. szBinString.TrimLeft();
  1769. while (!format_error && !szBinString.IsEmpty())
  1770. {
  1771. // If the string ended with a bunch of white space, it might now be
  1772. // empty. In that case, we don't want to return an error b/c the
  1773. // conversion was successful.
  1774. if (szBinString.IsEmpty())
  1775. {
  1776. break;
  1777. }
  1778. //
  1779. // Binary strings should always come 8 characters per byte
  1780. //
  1781. BYTE chByte = 0;
  1782. CString szTemp = szBinString.Left(8);
  1783. // NOTICE-NTRAID#NTBUG9-560868-2002/05/06-artm Verify substring length of 8.
  1784. // This ensures that we are working with 8 characters at a time, but does nothing
  1785. // for checking that the 8 characters are either '1' or '0' (see case statement
  1786. // below for that checking).
  1787. if (szTemp.GetLength() != 8)
  1788. {
  1789. nByteCount = static_cast<DWORD>(-1);
  1790. break;
  1791. }
  1792. for (int idx = 0; idx < 8 && !format_error; idx++)
  1793. {
  1794. switch (szTemp[idx])
  1795. {
  1796. case L'1':
  1797. // NOTICE-2002/04/29-artm fixed ntraid#ntbug9-567210
  1798. // Before was not combining partial result with the new bit
  1799. // to set.
  1800. // Also, previously was shifting one place too many.
  1801. chByte |= 0x1 << (8 - idx - 1);
  1802. break;
  1803. case L'0':
  1804. // Don't need to do anything, bit set to 0 by default.
  1805. break;
  1806. default:
  1807. format_error = true;
  1808. break;
  1809. }// end switch
  1810. }
  1811. if (!format_error)
  1812. {
  1813. pToLargeArray[nByteCount++] = chByte;
  1814. //
  1815. // Take off the value retrieved.
  1816. //
  1817. szBinString = szBinString.Right(szBinString.GetLength() - 8);
  1818. // Remove trailing white space (now at front of string).
  1819. szBinString.TrimLeft();
  1820. }
  1821. else
  1822. {
  1823. nByteCount = static_cast<DWORD>(-1);
  1824. }
  1825. }
  1826. if (nByteCount > 0 && nByteCount != static_cast<DWORD>(-1))
  1827. {
  1828. *ppByte = new BYTE[nByteCount];
  1829. if (*ppByte)
  1830. {
  1831. // NOTICE-2002/03/01-artm nByteCount is size of *ppByte,
  1832. // and pToLargeArray is roughly 8 times as big as nByteCount.
  1833. memcpy(*ppByte, pToLargeArray, nByteCount);
  1834. }
  1835. else
  1836. {
  1837. nByteCount = static_cast<DWORD>(-1);
  1838. }
  1839. }
  1840. delete[] pToLargeArray;
  1841. return nByteCount;
  1842. }
  1843. void ByteArrayToBinaryString(BYTE* pByte, DWORD dwLength, CString& szBinString)
  1844. {
  1845. szBinString.Empty();
  1846. for (DWORD dwIdx = 0; dwIdx < dwLength; dwIdx++)
  1847. {
  1848. CString szTempString;
  1849. BYTE chTemp = pByte[dwIdx];
  1850. for (size_t idx = 0; idx < sizeof(BYTE) * 8; idx++)
  1851. {
  1852. if ((chTemp & (0x1 << idx)) == 0)
  1853. {
  1854. szTempString = L'0' + szTempString;
  1855. }
  1856. else
  1857. {
  1858. szTempString = L'1' + szTempString;
  1859. }
  1860. }
  1861. if (dwIdx != 0)
  1862. {
  1863. szBinString += L" ";
  1864. }
  1865. szBinString += szTempString;
  1866. }
  1867. }
  1868. //////////////////////////////////////////////////////////////////////////////
  1869. BOOL LoadFileAsByteArray(PCWSTR pszPath, LPBYTE* ppByteArray, DWORD* pdwSize)
  1870. {
  1871. if (ppByteArray == NULL ||
  1872. pdwSize == NULL)
  1873. {
  1874. return FALSE;
  1875. }
  1876. CFile file;
  1877. if (!file.Open(pszPath, CFile::modeRead | CFile::shareDenyNone | CFile::typeBinary))
  1878. {
  1879. return FALSE;
  1880. }
  1881. *pdwSize = file.GetLength();
  1882. *ppByteArray = new BYTE[*pdwSize];
  1883. if (*ppByteArray == NULL)
  1884. {
  1885. return FALSE;
  1886. }
  1887. UINT uiCount = file.Read(*ppByteArray, *pdwSize);
  1888. ASSERT(uiCount == *pdwSize);
  1889. return TRUE;
  1890. }
  1891. //+---------------------------------------------------------------------------
  1892. //
  1893. // Function: ConvertToFixedPitchFont
  1894. //
  1895. // Synopsis: Converts a windows font to a fixed pitch font.
  1896. //
  1897. // Arguments: [hwnd] -- IN window handle
  1898. //
  1899. // Returns: BOOL
  1900. //
  1901. // History: 7/15/1995 RaviR Created
  1902. //
  1903. //----------------------------------------------------------------------------
  1904. BOOL ConvertToFixedPitchFont(HWND hwnd)
  1905. {
  1906. LOGFONT lf;
  1907. HFONT hFont = reinterpret_cast<HFONT>(::SendMessage(hwnd, WM_GETFONT, 0, 0));
  1908. if (!GetObject(hFont, sizeof(LOGFONT), &lf))
  1909. {
  1910. return FALSE;
  1911. }
  1912. lf.lfQuality = PROOF_QUALITY;
  1913. lf.lfPitchAndFamily &= ~VARIABLE_PITCH;
  1914. lf.lfPitchAndFamily |= FIXED_PITCH;
  1915. lf.lfFaceName[0] = L'\0';
  1916. HFONT hf = CreateFontIndirect(&lf);
  1917. if (hf == NULL)
  1918. {
  1919. return FALSE;
  1920. }
  1921. ::SendMessage(hwnd, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE); // macro in windowsx.h
  1922. return TRUE;
  1923. }
  1924. //////////////////////////////////////////////////////////////////
  1925. // Theming support
  1926. HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
  1927. {
  1928. PROPSHEETPAGE_V3 sp_v3 = {0};
  1929. CopyMemory (&sp_v3, psp, psp->dwSize);
  1930. sp_v3.dwSize = sizeof(sp_v3);
  1931. return (::CreatePropertySheetPage(&sp_v3));
  1932. }