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

847 lines
18 KiB

  1. // Copyright (C) 1999 Microsoft Corporation
  2. //
  3. // Implementation of ICloneSecurityPrincipal
  4. //
  5. // sburns 5-10-99
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "implmain.hpp"
  9. #include "common.hpp"
  10. const size_t NUMBER_OF_AUTOMATION_INTERFACES = 3;
  11. CloneSecurityPrincipal::CloneSecurityPrincipal()
  12. :
  13. connection(0),
  14. refcount(1), // implicit AddRef
  15. m_pSID(NULL)
  16. {
  17. LOG_CTOR(CloneSecurityPrincipal);
  18. m_ppTypeInfo = new ITypeInfo*[NUMBER_OF_AUTOMATION_INTERFACES];
  19. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  20. {
  21. m_ppTypeInfo[i] = NULL;
  22. }
  23. ITypeLib *ptl = 0;
  24. HRESULT hr = LoadRegTypeLib(LIBID_CloneSecurityPrincipalLib, 1, 0, 0, &ptl);
  25. if (SUCCEEDED(hr))
  26. {
  27. ptl->GetTypeInfoOfGuid(IID_ICloneSecurityPrincipal, &(m_ppTypeInfo[0]));
  28. ptl->GetTypeInfoOfGuid(IID_IADsSID, &(m_ppTypeInfo[1]));
  29. ptl->GetTypeInfoOfGuid(IID_IADsError, &(m_ppTypeInfo[2]));
  30. ptl->Release();
  31. }
  32. }
  33. CloneSecurityPrincipal::~CloneSecurityPrincipal()
  34. {
  35. LOG_DTOR(CloneSecurityPrincipal);
  36. ASSERT(refcount == 0);
  37. delete connection;
  38. if ( m_pSID )
  39. FreeADsMem( m_pSID );
  40. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  41. {
  42. m_ppTypeInfo[i]->Release();
  43. }
  44. delete[] m_ppTypeInfo;
  45. }
  46. HRESULT __stdcall
  47. CloneSecurityPrincipal::QueryInterface(REFIID riid, void **ppv)
  48. {
  49. LOG_FUNCTION(CloneSecurityPrincipal::QueryInterface);
  50. if (riid == IID_IUnknown)
  51. {
  52. LOG(L"IUnknown");
  53. *ppv = (IUnknown*)(ICloneSecurityPrincipal*)(this);
  54. }
  55. else if (riid == IID_ICloneSecurityPrincipal)
  56. {
  57. LOG(L"ICloneSecurityPrincipal");
  58. *ppv = static_cast<ICloneSecurityPrincipal*>(this);
  59. }
  60. else if (riid == IID_IADsSID)
  61. {
  62. LOG(L"IADsSID");
  63. *ppv = static_cast<IADsSID*>(this);
  64. }
  65. else if (riid == IID_IADsError)
  66. {
  67. LOG(L"IADsError");
  68. *ppv = static_cast<IADsError*>(this);
  69. }
  70. else if (riid == IID_IDispatch && m_ppTypeInfo[0])
  71. {
  72. LOG(L"IDispatch");
  73. *ppv = (IDispatch*)(ICloneSecurityPrincipal*)(this);
  74. }
  75. else if (riid == IID_ISupportErrorInfo)
  76. {
  77. LOG(L"ISupportErrorInfo");
  78. *ppv = (ISupportErrorInfo*)(this);
  79. }
  80. else
  81. {
  82. LOG(L"unknown");
  83. return (*ppv = 0), E_NOINTERFACE;
  84. }
  85. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  86. return S_OK;
  87. }
  88. ULONG __stdcall
  89. CloneSecurityPrincipal::AddRef(void)
  90. {
  91. LOG_ADDREF(CloneSecurityPrincipal);
  92. return Win::InterlockedIncrement(refcount);
  93. }
  94. ULONG __stdcall
  95. CloneSecurityPrincipal::Release(void)
  96. {
  97. LOG_RELEASE(CloneSecurityPrincipal);
  98. if (Win::InterlockedDecrement(refcount) == 0)
  99. {
  100. delete this;
  101. return 0;
  102. }
  103. return refcount;
  104. }
  105. HRESULT __stdcall
  106. CloneSecurityPrincipal::GetTypeInfoCount(UINT *pcti)
  107. {
  108. LOG_FUNCTION(CloneSecurityPrincipal::GetTypeInfoCount);
  109. if (pcti == 0)
  110. {
  111. return E_POINTER;
  112. }
  113. *pcti = 1;
  114. return S_OK;
  115. }
  116. HRESULT __stdcall
  117. CloneSecurityPrincipal::GetTypeInfo(UINT cti, LCID, ITypeInfo **ppti)
  118. {
  119. LOG_FUNCTION(CloneSecurityPrincipal::GetTypeInfo);
  120. if (ppti == 0)
  121. {
  122. return E_POINTER;
  123. }
  124. if (cti != 0)
  125. {
  126. *ppti = 0;
  127. return DISP_E_BADINDEX;
  128. }
  129. (*ppti = m_ppTypeInfo[0])->AddRef();
  130. return S_OK;
  131. }
  132. HRESULT __stdcall
  133. CloneSecurityPrincipal::GetIDsOfNames(
  134. REFIID riid,
  135. OLECHAR **prgpsz,
  136. UINT cNames,
  137. LCID lcid,
  138. DISPID *prgids)
  139. {
  140. LOG_FUNCTION(CloneSecurityPrincipal::GetIDsOfNames);
  141. HRESULT hr = S_OK;
  142. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  143. {
  144. hr = (m_ppTypeInfo[i])->GetIDsOfNames(prgpsz, cNames, prgids);
  145. if (SUCCEEDED(hr) || DISP_E_UNKNOWNNAME != hr)
  146. break;
  147. }
  148. return hr;
  149. }
  150. HRESULT __stdcall
  151. CloneSecurityPrincipal::Invoke(
  152. DISPID id,
  153. REFIID riid,
  154. LCID lcid,
  155. WORD wFlags,
  156. DISPPARAMS *params,
  157. VARIANT *pVarResult,
  158. EXCEPINFO *pei,
  159. UINT *puArgErr)
  160. {
  161. LOG_FUNCTION(CloneSecurityPrincipal::Invoke);
  162. HRESULT hr = S_OK;
  163. IDispatch *pDispatch[NUMBER_OF_AUTOMATION_INTERFACES] =
  164. {
  165. (IDispatch*)(ICloneSecurityPrincipal *)(this),
  166. (IDispatch*)(IADsSID *)(this),
  167. (IDispatch*)(IADsError *)(this)
  168. };
  169. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  170. {
  171. hr = (m_ppTypeInfo[i])->Invoke(
  172. pDispatch[i],
  173. id,
  174. wFlags,
  175. params,
  176. pVarResult,
  177. pei,
  178. puArgErr);
  179. if (DISP_E_MEMBERNOTFOUND != hr)
  180. break;
  181. }
  182. return hr;
  183. }
  184. HRESULT __stdcall
  185. CloneSecurityPrincipal::InterfaceSupportsErrorInfo(const IID& iid)
  186. {
  187. LOG_FUNCTION(CloneSecurityPrincipal::InterfaceSupportsErrorInfo);
  188. if (iid == IID_ICloneSecurityPrincipal ||
  189. iid == IID_IADsSID ||
  190. iid == IID_IADsError)
  191. {
  192. return S_OK;
  193. }
  194. return S_FALSE;
  195. }
  196. HRESULT __stdcall
  197. CloneSecurityPrincipal::Connect(
  198. BSTR srcDC,
  199. BSTR srcDomain,
  200. BSTR dstDC,
  201. BSTR dstDomain)
  202. {
  203. LOG_FUNCTION(CloneSecurityPrincipal::Connect);
  204. delete connection;
  205. connection = new Connection();
  206. // Even though a null parameter is technically illegal (the types are
  207. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  208. // prefer to pass null pointers instead of empty BSTRs
  209. return connection->Connect(
  210. srcDC ? srcDC : L"",
  211. srcDomain ? srcDomain : L"",
  212. dstDC ? dstDC : L"",
  213. dstDomain ? dstDomain : L"");
  214. }
  215. HRESULT __stdcall
  216. CloneSecurityPrincipal::AddSidHistory(
  217. BSTR srcPrincipalSamName,
  218. BSTR dstPrincipalSamName,
  219. long flags)
  220. {
  221. LOG_FUNCTION(CloneSecurityPrincipal::AddSidHistory);
  222. // Even though a null parameter is technically illegal (the types are
  223. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  224. // prefer to pass null pointers instead of empty BSTRs
  225. return
  226. DoAddSidHistory(
  227. srcPrincipalSamName ? srcPrincipalSamName : L"",
  228. dstPrincipalSamName ? dstPrincipalSamName : L"",
  229. flags);
  230. }
  231. HRESULT __stdcall
  232. CloneSecurityPrincipal::CopyDownlevelUserProperties(
  233. BSTR srcSamName,
  234. BSTR dstSamName,
  235. long flags)
  236. {
  237. LOG_FUNCTION(CloneSecurityPrincipal::CopyDownlevelUserProperties);
  238. // Even though a null parameter is technically illegal (the types are
  239. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  240. // prefer to pass null pointers instead of empty BSTRs
  241. return
  242. DoCopyDownlevelUserProperties(
  243. srcSamName ? srcSamName : L"",
  244. dstSamName ? dstSamName : L"",
  245. flags);
  246. }
  247. //+-----------------------------------------------------------------------
  248. //
  249. // Function: CloneSecurityPrincipal::GetMembersSIDs
  250. //
  251. // Synopsis: retrieve the <sid=XXXX> of all members of dstGroupDN.
  252. //
  253. //------------------------------------------------------------------------
  254. #define ATTRIBUTE_MEMBER L"member"
  255. HRESULT __stdcall
  256. CloneSecurityPrincipal::GetMembersSIDs(
  257. BSTR dstGroupDN,
  258. VARIANT* pVal)
  259. {
  260. // init the OUT parameter to hold an array of variants
  261. VariantInit(pVal);
  262. pVal->vt = VT_ARRAY | VT_VARIANT ;
  263. HRESULT hr = S_OK;
  264. std::vector<BSTR> values;
  265. PLDAPMessage pMsg = 0;
  266. LPTSTR lpszAttrs[] = {ATTRIBUTE_MEMBER, 0};
  267. LDAPControl serverControls = {LDAP_SERVER_EXTENDED_DN_OID_W, {0, (PCHAR)NULL}, TRUE};
  268. PLDAPControl aServerControls[] = {&serverControls, NULL};
  269. PLDAP pldap = connection->m_pldap;
  270. do
  271. {
  272. // the ldap connection to dstDC should have already been established
  273. if (!pldap)
  274. {
  275. hr = E_UNEXPECTED;
  276. LOG(L"pldap is null!");
  277. SetComError(IDS_OBJECT_STATE_BAD);
  278. break;
  279. }
  280. hr =
  281. Win32ToHresult(
  282. ldap_search_ext_s(
  283. pldap,
  284. dstGroupDN,
  285. LDAP_SCOPE_BASE, // scope
  286. _T("(objectClass=group)"), // filter
  287. lpszAttrs, // attrs[]
  288. 0, // atrssonly
  289. (PLDAPControl *)&aServerControls, // ServerControls
  290. NULL, // ClientControls
  291. 0, // no time limit
  292. 0, // no SizeLimit
  293. &pMsg));
  294. BREAK_ON_FAILED_HRESULT(hr);
  295. BSTR bstr = NULL;
  296. PTSTR pStart = NULL;
  297. PTSTR pEnd = NULL;
  298. PTSTR* ppValues = ldap_get_values(pldap, pMsg, ATTRIBUTE_MEMBER);
  299. if (!ppValues)
  300. {
  301. break;
  302. }
  303. PTSTR *p = ppValues;
  304. while(*p)
  305. {
  306. // *p is a string in the following format:
  307. // "<GUID=42e87199a88c854998dad04be4b8d29f>;<SID=0105000000
  308. // 00000515000000a23ca6557d03c651772c315d00040000>;CN=S-1-
  309. // 5-21-1436957858-1371931517-1563503735-1024,CN=Foreign
  310. // SecurityPrincipals,DC=linan,DC=nttest,DC=microsoft,DC=com"
  311. if ( (pStart = _tcsstr(*p, _T("<SID="))) &&
  312. (pEnd = _tcschr(pStart, _T('>'))) )
  313. {
  314. // retrieve <sid=XXXXX>, and add it to the vector
  315. if ( !(bstr = SysAllocStringLen(pStart, static_cast<UINT>(pEnd - pStart + 1))) )
  316. {
  317. hr = E_OUTOFMEMORY;
  318. SetComError(IDS_OUT_OF_MEMORY);
  319. break;
  320. }
  321. values.push_back(bstr);
  322. }
  323. p++;
  324. }
  325. ldap_value_free(ppValues);
  326. // SysAllocString may have failed and terminated the preceeding loop
  327. BREAK_ON_FAILED_HRESULT(hr);
  328. // populate the OUT parameter: the array of variants
  329. if (values.size() > 0)
  330. {
  331. SAFEARRAYBOUND bounds = {values.size(), 0};
  332. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  333. VARIANT* varArray;
  334. SafeArrayAccessData(psa, (void**)&varArray);
  335. int i = 0;
  336. for (
  337. std::vector<BSTR>::iterator it = values.begin();
  338. it != values.end();
  339. ++it, ++i)
  340. {
  341. VariantInit(&(varArray[i]));
  342. varArray[i].vt = VT_BSTR;
  343. varArray[i].bstrVal = *it;
  344. }
  345. SafeArrayUnaccessData(psa);
  346. pVal->parray = psa;
  347. }
  348. }
  349. while (0);
  350. if (pMsg)
  351. {
  352. ldap_msgfree(pMsg);
  353. }
  354. if (FAILED(hr))
  355. {
  356. for (
  357. std::vector<BSTR>::iterator it = values.begin();
  358. it != values.end();
  359. ++it)
  360. {
  361. SysFreeString(*it);
  362. }
  363. }
  364. return hr;
  365. }
  366. /////////////////////////////////////////////////////////////////////////////
  367. // IADsSID methods
  368. HRESULT VariantToSID(VARIANT *pVar , PSID *ppSID );
  369. HRESULT ByteToHexString(LPBYTE pByte, DWORD dwLength, LPTSTR *ppRet);
  370. // only support ADS_SID_ACTIVE_DIRECTORY_PATH and ADS_SID_WINNT_PATH and ADS_SID_SDDL
  371. STDMETHODIMP CloneSecurityPrincipal::SetAs(long lFormat, VARIANT var)
  372. {
  373. LOG_FUNCTION(CloneSecurityPrincipal::SetAs);
  374. PSID pNew = NULL ;
  375. HRESULT hr = S_OK;
  376. //
  377. // performing the necessary indirection if the source is VT_BYREF
  378. //
  379. VARIANT varData;
  380. VariantInit(&varData);
  381. hr = VariantCopyInd(&varData, (LPVARIANT)&var);
  382. if (FAILED(hr))
  383. return hr;
  384. switch( lFormat )
  385. {
  386. case ADS_SID_ACTIVE_DIRECTORY_PATH:
  387. {
  388. if ( V_VT(&varData) != VT_BSTR )
  389. return E_INVALIDARG;
  390. IDirectoryObject *pDir;
  391. hr = ADsGetObject( V_BSTR(&varData), IID_IDirectoryObject, (void**) &pDir );
  392. if ( FAILED(hr) )
  393. return hr;
  394. ADS_ATTR_INFO *pAttrInfo=NULL;
  395. DWORD dwReturn;
  396. LPWSTR pAttrNames[]={L"objectSID" };
  397. DWORD dwNumAttr=sizeof(pAttrNames)/sizeof(LPWSTR);
  398. hr = pDir->GetObjectAttributes( pAttrNames,
  399. dwNumAttr,
  400. &pAttrInfo,
  401. &dwReturn );
  402. if ( SUCCEEDED(hr) )
  403. {
  404. pNew = (PSID) AllocADsMem( pAttrInfo->pADsValues->OctetString.dwLength );
  405. if (!pNew)
  406. hr = E_OUTOFMEMORY;
  407. else
  408. CopyMemory( pNew, pAttrInfo->pADsValues->OctetString.lpValue,
  409. pAttrInfo->pADsValues->OctetString.dwLength );
  410. FreeADsMem( pAttrInfo );
  411. }
  412. pDir->Release();
  413. }
  414. break;
  415. case ADS_SID_WINNT_PATH:
  416. {
  417. if ( V_VT(&varData) != VT_BSTR )
  418. return E_INVALIDARG;
  419. IADs *pADs;
  420. hr = ADsGetObject( V_BSTR(&varData), IID_IADs, (void**) &pADs );
  421. if ( FAILED(hr) )
  422. return hr;
  423. VARIANT var;
  424. VariantInit(&var);
  425. hr = pADs->Get(L"objectSID", &var );
  426. if ( SUCCEEDED(hr) )
  427. hr = VariantToSID( &var, &pNew );
  428. pADs->Release();
  429. }
  430. break;
  431. case ADS_SID_SDDL:
  432. {
  433. if ( V_VT(&varData) != VT_BSTR )
  434. return E_INVALIDARG;
  435. LPCTSTR pszSID = V_BSTR(&varData);
  436. PSID pSID = NULL;
  437. if ( !ConvertStringSidToSid( pszSID, &pSID ) )
  438. {
  439. hr = HRESULT_FROM_WIN32(GetLastError());
  440. } else
  441. {
  442. DWORD dwLength = GetLengthSid(pSID);
  443. pNew = (PSID)AllocADsMem(dwLength);
  444. if (!pNew)
  445. hr = E_OUTOFMEMORY;
  446. else
  447. CopyMemory(pNew, pSID, dwLength);
  448. LocalFree(pSID);
  449. }
  450. }
  451. break;
  452. case ADS_SID_RAW:
  453. {
  454. // raw, meaning a variant (VT_ARRAY | VT_U1) containing the sid in the
  455. // same format as returned by the ObjectSid property.
  456. LOG(L"ADS_SID_RAW");
  457. if (V_VT(&varData) != (VT_ARRAY| VT_UI1))
  458. {
  459. return E_INVALIDARG;
  460. }
  461. hr = VariantToSID(&varData, &pNew);
  462. LOG_HRESULT(hr);
  463. break;
  464. }
  465. default:
  466. return E_INVALIDARG; // unrecognized flag.
  467. }
  468. if ( FAILED(hr) )
  469. return hr;
  470. if ( !pNew )
  471. return E_FAIL;
  472. if (!IsValidSid( pNew ) )
  473. {
  474. FreeADsMem( pNew );
  475. return E_FAIL;
  476. }
  477. if ( m_pSID )
  478. FreeADsMem( m_pSID );
  479. m_pSID = pNew;
  480. return hr;
  481. }
  482. // only support ADS_SID_SDDL and ADS_SID_HEXSTRING
  483. STDMETHODIMP CloneSecurityPrincipal::GetAs(long lFormat, VARIANT *pVar)
  484. {
  485. if ( !m_pSID )
  486. return E_INVALIDARG;
  487. HRESULT hr = S_OK;
  488. VariantClear(pVar);
  489. switch( lFormat )
  490. {
  491. case ADS_SID_HEXSTRING:
  492. {
  493. LPTSTR pStr;
  494. hr = ByteToHexString( (LPBYTE) m_pSID, GetLengthSid( m_pSID), &pStr );
  495. if ( SUCCEEDED(hr) )
  496. {
  497. V_VT( pVar ) = VT_BSTR;
  498. V_BSTR( pVar ) = SysAllocString(pStr);
  499. FreeADsMem( pStr );
  500. }
  501. }
  502. break;
  503. case ADS_SID_SDDL:
  504. {
  505. LPTSTR pszSID;
  506. if ( ConvertSidToStringSid( m_pSID, &pszSID ))
  507. {
  508. V_VT( pVar ) = VT_BSTR;
  509. V_BSTR( pVar ) = SysAllocString(pszSID);
  510. LocalFree( pszSID );
  511. } else
  512. hr = HRESULT_FROM_WIN32(GetLastError());
  513. }
  514. break;
  515. default:
  516. hr = E_INVALIDARG; // unrecognized flag.
  517. }
  518. return hr;
  519. }
  520. HRESULT VariantToSID(VARIANT *pVar , PSID *ppSID )
  521. {
  522. HRESULT hr = S_OK;
  523. SAFEARRAY *aList = NULL;
  524. CHAR HUGEP *pArray = NULL;
  525. DWORD dwLower, dwUpper, dwLength;
  526. hr = SafeArrayGetLBound(V_ARRAY(pVar),
  527. 1,
  528. (long FAR *) &dwLower );
  529. hr = SafeArrayGetUBound(V_ARRAY(pVar),
  530. 1,
  531. (long FAR *) &dwUpper );
  532. dwLength = dwUpper - dwLower;
  533. *ppSID = (PSID) AllocADsMem( dwLength + 1);
  534. aList = V_ARRAY( pVar );
  535. if ( aList == NULL )
  536. return E_UNEXPECTED;
  537. hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
  538. if ( !SUCCEEDED(hr) )
  539. return hr;
  540. CopyMemory( *ppSID, pArray, dwLength );
  541. SafeArrayUnaccessData( aList );
  542. if (!IsValidSid(*ppSID) )
  543. return E_FAIL;
  544. return hr;
  545. }
  546. HRESULT ByteToHexString( LPBYTE pByte, DWORD dwLength, LPTSTR *ppRet )
  547. {
  548. LPTSTR pDest=NULL;
  549. LPTSTR pHead=NULL;
  550. pDest = pHead = (LPTSTR) AllocADsMem( ((dwLength+1)*2) * sizeof(TCHAR));
  551. if( pHead == NULL )
  552. return E_OUTOFMEMORY;
  553. //////////////////////////////////
  554. // Convert into the Hex String
  555. //////////////////////////////////
  556. for (DWORD idx=0; idx < dwLength; idx++, pDest+=2, pByte++ )
  557. {
  558. wsprintf(pDest, _T("%02X"), *pByte );
  559. }
  560. *ppRet = pHead;
  561. return S_OK;
  562. }
  563. /////////////////////////////////////////////////////////////////////////////
  564. // IADsError methods
  565. HRESULT
  566. GetMessageHelper(
  567. OUT BSTR *pbstr,
  568. IN HRESULT hrErr,
  569. IN DWORD dwFlags,
  570. IN HINSTANCE hMsgDll = NULL
  571. );
  572. #define FACILITY_ADSI 0x00005000
  573. String
  574. GetErrorMessageADSIExtended(HRESULT hr)
  575. {
  576. LOG_FUNCTION2(GetErrorMessageADSIExtended, String::format("%1!08X!", hr));
  577. if (!FAILED(hr))
  578. {
  579. // no messages for success!
  580. return String();
  581. }
  582. String errmsg = GetErrorMessage(hr);
  583. if ((hr & FACILITY_ADSI) || //adsi
  584. HRESULT_FACILITY(hr) == FACILITY_WIN32 ) // and win32
  585. {
  586. WCHAR szBuffer[MAX_PATH];
  587. WCHAR szName[MAX_PATH];
  588. DWORD dwError;
  589. HRESULT hrEx = ADsGetLastError( &dwError, szBuffer, (sizeof(szBuffer)/sizeof(WCHAR))-1,
  590. szName, (sizeof(szName)/sizeof(WCHAR))-1 );
  591. if ( SUCCEEDED(hrEx) && dwError != ERROR_INVALID_DATA && wcslen(szBuffer))
  592. {
  593. String errmsgextended;
  594. errmsgextended = String::format(IDS_ADSI_EXTENDED_ERROR, errmsg.c_str(), szName, szBuffer);
  595. return errmsgextended;
  596. }
  597. }
  598. return errmsg;
  599. }
  600. HRESULT __stdcall
  601. CloneSecurityPrincipal::GetErrorMsg(
  602. long hrErr,
  603. BSTR* pbstrMsg)
  604. {
  605. String s = GetErrorMessageADSIExtended(hrErr);
  606. *pbstrMsg = SysAllocString(const_cast<String::value_type*>(s.c_str()));
  607. if (!*pbstrMsg)
  608. return E_OUTOFMEMORY;
  609. return S_OK;
  610. }
  611. //
  612. // S_OK: found and returned in pbstr
  613. // S_FALSE: message not found
  614. // hr: some error happened
  615. //
  616. HRESULT
  617. GetMessageHelper(
  618. OUT BSTR *pbstr,
  619. IN HRESULT hrErr,
  620. IN DWORD dwFlags,
  621. IN HINSTANCE hMsgDll
  622. )
  623. {
  624. *pbstr = NULL;
  625. LPTSTR lpBuffer = NULL;
  626. DWORD dwRet =
  627. FormatMessage(
  628. FORMAT_MESSAGE_ALLOCATE_BUFFER | dwFlags,
  629. (LPCVOID) hMsgDll,
  630. hrErr,
  631. 0,
  632. (LPTSTR) &lpBuffer,
  633. 0,
  634. NULL);
  635. if ( !dwRet )
  636. {
  637. DWORD dwErr = GetLastError();
  638. if (ERROR_MR_MID_NOT_FOUND == dwErr)
  639. return S_FALSE;
  640. else
  641. return HRESULT_FROM_WIN32(dwErr);
  642. }
  643. *pbstr = SysAllocString(lpBuffer);
  644. LocalFree(lpBuffer);
  645. if (!*pbstr)
  646. return E_OUTOFMEMORY;
  647. return S_OK;
  648. }