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.

3558 lines
82 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. EEInfo.cxx
  5. Abstract:
  6. Extended Error Info public & private functions
  7. Author:
  8. Kamen Moutafov [KamenM]
  9. Revision History:
  10. KamenM Mar 2000 Initial version
  11. KamenM Oct 2000 Add caching of EEInfo blocks to
  12. solve Exchange perf problems
  13. --*/
  14. #include <precomp.hxx>
  15. #include <EEInfo.h>
  16. #include <EEInfo.hxx>
  17. const int MaxBinaryBlobSize = 4096; // 4K limit
  18. ExtendedErrorInfo *
  19. AllocateExtendedErrorInfoRecord (
  20. IN int NumberOfParams
  21. )
  22. /*++
  23. Routine Description:
  24. Allocates a memory block large enough to hold an
  25. extended error record with the specified number of
  26. parameters. It is allocated with MIDL_user_allocate.
  27. Arguments:
  28. NumberOfParams - number of paramaters to provide space
  29. for
  30. Return Value:
  31. The address of the block or NULL if out of memory
  32. --*/
  33. {
  34. ExtendedErrorInfo *EEInfo;
  35. THREAD *ThisThread;
  36. ThisThread = ThreadSelf();
  37. if (ThisThread)
  38. {
  39. EEInfo = ThisThread->GetCachedEEInfoBlock(NumberOfParams);
  40. }
  41. else
  42. EEInfo = NULL;
  43. if (EEInfo == NULL)
  44. {
  45. EEInfo = (ExtendedErrorInfo *) MIDL_user_allocate(sizeof(ExtendedErrorInfo) +
  46. (NumberOfParams - 1) * sizeof(ExtendedErrorParam));
  47. }
  48. if (EEInfo)
  49. EEInfo->nLen = (short)NumberOfParams;
  50. return EEInfo;
  51. }
  52. inline void
  53. FreeEEInfoRecordShallow (
  54. IN ExtendedErrorInfo *InfoToFree
  55. )
  56. /*++
  57. Routine Description:
  58. Frees only the eeinfo record - not any of
  59. the pointers contained in it.
  60. Arguments:
  61. InfoToFree - the eeinfo record
  62. Return Value:
  63. void
  64. --*/
  65. {
  66. MIDL_user_free(InfoToFree);
  67. }
  68. RPC_STATUS
  69. DuplicatePrivateString (
  70. IN EEUString *SourceString,
  71. OUT EEUString *DestString
  72. )
  73. /*++
  74. Routine Description:
  75. Takes a EEUString structure and makes a copy
  76. of it.
  77. Arguments:
  78. SourceString - the string to copy
  79. DestString - a placeholder allocated by caller to copy to
  80. Return Value:
  81. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  82. --*/
  83. {
  84. DestString->nLength = SourceString->nLength;
  85. DestString->pString = (LPWSTR)MIDL_user_allocate(DestString->nLength * sizeof(unsigned short));
  86. if (DestString->pString != NULL)
  87. {
  88. RpcpMemoryCopy(DestString->pString, SourceString->pString, DestString->nLength * sizeof(unsigned short));
  89. return RPC_S_OK;
  90. }
  91. else
  92. {
  93. return RPC_S_OUT_OF_MEMORY;
  94. }
  95. }
  96. RPC_STATUS
  97. DuplicatePrivateString (
  98. IN EEAString *SourceString,
  99. OUT EEAString *DestString
  100. )
  101. /*++
  102. Routine Description:
  103. Takes a EEAString structure and makes a copy
  104. of it.
  105. Arguments:
  106. SourceString - the string to copy
  107. DestString - a placeholder allocated by caller to copy to
  108. Return Value:
  109. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  110. --*/
  111. {
  112. DestString->nLength = SourceString->nLength;
  113. DestString->pString = (unsigned char *)MIDL_user_allocate(DestString->nLength);
  114. if (DestString->pString != NULL)
  115. {
  116. RpcpMemoryCopy(DestString->pString, SourceString->pString, DestString->nLength);
  117. return RPC_S_OK;
  118. }
  119. else
  120. {
  121. return RPC_S_OUT_OF_MEMORY;
  122. }
  123. }
  124. RPC_STATUS
  125. DuplicateBlob (
  126. IN void *SourceBlob,
  127. IN short Size,
  128. OUT void **DestBlob)
  129. /*++
  130. Routine Description:
  131. Takes a blob and makes a copy of it.
  132. Arguments:
  133. SourceBlob - the blob to copy
  134. Size - the size of the blob
  135. DestBlob - a placeholder where a pointer to the copied
  136. buffer will be put
  137. Return Value:
  138. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  139. --*/
  140. {
  141. void *CopiedBlob;
  142. CopiedBlob = MIDL_user_allocate(Size);
  143. if (CopiedBlob)
  144. {
  145. RpcpMemoryCopy(CopiedBlob, SourceBlob, Size);
  146. *DestBlob = CopiedBlob;
  147. return RPC_S_OK;
  148. }
  149. else
  150. {
  151. return RPC_S_OUT_OF_MEMORY;
  152. }
  153. }
  154. RPC_STATUS
  155. DuplicatePrivateBlob (
  156. IN BinaryEEInfo *SourceBlob,
  157. OUT BinaryEEInfo *DestBlob)
  158. /*++
  159. Routine Description:
  160. Takes a binary param and makes a copy of it.
  161. Arguments:
  162. SourceBlob - the blob to copy
  163. DestBlob - a placeholder allocated by caller to copy to
  164. Return Value:
  165. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  166. --*/
  167. {
  168. RPC_STATUS Status;
  169. Status = DuplicateBlob(SourceBlob->pBlob, SourceBlob->nSize, (PVOID *)&DestBlob->pBlob);
  170. if (Status == RPC_S_OK)
  171. {
  172. DestBlob->nSize = SourceBlob->nSize;
  173. }
  174. return Status;
  175. }
  176. RPC_STATUS
  177. ConvertPublicStringToPrivateString (
  178. IN LPWSTR PublicString,
  179. OUT EEUString *PrivateString)
  180. /*++
  181. Routine Description:
  182. Takes a LPWSTR string and makes a copy
  183. of it into a EEUString structure
  184. Arguments:
  185. PublicString - the string to copy - cannot be NULL
  186. PrivateString - a placeholder allocated by caller to copy to
  187. Return Value:
  188. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  189. --*/
  190. {
  191. // the StringLength is in bytes
  192. int StringLength = (wcslen(PublicString) + 1) * 2;
  193. LPWSTR CopiedString;
  194. CopiedString = (LPWSTR)MIDL_user_allocate(StringLength);
  195. if (CopiedString)
  196. {
  197. RpcpMemoryCopy(CopiedString, PublicString, StringLength);
  198. PrivateString->pString = CopiedString;
  199. PrivateString->nLength = (short)StringLength / 2;
  200. return RPC_S_OK;
  201. }
  202. else
  203. {
  204. return RPC_S_OUT_OF_MEMORY;
  205. }
  206. }
  207. RPC_STATUS
  208. ConvertPublicStringToPrivateString (
  209. IN LPSTR PublicString,
  210. OUT EEAString *PrivateString)
  211. /*++
  212. Routine Description:
  213. Takes a LPSTR string and makes a copy
  214. of it into a EEAString structure
  215. Arguments:
  216. PublicString - the string to copy - cannot be NULL
  217. PrivateString - a placeholder allocated by caller to copy to
  218. Return Value:
  219. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  220. --*/
  221. {
  222. int StringLength = strlen(PublicString) + 1;
  223. LPSTR CopiedString;
  224. CopiedString = (LPSTR)MIDL_user_allocate(StringLength);
  225. if (CopiedString)
  226. {
  227. RpcpMemoryCopy(CopiedString, PublicString, StringLength);
  228. PrivateString->pString = (unsigned char *)CopiedString;
  229. PrivateString->nLength = (short)StringLength;
  230. return RPC_S_OK;
  231. }
  232. else
  233. {
  234. return RPC_S_OUT_OF_MEMORY;
  235. }
  236. }
  237. RPC_STATUS
  238. ConvertPublicBlobToPrivateBlob (
  239. IN BinaryParam *PublicBlob,
  240. OUT BinaryEEInfo *PrivateBlob)
  241. /*++
  242. Routine Description:
  243. Takes a binary param and converts it to private format.
  244. Arguments:
  245. PublicBlob - the blob to copy - cannot be NULL
  246. PrivateBlob - a placeholder allocated by caller to copy to
  247. Return Value:
  248. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  249. --*/
  250. {
  251. unsigned char *CopiedBlob;
  252. if (PublicBlob->Size > MaxBinaryBlobSize)
  253. {
  254. return ERROR_INVALID_PARAMETER;
  255. }
  256. RPC_STATUS Status;
  257. Status = DuplicateBlob(PublicBlob->Buffer, PublicBlob->Size, (PVOID *)&PrivateBlob->pBlob);
  258. if (Status == RPC_S_OK)
  259. {
  260. PrivateBlob->nSize = PublicBlob->Size;
  261. }
  262. return Status;
  263. }
  264. RPC_STATUS
  265. ConvertPrivateStringToPublicString (
  266. IN EEUString *PrivateString,
  267. IN BOOL CopyStrings,
  268. OUT LPWSTR *PublicString
  269. )
  270. /*++
  271. Routine Description:
  272. Takes a EEUString and makes a copy
  273. of it into a LPWSTR
  274. Arguments:
  275. PrivateString - the string to copy
  276. CopyStrings - if non-zero this routine will allocate
  277. space on the process heap and will copy the string.
  278. If zero, it will alias the PublicString to the
  279. pString member of PrivateString
  280. PublicString - the string to copy to
  281. Return Value:
  282. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  283. --*/
  284. {
  285. LPWSTR ReturnString;
  286. int StringLength; // in bytes
  287. if (CopyStrings)
  288. {
  289. StringLength = PrivateString->nLength * 2;
  290. ReturnString = (LPWSTR)RtlAllocateHeap(RtlProcessHeap(), 0, StringLength);
  291. if (ReturnString == NULL)
  292. return RPC_S_OUT_OF_MEMORY;
  293. RpcpMemoryCopy(ReturnString, PrivateString->pString, StringLength);
  294. }
  295. else
  296. {
  297. ReturnString = PrivateString->pString;
  298. }
  299. *PublicString = ReturnString;
  300. return RPC_S_OK;
  301. }
  302. RPC_STATUS
  303. ConvertPrivateStringToPublicString (
  304. IN EEAString *PrivateString,
  305. IN BOOL CopyStrings,
  306. OUT LPSTR *PublicString
  307. )
  308. /*++
  309. Routine Description:
  310. Takes a EEAString and makes a copy
  311. of it into a LPSTR
  312. Arguments:
  313. PrivateString - the string to copy
  314. CopyStrings - if non-zero this routine will allocate
  315. space on the process heap and will copy the string.
  316. If zero, it will alias the PublicString to the
  317. pString member of PrivateString
  318. PublicString - the string to copy to
  319. Return Value:
  320. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  321. --*/
  322. {
  323. LPSTR ReturnString;
  324. if (CopyStrings)
  325. {
  326. ReturnString = (LPSTR)RtlAllocateHeap(RtlProcessHeap(), 0, PrivateString->nLength);
  327. if (ReturnString == NULL)
  328. return RPC_S_OUT_OF_MEMORY;
  329. RpcpMemoryCopy(ReturnString, PrivateString->pString, PrivateString->nLength);
  330. }
  331. else
  332. {
  333. ReturnString = (char *)PrivateString->pString;
  334. }
  335. *PublicString = ReturnString;
  336. return RPC_S_OK;
  337. }
  338. RPC_STATUS
  339. ConvertPrivateBlobToPublicBlob (
  340. IN BinaryEEInfo *PrivateBlob,
  341. IN BOOL CopyStrings,
  342. OUT BinaryParam *PublicBlob
  343. )
  344. /*++
  345. Routine Description:
  346. Takes a private blob and makes a copy
  347. of it into a public blob format
  348. Arguments:
  349. PrivateBlob - the blob to copy
  350. CopyStrings - if non-zero this routine will allocate
  351. space on the process heap and will copy the blob.
  352. If zero, it will alias the PublicBlob to the
  353. Blob.pBlob member of PrivateBlob
  354. PublicBlob - the blob to copy to
  355. Return Value:
  356. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  357. --*/
  358. {
  359. void *ReturnBuffer;
  360. if (CopyStrings)
  361. {
  362. ReturnBuffer = RtlAllocateHeap(RtlProcessHeap(), 0, PrivateBlob->nSize);
  363. if (ReturnBuffer == NULL)
  364. return RPC_S_OUT_OF_MEMORY;
  365. RpcpMemoryCopy(ReturnBuffer, PrivateBlob->pBlob, PrivateBlob->nSize);
  366. }
  367. else
  368. {
  369. ReturnBuffer = PrivateBlob->pBlob;
  370. }
  371. PublicBlob->Buffer = ReturnBuffer;
  372. PublicBlob->Size = PrivateBlob->nSize;
  373. return RPC_S_OK;
  374. }
  375. inline void
  376. FreePublicStringIfNecessary (
  377. OUT LPWSTR PublicString,
  378. IN BOOL CopyStrings
  379. )
  380. /*++
  381. Routine Description:
  382. Deletes the string if necessary
  383. Arguments:
  384. PublicString - the string to delete. Must be on the
  385. process heap
  386. CopyStrings - the value of the CopyStrings parameter
  387. when RpcErrorGetNextRecord was called. If non-zero
  388. the string will be freed. Otherwise, the function
  389. is a no-op
  390. Return Value:
  391. void
  392. --*/
  393. {
  394. if (CopyStrings)
  395. {
  396. if (PublicString)
  397. {
  398. RtlFreeHeap(RtlProcessHeap(), 0, PublicString);
  399. }
  400. }
  401. }
  402. void
  403. FreeEEInfoPrivateParam (
  404. IN ExtendedErrorParam *Param
  405. )
  406. {
  407. if ((Param->Type == eeptiAnsiString)
  408. || (Param->Type == eeptiUnicodeString))
  409. {
  410. // AnsiString & UnicodeString occupy the same
  411. // memory location - ok to free any of them
  412. MIDL_user_free(Param->AnsiString.pString);
  413. }
  414. else if (Param->Type == eeptiBinary)
  415. {
  416. MIDL_user_free(Param->Blob.pBlob);
  417. }
  418. }
  419. void
  420. FreeEEInfoPublicParam (
  421. IN OUT RPC_EE_INFO_PARAM *Param,
  422. IN BOOL CopyStrings
  423. )
  424. /*++
  425. Routine Description:
  426. If the type of parameter is string (ansi or unicode)
  427. and CopyStrings, free the string
  428. Arguments:
  429. Param - the parameter to free
  430. CopyStrings - the value of the CopyStrings parameter
  431. when RpcErrorGetNextRecord was called. If non-zero
  432. the string will be freed. Otherwise, the function
  433. is a no-op
  434. Return Value:
  435. void
  436. --*/
  437. {
  438. if ((Param->ParameterType == eeptAnsiString)
  439. || (Param->ParameterType == eeptUnicodeString))
  440. {
  441. if (CopyStrings)
  442. {
  443. RtlFreeHeap(RtlProcessHeap(), 0, Param->u.AnsiString);
  444. }
  445. }
  446. else if (Param->ParameterType == eeptBinary)
  447. {
  448. if (CopyStrings)
  449. {
  450. RtlFreeHeap(RtlProcessHeap(), 0, Param->u.BVal.Buffer);
  451. }
  452. }
  453. }
  454. RPC_STATUS
  455. ConvertPublicParamToPrivateParam (
  456. IN RPC_EE_INFO_PARAM *PublicParam,
  457. OUT ExtendedErrorParam *PrivateParam
  458. )
  459. /*++
  460. Routine Description:
  461. Takes a parameter in format RPC_EE_INFO_PARAM and
  462. converts it to ExtendedErrorParam.
  463. Arguments:
  464. PublicParam - the parameter to copy.
  465. PrivateParam - the parameter to copy to
  466. Return Value:
  467. RPC_S_OK, RPC_S_INTERNAL_ERROR, RPC_S_OUT_OF_MEMORY
  468. --*/
  469. {
  470. RPC_STATUS RpcStatus = RPC_S_OK;
  471. PrivateParam->Type = (ExtendedErrorParamTypesInternal)PublicParam->ParameterType;
  472. switch (PrivateParam->Type)
  473. {
  474. case eeptiAnsiString:
  475. RpcStatus = ConvertPublicStringToPrivateString(PublicParam->u.AnsiString,
  476. &PrivateParam->AnsiString);
  477. break;
  478. case eeptiUnicodeString:
  479. RpcStatus = ConvertPublicStringToPrivateString(PublicParam->u.UnicodeString,
  480. &PrivateParam->UnicodeString);
  481. break;
  482. case eeptiLongVal:
  483. PrivateParam->LVal = PublicParam->u.LVal;
  484. break;
  485. case eeptiShortVal:
  486. PrivateParam->IVal = PublicParam->u.SVal;
  487. break;
  488. case eeptiPointerVal:
  489. PrivateParam->PVal = (ULONGLONG)PublicParam->u.PVal;
  490. break;
  491. case eeptiNone:
  492. break;
  493. case eeptiBinary:
  494. RpcStatus = ConvertPublicBlobToPrivateBlob(&PublicParam->u.BVal,
  495. &PrivateParam->Blob);
  496. break;
  497. default:
  498. ASSERT(FALSE);
  499. RpcStatus = ERROR_INVALID_PARAMETER;
  500. }
  501. return RpcStatus;
  502. }
  503. RPC_STATUS
  504. ConvertPrivateParamToPublicParam (
  505. IN ExtendedErrorParam *PrivateParam,
  506. IN BOOL CopyStrings,
  507. OUT RPC_EE_INFO_PARAM *PublicParam
  508. )
  509. /*++
  510. Routine Description:
  511. Takes a parameter in format ExtendedErrorParam and
  512. converts it to RPC_EE_INFO_PARAM.
  513. Arguments:
  514. PrivateParam - the parameter to copy
  515. CopyStrings - if non-zero, this function will allocate
  516. space for any strings to be copied on the process
  517. heap and will copy the strings. If FALSE, it
  518. will alias the output pointers to RPC internal
  519. data structures
  520. PublicParam - the parameter to copy to
  521. Return Value:
  522. RPC_S_OK, RPC_S_INTERNAL_ERROR, RPC_S_OUT_OF_MEMORY
  523. --*/
  524. {
  525. RPC_STATUS RpcStatus = RPC_S_OK;
  526. PublicParam->ParameterType = (ExtendedErrorParamTypes)PrivateParam->Type;
  527. switch (PublicParam->ParameterType)
  528. {
  529. case eeptAnsiString:
  530. RpcStatus = ConvertPrivateStringToPublicString(&PrivateParam->AnsiString,
  531. CopyStrings,
  532. &PublicParam->u.AnsiString);
  533. break;
  534. case eeptUnicodeString:
  535. RpcStatus = ConvertPrivateStringToPublicString(&PrivateParam->UnicodeString,
  536. CopyStrings,
  537. &PublicParam->u.UnicodeString);
  538. break;
  539. case eeptLongVal:
  540. PublicParam->u.LVal = PrivateParam->LVal;
  541. break;
  542. case eeptShortVal:
  543. PublicParam->u.SVal = PrivateParam->IVal;
  544. break;
  545. case eeptPointerVal:
  546. PublicParam->u.PVal = PrivateParam->PVal;
  547. break;
  548. case eeptNone:
  549. break;
  550. case eeptBinary:
  551. RpcStatus = ConvertPrivateBlobToPublicBlob(&PrivateParam->Blob,
  552. CopyStrings,
  553. &PublicParam->u.BVal);
  554. break;
  555. default:
  556. ASSERT(FALSE);
  557. RpcStatus = RPC_S_INTERNAL_ERROR;
  558. }
  559. return RpcStatus;
  560. }
  561. void
  562. InitializePrivateEEInfo (
  563. IN ExtendedErrorInfo *ErrorInfo
  564. )
  565. /*++
  566. Routine Description:
  567. Initializes the common data members of the ExtendedErrorInfo
  568. structure.
  569. Arguments:
  570. ErrorInfo - the structure to initialize
  571. Return Value:
  572. void
  573. --*/
  574. {
  575. ErrorInfo->Next = NULL;
  576. ErrorInfo->ComputerName.Type = eecnpNotPresent;
  577. ErrorInfo->ProcessID = GetCurrentProcessId();
  578. GetSystemTimeAsFileTime((FILETIME *)&ErrorInfo->TimeStamp);
  579. ErrorInfo->Flags = 0;
  580. }
  581. RPC_STATUS
  582. ConvertPublicEEInfoToPrivateEEInfo (
  583. IN RPC_EXTENDED_ERROR_INFO *PublicEEInfo,
  584. IN short DetectionLocation,
  585. OUT ExtendedErrorInfo *PrivateEEInfo
  586. )
  587. /*++
  588. Routine Description:
  589. Takes a RPC_EXTENDED_ERROR_INFO record and converts
  590. it to an ExtendedErrorInfo record.
  591. Arguments:
  592. PublicEEInfo - the public record to convert
  593. DetectionLocation - the detection location to use in the
  594. private record.
  595. PrivateEEInfo - the private record to copy to
  596. Return Value:
  597. RPC_S_OK or RPC_S_* error
  598. --*/
  599. {
  600. int NumberOfParams;
  601. int i;
  602. RPC_STATUS RpcStatus = RPC_S_OK;
  603. ASSERT(PrivateEEInfo != NULL);
  604. ASSERT(PrivateEEInfo->nLen == PublicEEInfo->NumberOfParameters);
  605. if (PublicEEInfo->Version != RPC_EEINFO_VERSION)
  606. return RPC_S_INVALID_LEVEL;
  607. InitializePrivateEEInfo(PrivateEEInfo);
  608. // EEInfoGCCOM can come externally. If it's not, set it to
  609. // EEInfoGCApplication
  610. if (PublicEEInfo->GeneratingComponent != EEInfoGCCOM)
  611. {
  612. PrivateEEInfo->GeneratingComponent = EEInfoGCApplication;
  613. }
  614. else
  615. {
  616. PrivateEEInfo->GeneratingComponent = EEInfoGCCOM;
  617. }
  618. PrivateEEInfo->Status = PublicEEInfo->Status;
  619. PrivateEEInfo->DetectionLocation = DetectionLocation;
  620. // the next line should have been executed by the allocating code
  621. //PrivateEEInfo->nLen = PublicEEInfo->NumberOfParameters;
  622. NumberOfParams = PrivateEEInfo->nLen;
  623. for (i = 0; i < NumberOfParams; i ++)
  624. {
  625. if ((PublicEEInfo->Parameters[i].ParameterType < eeptAnsiString)
  626. || (PublicEEInfo->Parameters[i].ParameterType > eeptBinary))
  627. RpcStatus = ERROR_INVALID_PARAMETER;
  628. if (RpcStatus == RPC_S_OK)
  629. {
  630. RpcStatus = ConvertPublicParamToPrivateParam(&PublicEEInfo->Parameters[i],
  631. &PrivateEEInfo->Params[i]);
  632. }
  633. if (RpcStatus != RPC_S_OK)
  634. {
  635. // go backward and free all memory
  636. i --;
  637. for (; i >= 0; i --)
  638. {
  639. FreeEEInfoPrivateParam(&PrivateEEInfo->Params[i]);
  640. }
  641. break;
  642. }
  643. }
  644. return RpcStatus;
  645. }
  646. RPC_STATUS
  647. ConvertPrivateEEInfoToPublicEEInfo (
  648. IN ExtendedErrorInfo *PrivateEEInfo,
  649. IN BOOL CopyStrings,
  650. OUT RPC_EXTENDED_ERROR_INFO *PublicEEInfo
  651. )
  652. /*++
  653. Routine Description:
  654. Takes an ExtendedErrorInfo record and converts
  655. it to a RPC_EXTENDED_ERROR_INFO record.
  656. Arguments:
  657. PrivateEEInfo - the private record to convert
  658. CopyStrings - If non-zero, all strings will be allocated
  659. space on the process heap and will be copied. Otherwise
  660. they will be aliased to the privated data structure
  661. strings
  662. PublicEEInfo - the public record to copy to
  663. Return Value:
  664. RPC_S_OK or RPC_S_* error
  665. --*/
  666. {
  667. BOOL Result;
  668. int NumberOfParams;
  669. int i;
  670. RPC_STATUS RpcStatus;
  671. ASSERT (PublicEEInfo != NULL);
  672. if (PublicEEInfo->Version != RPC_EEINFO_VERSION)
  673. return RPC_S_INVALID_LEVEL;
  674. if (PublicEEInfo->NumberOfParameters < PrivateEEInfo->nLen)
  675. return RPC_S_BUFFER_TOO_SMALL;
  676. if (PublicEEInfo->Flags & (~EEInfoValidInputFlags))
  677. return RPC_S_INVALID_LEVEL;
  678. if (PrivateEEInfo->ComputerName.Type == eecnpNotPresent)
  679. {
  680. PublicEEInfo->ComputerName = NULL;
  681. }
  682. else
  683. {
  684. RpcStatus = ConvertPrivateStringToPublicString(&PrivateEEInfo->ComputerName.Name,
  685. CopyStrings, &PublicEEInfo->ComputerName);
  686. if (RpcStatus != RPC_S_OK)
  687. return RpcStatus;
  688. }
  689. PublicEEInfo->ProcessID = PrivateEEInfo->ProcessID;
  690. if (PublicEEInfo->Flags & EEInfoUseFileTime)
  691. {
  692. RpcpMemoryCopy(&PublicEEInfo->u.FileTime, &PrivateEEInfo->TimeStamp, sizeof(FILETIME));
  693. }
  694. else
  695. {
  696. Result = FileTimeToSystemTime((FILETIME *)&PrivateEEInfo->TimeStamp,
  697. &PublicEEInfo->u.SystemTime);
  698. if (Result == 0)
  699. return GetLastError();
  700. }
  701. PublicEEInfo->GeneratingComponent = PrivateEEInfo->GeneratingComponent;
  702. PublicEEInfo->Status = PrivateEEInfo->Status;
  703. PublicEEInfo->DetectionLocation = PrivateEEInfo->DetectionLocation;
  704. PublicEEInfo->Flags = PrivateEEInfo->Flags;
  705. // restore the consistency of the flags, if necessary
  706. if (PrivateEEInfo->Next)
  707. {
  708. // if there is next record, and its flags indicate that
  709. // a previous record is missing
  710. if (PrivateEEInfo->Next->Flags & EEInfoPreviousRecordsMissing)
  711. PublicEEInfo->Flags |= EEInfoNextRecordsMissing;
  712. }
  713. NumberOfParams = PrivateEEInfo->nLen;
  714. PublicEEInfo->NumberOfParameters = NumberOfParams;
  715. for (i = 0; i < NumberOfParams; i ++)
  716. {
  717. // convert the params
  718. RpcStatus = ConvertPrivateParamToPublicParam(&PrivateEEInfo->Params[i],
  719. CopyStrings, &PublicEEInfo->Parameters[i]);
  720. if (RpcStatus != RPC_S_OK)
  721. {
  722. // go back, and free eveyrthing
  723. FreePublicStringIfNecessary(PublicEEInfo->ComputerName, CopyStrings);
  724. i --;
  725. for ( ; i >= 0; i --)
  726. {
  727. FreeEEInfoPublicParam(&PublicEEInfo->Parameters[i], CopyStrings);
  728. }
  729. return RpcStatus;
  730. }
  731. }
  732. return RPC_S_OK;
  733. }
  734. void
  735. FreeEEInfoRecord (
  736. IN ExtendedErrorInfo *EEInfo
  737. )
  738. /*++
  739. Routine Description:
  740. Frees a single ExtendedErrorInfo record and
  741. all strings within it.
  742. Arguments:
  743. EEInfo - record to free
  744. Return Value:
  745. void
  746. --*/
  747. {
  748. int i;
  749. THREAD *Thread;
  750. for (i = 0; i < EEInfo->nLen; i ++)
  751. {
  752. FreeEEInfoPrivateParam(&EEInfo->Params[i]);
  753. }
  754. if (EEInfo->ComputerName.Type == eecnpPresent)
  755. {
  756. MIDL_user_free(EEInfo->ComputerName.Name.pString);
  757. }
  758. Thread = RpcpGetThreadPointer();
  759. if (Thread)
  760. {
  761. Thread->SetCachedEEInfoBlock(EEInfo, EEInfo->nLen);
  762. }
  763. else
  764. {
  765. FreeEEInfoRecordShallow(EEInfo);
  766. }
  767. }
  768. void
  769. FreeEEInfoChain (
  770. IN ExtendedErrorInfo *EEInfo
  771. )
  772. /*++
  773. Routine Description:
  774. Frees a chain of ExtendedErrorInfo records and
  775. all strings within them.
  776. Arguments:
  777. EEInfo - head of list to free
  778. Return Value:
  779. void
  780. --*/
  781. {
  782. ExtendedErrorInfo *CurrentInfo, *NextInfo;
  783. CurrentInfo = EEInfo;
  784. while (CurrentInfo != NULL)
  785. {
  786. // get the next link while we can
  787. NextInfo = CurrentInfo->Next;
  788. FreeEEInfoRecord(CurrentInfo);
  789. CurrentInfo = NextInfo;
  790. }
  791. }
  792. RPC_STATUS
  793. CloneEEInfoParam (
  794. IN ExtendedErrorParam *SourceParam,
  795. OUT ExtendedErrorParam *DestParam
  796. )
  797. /*++
  798. Routine Description:
  799. Makes an exact deep copy of an ExtendedErrorParam structure
  800. Arguments:
  801. SourceParam - the parameter to copy from
  802. DestParam - the parameter to copy to
  803. Return Value:
  804. RPC_S_OK or RPC_S_* error
  805. --*/
  806. {
  807. RPC_STATUS RpcStatus = RPC_S_OK;
  808. ASSERT (DestParam != NULL);
  809. switch (SourceParam->Type)
  810. {
  811. case eeptiAnsiString:
  812. RpcStatus = DuplicatePrivateString(&SourceParam->AnsiString,
  813. &DestParam->AnsiString);
  814. break;
  815. case eeptiUnicodeString:
  816. RpcStatus = DuplicatePrivateString(&SourceParam->UnicodeString,
  817. &DestParam->UnicodeString);
  818. break;
  819. case eeptiLongVal:
  820. DestParam->LVal = SourceParam->LVal;
  821. break;
  822. case eeptiShortVal:
  823. DestParam->IVal = SourceParam->IVal;
  824. break;
  825. case eeptiPointerVal:
  826. DestParam->PVal = SourceParam->PVal;
  827. break;
  828. case eeptiNone:
  829. break;
  830. case eeptiBinary:
  831. RpcStatus = DuplicatePrivateBlob(&SourceParam->Blob,
  832. &DestParam->Blob);
  833. break;
  834. default:
  835. ASSERT(0);
  836. RpcStatus = RPC_S_INTERNAL_ERROR;
  837. }
  838. DestParam->Type = SourceParam->Type;
  839. return RpcStatus;
  840. }
  841. RPC_STATUS
  842. CloneEEInfoRecord (
  843. IN ExtendedErrorInfo *SourceInfo,
  844. OUT ExtendedErrorInfo **DestInfo
  845. )
  846. /*++
  847. Routine Description:
  848. Makes an exact deep copy of a single ExtendedErrorInfo record
  849. Arguments:
  850. SourceInfo - the record to copy from
  851. DestInfo - the record to copy to
  852. Return Value:
  853. RPC_S_OK or RPC_S_* error
  854. --*/
  855. {
  856. ExtendedErrorInfo *NewInfo;
  857. int NumberOfParams;
  858. int i;
  859. RPC_STATUS RpcStatus;
  860. EEUString *ComputerNameToFree = NULL;
  861. *DestInfo = NULL;
  862. NumberOfParams = SourceInfo->nLen;
  863. NewInfo = AllocateExtendedErrorInfoRecord(NumberOfParams);
  864. if (NewInfo == NULL)
  865. return RPC_S_OUT_OF_MEMORY;
  866. // shallow copy all the fields. This is good for most fields
  867. // we will process the ones that need deep copy further down.
  868. // we copy everything, but the first param, which may require
  869. // deep copying
  870. RpcpMemoryCopy(NewInfo, SourceInfo, sizeof(ExtendedErrorInfo) - sizeof(ExtendedErrorParam));
  871. // N.B. Zero out the next field before any failure paths
  872. NewInfo->Next = NULL;
  873. if (SourceInfo->ComputerName.Type == eecnpPresent)
  874. {
  875. RpcStatus = DuplicatePrivateString(&SourceInfo->ComputerName.Name,
  876. &NewInfo->ComputerName.Name);
  877. if (RpcStatus != RPC_S_OK)
  878. {
  879. FreeEEInfoRecordShallow(NewInfo);
  880. return RpcStatus;
  881. }
  882. ComputerNameToFree = &NewInfo->ComputerName.Name;
  883. }
  884. for (i = 0; i < NumberOfParams; i ++)
  885. {
  886. RpcStatus = CloneEEInfoParam(&SourceInfo->Params[i],
  887. &NewInfo->Params[i]);
  888. if (RpcStatus != RPC_S_OK)
  889. {
  890. if (ComputerNameToFree)
  891. MIDL_user_free(ComputerNameToFree->pString);
  892. i --;
  893. for ( ; i >= 0; i --)
  894. {
  895. FreeEEInfoPrivateParam(&NewInfo->Params[i]);
  896. }
  897. FreeEEInfoRecordShallow(NewInfo);
  898. return RpcStatus;
  899. }
  900. }
  901. *DestInfo = NewInfo;
  902. return RPC_S_OK;
  903. }
  904. RPC_STATUS
  905. CloneEEInfoChain (
  906. IN ExtendedErrorInfo *SourceEEInfo,
  907. OUT ExtendedErrorInfo **DestEEInfo
  908. )
  909. /*++
  910. Routine Description:
  911. Makes an exact deep copy of an ExtendedErrorInfo chain
  912. Arguments:
  913. SourceEEInfo - the head of the chain to copy from
  914. DestEEInfo - a pointer to the head of the cloned chain.
  915. The memory for the head of the cloned chain will be
  916. allocated by this function and the given pointer
  917. will be set to point to it.
  918. Return Value:
  919. RPC_S_OK or RPC_S_* error
  920. --*/
  921. {
  922. ExtendedErrorInfo *CurrentInfo, *NewInfo, *NewInfoHead = NULL;
  923. ExtendedErrorInfo *LastNewInfo = NULL;
  924. RPC_STATUS RpcStatus;
  925. CurrentInfo = SourceEEInfo;
  926. while (CurrentInfo != NULL)
  927. {
  928. RpcStatus = CloneEEInfoRecord(CurrentInfo, &NewInfo);
  929. if (RpcStatus != RPC_S_OK)
  930. {
  931. if (NewInfoHead != NULL)
  932. FreeEEInfoChain(NewInfoHead);
  933. return RpcStatus;
  934. }
  935. if (NewInfoHead == NULL)
  936. NewInfoHead = NewInfo;
  937. if (LastNewInfo != NULL)
  938. LastNewInfo->Next = NewInfo;
  939. // advance both chains
  940. LastNewInfo = NewInfo;
  941. CurrentInfo = CurrentInfo->Next;
  942. }
  943. *DestEEInfo = NewInfoHead;
  944. return RPC_S_OK;
  945. }
  946. const ULONG EnumSignatureLive = 0xfcfcfcfc;
  947. const ULONG EnumSignatureDead = 0xfdfdfdfd;
  948. void
  949. InitializeEnumHandleWithEEInfo (
  950. IN ExtendedErrorInfo *EEInfo,
  951. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  952. )
  953. /*++
  954. Routine Description:
  955. Initializes the common fields of a RPC_ERROR_ENUM_HANDLE
  956. structure
  957. Arguments:
  958. EEInfo - the chain we're enumerating from
  959. EnumHandle - the structure to initialize
  960. Return Value:
  961. void
  962. --*/
  963. {
  964. ASSERT(EEInfo != NULL);
  965. EnumHandle->Signature = EnumSignatureLive;
  966. EnumHandle->Head = EEInfo;
  967. EnumHandle->CurrentPos = EEInfo;
  968. }
  969. RPC_STATUS
  970. RpcpErrorStartEnumerationFromEEInfo (
  971. IN ExtendedErrorInfo *EEInfo,
  972. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  973. )
  974. /*++
  975. Routine Description:
  976. Starts an eeinfo enumeration using the passed
  977. EEInfo structure to start the enumeration
  978. Arguments:
  979. EEInfo - the chain we will enumerate
  980. EnumHandle - the enumeration handle
  981. Return Value:
  982. RPC_S_OK or RPC_S_* error
  983. --*/
  984. {
  985. ExtendedErrorInfo *ClonedEEInfo;
  986. RPC_STATUS RpcStatus;
  987. RpcStatus = CloneEEInfoChain(EEInfo, &ClonedEEInfo);
  988. if (RpcStatus != RPC_S_OK)
  989. return RpcStatus;
  990. InitializeEnumHandleWithEEInfo(ClonedEEInfo, EnumHandle);
  991. return RPC_S_OK;
  992. }
  993. RPCRTAPI
  994. RPC_STATUS
  995. RPC_ENTRY
  996. RpcErrorStartEnumeration (
  997. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  998. )
  999. /*++
  1000. Routine Description:
  1001. Starts an eeinfo enumeration using the eeinfo on
  1002. the thread
  1003. Arguments:
  1004. EnumHandle - the enumeration handle. Allocated by caller
  1005. Return Value:
  1006. RPC_S_OK or RPC_S_* error
  1007. --*/
  1008. {
  1009. ExtendedErrorInfo *ClonedEEInfo, *EEInfo;
  1010. RPC_STATUS RpcStatus;
  1011. THREAD *Thread;
  1012. // get the EEInfo from the Teb
  1013. Thread = RpcpGetThreadPointer();
  1014. if (Thread == NULL)
  1015. return RPC_S_ENTRY_NOT_FOUND;
  1016. EEInfo = Thread->GetEEInfo();
  1017. if (EEInfo == NULL)
  1018. return RPC_S_ENTRY_NOT_FOUND;
  1019. return RpcpErrorStartEnumerationFromEEInfo(EEInfo, EnumHandle);
  1020. }
  1021. RPCRTAPI
  1022. RPC_STATUS
  1023. RPC_ENTRY
  1024. RpcErrorGetNextRecord (
  1025. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  1026. IN BOOL CopyStrings,
  1027. OUT RPC_EXTENDED_ERROR_INFO *ErrorInfo
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Retrieves the next private record from the enumeration
  1032. and converts it to public format
  1033. Arguments:
  1034. EnumHandle - the enumeration handle
  1035. CopyStrings - if non-zero, all strings converted to public
  1036. format will be allocated space for on the process heap
  1037. and will be copied there. If FALSE, the strings in the
  1038. public structures will be aliases to the private structure
  1039. ErrorInfo - the public record that will be filled on output
  1040. Return Value:
  1041. RPC_S_OK or RPC_S_* error
  1042. --*/
  1043. {
  1044. RPC_STATUS RpcStatus;
  1045. ExtendedErrorInfo *CurrentRecord;
  1046. ASSERT(EnumHandle != NULL);
  1047. ASSERT(EnumHandle->Head != NULL);
  1048. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1049. if (EnumHandle->Signature != EnumSignatureLive)
  1050. return ERROR_INVALID_PARAMETER;
  1051. if (EnumHandle->CurrentPos == NULL)
  1052. return RPC_S_ENTRY_NOT_FOUND;
  1053. CurrentRecord = (ExtendedErrorInfo *) EnumHandle->CurrentPos;
  1054. RpcStatus = ConvertPrivateEEInfoToPublicEEInfo(CurrentRecord,
  1055. CopyStrings, ErrorInfo);
  1056. if (RpcStatus == RPC_S_OK)
  1057. {
  1058. EnumHandle->CurrentPos = CurrentRecord->Next;
  1059. }
  1060. return RpcStatus;
  1061. }
  1062. RPCRTAPI
  1063. RPC_STATUS
  1064. RPC_ENTRY
  1065. RpcErrorEndEnumeration (
  1066. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Finished the enumeration and frees all resources associated with
  1071. the enumeration
  1072. Arguments:
  1073. EnumHandle - the enumeration handle
  1074. Return Value:
  1075. RPC_S_OK or RPC_S_* error - can fail only if given invalid parameters
  1076. --*/
  1077. {
  1078. ExtendedErrorInfo *EEInfoChain;
  1079. ASSERT(EnumHandle != NULL);
  1080. ASSERT(EnumHandle->Head != NULL);
  1081. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1082. if (EnumHandle->Signature != EnumSignatureLive)
  1083. return ERROR_INVALID_PARAMETER;
  1084. EEInfoChain = (ExtendedErrorInfo *)EnumHandle->Head;
  1085. FreeEEInfoChain(EEInfoChain);
  1086. EnumHandle->Head = NULL;
  1087. EnumHandle->Signature = EnumSignatureDead;
  1088. return RPC_S_OK;
  1089. }
  1090. RPCRTAPI
  1091. RPC_STATUS
  1092. RPC_ENTRY
  1093. RpcErrorResetEnumeration (
  1094. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Reset the enumeration so that the next call to
  1099. RpcErrorGetNextRecord returns the first record
  1100. again.
  1101. Arguments:
  1102. EnumHandle - the enumeration handle
  1103. Return Value:
  1104. RPC_S_OK or RPC_S_* error - can fail only if given invalid
  1105. parameters
  1106. --*/
  1107. {
  1108. ASSERT(EnumHandle != NULL);
  1109. ASSERT(EnumHandle->Head != NULL);
  1110. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1111. if (EnumHandle->Signature != EnumSignatureLive)
  1112. return ERROR_INVALID_PARAMETER;
  1113. EnumHandle->CurrentPos = EnumHandle->Head;
  1114. return RPC_S_OK;
  1115. }
  1116. RPCRTAPI
  1117. RPC_STATUS
  1118. RPC_ENTRY
  1119. RpcErrorGetNumberOfRecords (
  1120. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  1121. OUT int *Records
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. Gets the number of records in the chain that it currently
  1126. enumerated
  1127. Arguments:
  1128. EnumHandle - the enumeration handle
  1129. Records - on output will contain the number of records
  1130. Return Value:
  1131. RPC_S_OK or RPC_S_* error - the function cannot fail unless
  1132. given invalid parameters
  1133. --*/
  1134. {
  1135. ExtendedErrorInfo *CurrentRecord;
  1136. int Count;
  1137. ASSERT(EnumHandle != NULL);
  1138. ASSERT(EnumHandle->Head != NULL);
  1139. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1140. if (EnumHandle->Signature != EnumSignatureLive)
  1141. return ERROR_INVALID_PARAMETER;
  1142. CurrentRecord = (ExtendedErrorInfo *) EnumHandle->Head;
  1143. Count = 0;
  1144. while (CurrentRecord != NULL)
  1145. {
  1146. Count ++;
  1147. CurrentRecord = CurrentRecord->Next;
  1148. }
  1149. *Records = Count;
  1150. return RPC_S_OK;
  1151. }
  1152. RPCRTAPI
  1153. RPC_STATUS
  1154. RPC_ENTRY
  1155. RpcErrorSaveErrorInfo (
  1156. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  1157. OUT PVOID *ErrorBlob,
  1158. OUT size_t *BlobSize
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Saves the eeinfo in the enumeration to a memory block
  1163. Arguments:
  1164. EnumHandle - the enumeration handle
  1165. ErrorBlob - on output the allocated and filled in blob
  1166. containing the eeinfo in binary format
  1167. BlobSize - on output the size of the blob
  1168. Return Value:
  1169. RPC_S_OK or RPC_S_* error
  1170. --*/
  1171. {
  1172. ULONG EncodedSize;
  1173. ExtendedErrorInfo *EEInfo;
  1174. handle_t PickleHandle;
  1175. char *TempBuffer;
  1176. RPC_STATUS RpcStatus;
  1177. ExtendedErrorInfoPtr *EEInfoPtr;
  1178. size_t MarshallSize;
  1179. HANDLE ProcessHeap;
  1180. PVOID Buffer;
  1181. ASSERT(EnumHandle != NULL);
  1182. ASSERT(EnumHandle->Head != NULL);
  1183. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1184. if (EnumHandle->Signature != EnumSignatureLive)
  1185. return ERROR_INVALID_PARAMETER;
  1186. // pickle the eeinfo into a buffer
  1187. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  1188. if (RpcStatus != RPC_S_OK)
  1189. {
  1190. return RpcStatus;
  1191. }
  1192. EEInfo = (ExtendedErrorInfo *) EnumHandle->Head;
  1193. EEInfoPtr = &EEInfo;
  1194. // get the estimated size
  1195. MarshallSize = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  1196. ProcessHeap = RtlProcessHeap();
  1197. Buffer = RtlAllocateHeap(ProcessHeap, 0, MarshallSize);
  1198. if (Buffer == NULL)
  1199. {
  1200. MesHandleFree(PickleHandle);
  1201. return RPC_S_OUT_OF_MEMORY;
  1202. }
  1203. TempBuffer = (char *)Buffer;
  1204. // re-initialize the handle to fixed buffer
  1205. RpcStatus = MesBufferHandleReset(PickleHandle,
  1206. MES_FIXED_BUFFER_HANDLE,
  1207. MES_ENCODE,
  1208. &TempBuffer,
  1209. MarshallSize,
  1210. &EncodedSize);
  1211. if (RpcStatus != RPC_S_OK)
  1212. {
  1213. MesHandleFree(PickleHandle);
  1214. RtlFreeHeap(ProcessHeap, 0, Buffer);
  1215. return RpcStatus;
  1216. }
  1217. // do the pickling itself
  1218. RpcTryExcept
  1219. {
  1220. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  1221. }
  1222. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1223. {
  1224. RpcStatus = RpcExceptionCode();
  1225. }
  1226. RpcEndExcept
  1227. if (RpcStatus != RPC_S_OK)
  1228. {
  1229. MesHandleFree(PickleHandle);
  1230. RtlFreeHeap(ProcessHeap, 0, Buffer);
  1231. return RpcStatus;
  1232. }
  1233. // whack out the rest, to prevent random process data going out on the wire/disk
  1234. RpcpMemorySet((unsigned char *)Buffer + EncodedSize, 0, MarshallSize - EncodedSize);
  1235. MesHandleFree(PickleHandle);
  1236. *ErrorBlob = Buffer;
  1237. *BlobSize = EncodedSize;
  1238. return RPC_S_OK;
  1239. }
  1240. RPCRTAPI
  1241. RPC_STATUS
  1242. RPC_ENTRY
  1243. RpcErrorLoadErrorInfo (
  1244. IN PVOID ErrorBlob,
  1245. IN size_t BlobSize,
  1246. OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. Creates an enumeration from a blob
  1251. Arguments:
  1252. ErrorBlob - the blob as obtained by RpcErrorSaveErrorInfo
  1253. BlobSize - the size of the blob as obtained by RpcErrorSaveErrorInfo
  1254. EnumHandle - the enumeration handle allocated by the caller
  1255. and filled on output
  1256. Return Value:
  1257. RPC_S_OK or RPC_S_* error
  1258. --*/
  1259. {
  1260. RPC_STATUS RpcStatus;
  1261. ExtendedErrorInfo *EEInfo;
  1262. RpcStatus = UnpickleEEInfo((unsigned char *)ErrorBlob, BlobSize, &EEInfo);
  1263. if (RpcStatus != RPC_S_OK)
  1264. return RpcStatus;
  1265. InitializeEnumHandleWithEEInfo(EEInfo, EnumHandle);
  1266. return RPC_S_OK;
  1267. }
  1268. RPC_STATUS
  1269. AddPrivateRecord (
  1270. IN ExtendedErrorInfo *ErrorInfo
  1271. )
  1272. /*++
  1273. Routine Description:
  1274. Adds the supplied record to the top of the chain in the teb
  1275. N.B. There can be no additional failure paths in the callers
  1276. after this function. This is because it will chain this
  1277. record to the teb, and if we bail out later, the teb will
  1278. point to invalid record.
  1279. Arguments:
  1280. ErrorInfo - the eeinfo record to add to the chain
  1281. Return Value:
  1282. RPC_S_OK or RPC_S_* error - the function cannot fail if the
  1283. RPC per-thread object has already been allocated for this
  1284. thread
  1285. --*/
  1286. {
  1287. THREAD *Thread;
  1288. Thread = ThreadSelf();
  1289. if (Thread == NULL)
  1290. return RPC_S_OUT_OF_MEMORY;
  1291. ErrorInfo->Next = Thread->GetEEInfo();
  1292. Thread->SetEEInfo(ErrorInfo);
  1293. return RPC_S_OK;
  1294. }
  1295. inline LPWSTR
  1296. ReplaceWithEmptyStringIfNull (
  1297. IN LPWSTR String
  1298. )
  1299. {
  1300. return (String ? String : L"");
  1301. }
  1302. inline LPSTR
  1303. ReplaceWithEmptyStringIfNull (
  1304. IN LPSTR String
  1305. )
  1306. {
  1307. return (String ? String : "");
  1308. }
  1309. void
  1310. RpcpErrorAddRecord (
  1311. ULONG GeneratingComponent,
  1312. ULONG Status,
  1313. USHORT DetectionLocation,
  1314. int NumberOfParameters,
  1315. ExtendedErrorParam *Params
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. Adds an extended error info to the thread. The
  1320. following is a description of how fields are set:
  1321. Next - will be set to the next record.
  1322. ComputerName - will be set to not-present (eecnpNotPresent)
  1323. ProcessID - will be set to the process ID
  1324. TimeStamp - will be set to the current time
  1325. GeneratingComponent - set to GeneratingComponent
  1326. Status - set to Status
  1327. DetectionLocation - set to DetectionLocation
  1328. Flags - set to 0.
  1329. nLen - set to NumberOfParameters
  1330. Params will be copied to the parameters array. The caller can
  1331. allocate them off the stack if it wants.
  1332. N.B. The runtime should never directly call this function. If it
  1333. needs to add records, it should call one of the overloaded
  1334. RpcpErrorAddRecord functions below. If there isn't one suitable,
  1335. add one. All the RpcpErrorAddRecord functions below are just
  1336. syntactic sugar for this function.
  1337. Arguments:
  1338. GeneratingComponent - will be set in the record
  1339. Status - will be set in the record
  1340. DetectionLocation - will be set in the record
  1341. NumberOfParameters - the number of parameters in the Params array
  1342. Params - the parameters to add
  1343. Return Value:
  1344. void - this is a best effort - no guarantees. Even if we
  1345. return failure, there's little the caller can do about it.
  1346. --*/
  1347. {
  1348. ExtendedErrorInfo *NewRecord;
  1349. RPC_STATUS RpcStatus;
  1350. int i;
  1351. LogEvent(SU_EEINFO,
  1352. (char)GeneratingComponent,
  1353. ULongToPtr(Status),
  1354. ULongToPtr(DetectionLocation),
  1355. (NumberOfParameters > 0) ? Params[0].LVal : 0);
  1356. NewRecord = AllocateExtendedErrorInfoRecord(NumberOfParameters);
  1357. if (NewRecord == NULL)
  1358. return;
  1359. InitializePrivateEEInfo(NewRecord);
  1360. NewRecord->DetectionLocation = DetectionLocation;
  1361. NewRecord->GeneratingComponent = GeneratingComponent;
  1362. NewRecord->Status = Status;
  1363. for (i = 0; i < NumberOfParameters; i ++)
  1364. {
  1365. // all parameter types requiring an allocation have already
  1366. // been copied by our caller - no need to clone - we can just
  1367. // do shallow copy
  1368. RpcpMemoryCopy(&NewRecord->Params[i], &Params[i], sizeof(ExtendedErrorParam));
  1369. }
  1370. RpcStatus = AddPrivateRecord(NewRecord);
  1371. if (RpcStatus != RPC_S_OK)
  1372. {
  1373. FreeEEInfoRecord(NewRecord);
  1374. }
  1375. }
  1376. void
  1377. RpcpErrorAddRecord (
  1378. IN ULONG GeneratingComponent,
  1379. IN ULONG Status,
  1380. IN USHORT DetectionLocation,
  1381. IN ULONG Long,
  1382. IN short Short,
  1383. IN ULONG Long2
  1384. )
  1385. /*++
  1386. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1387. USHORT, int, ExtendedErrorParam*) above
  1388. --*/
  1389. {
  1390. ExtendedErrorParam Params[3];
  1391. Params[0].Type = eeptiLongVal;
  1392. Params[0].LVal = (long)Long;
  1393. Params[1].Type = eeptiShortVal;
  1394. Params[1].IVal = Short;
  1395. Params[2].Type = eeptiLongVal;
  1396. Params[2].LVal = (long)Long2;
  1397. RpcpErrorAddRecord (GeneratingComponent,
  1398. Status,
  1399. DetectionLocation,
  1400. 3,
  1401. Params);
  1402. }
  1403. void
  1404. RpcpErrorAddRecord (
  1405. IN ULONG GeneratingComponent,
  1406. IN ULONG Status,
  1407. IN USHORT DetectionLocation,
  1408. IN ULONG Long,
  1409. IN short Short,
  1410. IN ULONG Long2,
  1411. IN ULONG Long3
  1412. )
  1413. /*++
  1414. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1415. USHORT, int, ExtendedErrorParam*) above
  1416. --*/
  1417. {
  1418. ExtendedErrorParam Params[4];
  1419. Params[0].Type = eeptiLongVal;
  1420. Params[0].LVal = (long)Long;
  1421. Params[1].Type = eeptiShortVal;
  1422. Params[1].IVal = Short;
  1423. Params[2].Type = eeptiLongVal;
  1424. Params[2].LVal = (long)Long2;
  1425. Params[3].Type = eeptiLongVal;
  1426. Params[3].LVal = (long)Long3;
  1427. RpcpErrorAddRecord (GeneratingComponent,
  1428. Status,
  1429. DetectionLocation,
  1430. 4,
  1431. Params);
  1432. }
  1433. void
  1434. RpcpErrorAddRecord (
  1435. IN ULONG GeneratingComponent,
  1436. IN ULONG Status,
  1437. IN USHORT DetectionLocation,
  1438. IN ULONG Long,
  1439. IN ULONG Long2
  1440. )
  1441. /*++
  1442. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1443. USHORT, int, ExtendedErrorParam*) above
  1444. --*/
  1445. {
  1446. ExtendedErrorParam Params[2];
  1447. Params[0].Type = eeptiLongVal;
  1448. Params[0].LVal = (long)Long;
  1449. Params[1].Type = eeptiLongVal;
  1450. Params[1].LVal = (long)Long2;
  1451. RpcpErrorAddRecord (GeneratingComponent,
  1452. Status,
  1453. DetectionLocation,
  1454. 2,
  1455. Params);
  1456. }
  1457. void
  1458. RpcpErrorAddRecord (
  1459. IN ULONG GeneratingComponent,
  1460. IN ULONG Status,
  1461. IN USHORT DetectionLocation,
  1462. IN LPWSTR String1,
  1463. IN LPWSTR String2
  1464. )
  1465. /*++
  1466. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1467. USHORT, int, ExtendedErrorParam*) above
  1468. --*/
  1469. {
  1470. ExtendedErrorParam Params[2];
  1471. RPC_STATUS RpcStatus;
  1472. int i;
  1473. LPWSTR Strings[2];
  1474. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1475. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1476. for (i = 0; i < 2; i ++)
  1477. {
  1478. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1479. &Params[i].UnicodeString);
  1480. if (RpcStatus == RPC_S_OK)
  1481. {
  1482. Params[i].Type = eeptiUnicodeString;
  1483. }
  1484. else
  1485. {
  1486. Params[i].Type = eeptiNone;
  1487. }
  1488. }
  1489. RpcpErrorAddRecord (GeneratingComponent,
  1490. Status,
  1491. DetectionLocation,
  1492. 2,
  1493. Params);
  1494. }
  1495. void
  1496. RpcpErrorAddRecord (
  1497. IN ULONG GeneratingComponent,
  1498. IN ULONG Status,
  1499. IN USHORT DetectionLocation,
  1500. IN LPWSTR String1,
  1501. IN LPWSTR String2,
  1502. IN ULONG Long1,
  1503. IN ULONG Long2
  1504. )
  1505. /*++
  1506. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1507. USHORT, int, ExtendedErrorParam*) above
  1508. --*/
  1509. {
  1510. ExtendedErrorParam Params[4];
  1511. RPC_STATUS RpcStatus;
  1512. int i;
  1513. LPWSTR Strings[2];
  1514. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1515. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1516. for (i = 0; i < 2; i ++)
  1517. {
  1518. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1519. &Params[i].UnicodeString);
  1520. if (RpcStatus == RPC_S_OK)
  1521. {
  1522. Params[i].Type = eeptiUnicodeString;
  1523. }
  1524. else
  1525. {
  1526. Params[i].Type = eeptiNone;
  1527. }
  1528. }
  1529. Params[2].Type = eeptiLongVal;
  1530. Params[2].LVal = (long)Long1;
  1531. Params[3].Type = eeptiLongVal;
  1532. Params[3].LVal = (long)Long2;
  1533. RpcpErrorAddRecord (GeneratingComponent,
  1534. Status,
  1535. DetectionLocation,
  1536. 4,
  1537. Params);
  1538. }
  1539. void
  1540. RpcpErrorAddRecord (
  1541. IN ULONG GeneratingComponent,
  1542. IN ULONG Status,
  1543. IN USHORT DetectionLocation,
  1544. IN LPWSTR String1,
  1545. IN LPWSTR String2,
  1546. IN ULONG Long1,
  1547. IN ULONGLONG PVal1
  1548. )
  1549. /*++
  1550. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1551. USHORT, int, ExtendedErrorParam*) above
  1552. --*/
  1553. {
  1554. ExtendedErrorParam Params[4];
  1555. RPC_STATUS RpcStatus;
  1556. int i;
  1557. LPWSTR Strings[2];
  1558. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1559. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1560. for (i = 0; i < 2; i ++)
  1561. {
  1562. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1563. &Params[i].UnicodeString);
  1564. if (RpcStatus == RPC_S_OK)
  1565. {
  1566. Params[i].Type = eeptiUnicodeString;
  1567. }
  1568. else
  1569. {
  1570. Params[i].Type = eeptiNone;
  1571. }
  1572. }
  1573. Params[2].Type = eeptiLongVal;
  1574. Params[2].LVal = (long)Long1;
  1575. Params[3].Type = eeptiPointerVal;
  1576. Params[3].PVal = (long)PVal1;
  1577. RpcpErrorAddRecord (GeneratingComponent,
  1578. Status,
  1579. DetectionLocation,
  1580. 4,
  1581. Params);
  1582. }
  1583. void
  1584. RpcpErrorAddRecord (
  1585. IN ULONG GeneratingComponent,
  1586. IN ULONG Status,
  1587. IN USHORT DetectionLocation,
  1588. IN ULONG Long1,
  1589. IN ULONG Long2,
  1590. IN LPWSTR String,
  1591. IN ULONG Long3
  1592. )
  1593. /*++
  1594. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1595. USHORT, int, ExtendedErrorParam*) above
  1596. --*/
  1597. {
  1598. ExtendedErrorParam Params[4];
  1599. RPC_STATUS RpcStatus;
  1600. Params[0].Type = eeptiLongVal;
  1601. Params[0].LVal = (long)Long1;
  1602. Params[1].Type = eeptiLongVal;
  1603. Params[1].LVal = (long)Long2;
  1604. Params[3].Type = eeptiLongVal;
  1605. Params[3].LVal = (long)Long3;
  1606. RpcStatus = ConvertPublicStringToPrivateString(
  1607. ReplaceWithEmptyStringIfNull(String),
  1608. &Params[2].UnicodeString);
  1609. if (RpcStatus == RPC_S_OK)
  1610. {
  1611. Params[2].Type = eeptiUnicodeString;
  1612. }
  1613. else
  1614. {
  1615. Params[2].Type = eeptiNone;
  1616. }
  1617. RpcpErrorAddRecord (GeneratingComponent,
  1618. Status,
  1619. DetectionLocation,
  1620. 4,
  1621. Params);
  1622. }
  1623. void
  1624. RpcpErrorAddRecord (
  1625. IN ULONG GeneratingComponent,
  1626. IN ULONG Status,
  1627. IN USHORT DetectionLocation,
  1628. IN LPWSTR String,
  1629. IN ULONG Long
  1630. )
  1631. /*++
  1632. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1633. USHORT, int, ExtendedErrorParam*) above
  1634. --*/
  1635. {
  1636. ExtendedErrorParam Params[2];
  1637. RPC_STATUS RpcStatus;
  1638. Params[0].Type = eeptiLongVal;
  1639. Params[0].LVal = (long)Long;
  1640. RpcStatus = ConvertPublicStringToPrivateString(
  1641. ReplaceWithEmptyStringIfNull(String),
  1642. &Params[1].UnicodeString);
  1643. if (RpcStatus == RPC_S_OK)
  1644. {
  1645. Params[1].Type = eeptiUnicodeString;
  1646. }
  1647. else
  1648. {
  1649. Params[1].Type = eeptiNone;
  1650. }
  1651. RpcpErrorAddRecord (GeneratingComponent,
  1652. Status,
  1653. DetectionLocation,
  1654. 2,
  1655. Params);
  1656. }
  1657. void
  1658. RpcpErrorAddRecord (
  1659. IN ULONG GeneratingComponent,
  1660. IN ULONG Status,
  1661. IN USHORT DetectionLocation,
  1662. IN LPWSTR String,
  1663. IN ULONG Long1,
  1664. IN ULONG Long2
  1665. )
  1666. /*++
  1667. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1668. USHORT, int, ExtendedErrorParam*) above
  1669. --*/
  1670. {
  1671. ExtendedErrorParam Params[3];
  1672. RPC_STATUS RpcStatus;
  1673. Params[1].Type = eeptiLongVal;
  1674. Params[1].LVal = (long)Long1;
  1675. Params[2].Type = eeptiLongVal;
  1676. Params[2].LVal = (long)Long2;
  1677. RpcStatus = ConvertPublicStringToPrivateString(
  1678. ReplaceWithEmptyStringIfNull(String),
  1679. &Params[0].UnicodeString);
  1680. if (RpcStatus == RPC_S_OK)
  1681. {
  1682. Params[0].Type = eeptiUnicodeString;
  1683. }
  1684. else
  1685. {
  1686. Params[0].Type = eeptiNone;
  1687. }
  1688. RpcpErrorAddRecord (GeneratingComponent,
  1689. Status,
  1690. DetectionLocation,
  1691. 3,
  1692. Params);
  1693. }
  1694. void
  1695. RpcpErrorAddRecord (
  1696. IN ULONG GeneratingComponent,
  1697. IN ULONG Status,
  1698. IN USHORT DetectionLocation,
  1699. IN LPWSTR String
  1700. )
  1701. /*++
  1702. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1703. USHORT, int, ExtendedErrorParam*) above
  1704. --*/
  1705. {
  1706. ExtendedErrorParam Params[1];
  1707. RPC_STATUS RpcStatus;
  1708. RpcStatus = ConvertPublicStringToPrivateString(
  1709. ReplaceWithEmptyStringIfNull(String),
  1710. &Params[0].UnicodeString);
  1711. if (RpcStatus == RPC_S_OK)
  1712. {
  1713. Params[0].Type = eeptiUnicodeString;
  1714. }
  1715. else
  1716. {
  1717. Params[0].Type = eeptiNone;
  1718. }
  1719. RpcpErrorAddRecord (GeneratingComponent,
  1720. Status,
  1721. DetectionLocation,
  1722. 1,
  1723. Params);
  1724. }
  1725. void
  1726. RpcpErrorAddRecord (
  1727. IN ULONG GeneratingComponent,
  1728. IN ULONG Status,
  1729. IN USHORT DetectionLocation,
  1730. IN LPSTR String
  1731. )
  1732. /*++
  1733. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1734. USHORT, int, ExtendedErrorParam*) above
  1735. --*/
  1736. {
  1737. ExtendedErrorParam Params[1];
  1738. RPC_STATUS RpcStatus;
  1739. RpcStatus = ConvertPublicStringToPrivateString(
  1740. ReplaceWithEmptyStringIfNull(String),
  1741. &Params[0].AnsiString);
  1742. if (RpcStatus == RPC_S_OK)
  1743. {
  1744. Params[0].Type = eeptiAnsiString;
  1745. }
  1746. else
  1747. {
  1748. Params[0].Type = eeptiNone;
  1749. }
  1750. RpcpErrorAddRecord (GeneratingComponent,
  1751. Status,
  1752. DetectionLocation,
  1753. 1,
  1754. Params);
  1755. }
  1756. void
  1757. RpcpErrorAddRecord (
  1758. IN ULONG GeneratingComponent,
  1759. IN ULONG Status,
  1760. IN USHORT DetectionLocation,
  1761. IN ULONG Long,
  1762. IN ULONG Long2,
  1763. IN ULONG Long3
  1764. )
  1765. /*++
  1766. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1767. USHORT, int, ExtendedErrorParam*) above
  1768. --*/
  1769. {
  1770. ExtendedErrorParam Params[3];
  1771. Params[0].Type = eeptiLongVal;
  1772. Params[0].LVal = (long)Long;
  1773. Params[1].Type = eeptiLongVal;
  1774. Params[1].LVal = (long)Long2;
  1775. Params[2].Type = eeptiLongVal;
  1776. Params[2].LVal = (long)Long3;
  1777. RpcpErrorAddRecord (GeneratingComponent,
  1778. Status,
  1779. DetectionLocation,
  1780. 3,
  1781. Params);
  1782. }
  1783. void
  1784. RpcpErrorAddRecord (
  1785. IN ULONG GeneratingComponent,
  1786. IN ULONG Status,
  1787. IN USHORT DetectionLocation,
  1788. IN ULONGLONG PVal1,
  1789. IN ULONGLONG PVal2,
  1790. IN ULONG Long
  1791. )
  1792. /*++
  1793. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1794. USHORT, int, ExtendedErrorParam*) above
  1795. --*/
  1796. {
  1797. ExtendedErrorParam Params[3];
  1798. Params[0].Type = eeptiPointerVal;
  1799. Params[0].PVal = PVal1;
  1800. Params[1].Type = eeptiPointerVal;
  1801. Params[1].PVal = PVal2;
  1802. Params[2].Type = eeptiLongVal;
  1803. Params[2].LVal = (long)Long;
  1804. RpcpErrorAddRecord (GeneratingComponent,
  1805. Status,
  1806. DetectionLocation,
  1807. 3,
  1808. Params);
  1809. }
  1810. void
  1811. RpcpErrorAddRecord (
  1812. IN ULONG GeneratingComponent,
  1813. IN ULONG Status,
  1814. IN USHORT DetectionLocation,
  1815. IN ULONGLONG PVal1,
  1816. IN ULONGLONG PVal2,
  1817. IN ULONG Long1,
  1818. IN ULONG Long2
  1819. )
  1820. /*++
  1821. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1822. USHORT, int, ExtendedErrorParam*) above
  1823. --*/
  1824. {
  1825. ExtendedErrorParam Params[4];
  1826. Params[0].Type = eeptiPointerVal;
  1827. Params[0].PVal = PVal1;
  1828. Params[1].Type = eeptiPointerVal;
  1829. Params[1].PVal = PVal2;
  1830. Params[2].Type = eeptiLongVal;
  1831. Params[2].LVal = (long)Long1;
  1832. Params[3].Type = eeptiLongVal;
  1833. Params[3].LVal = (long)Long2;
  1834. RpcpErrorAddRecord (GeneratingComponent,
  1835. Status,
  1836. DetectionLocation,
  1837. 4,
  1838. Params);
  1839. }
  1840. void
  1841. RpcpErrorAddRecord (
  1842. IN ULONG GeneratingComponent,
  1843. IN ULONG Status,
  1844. IN USHORT DetectionLocation,
  1845. IN ULONGLONG PVal1,
  1846. IN ULONGLONG PVal2
  1847. )
  1848. /*++
  1849. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1850. USHORT, int, ExtendedErrorParam*) above
  1851. --*/
  1852. {
  1853. ExtendedErrorParam Params[2];
  1854. Params[0].Type = eeptiPointerVal;
  1855. Params[0].PVal = PVal1;
  1856. Params[1].Type = eeptiPointerVal;
  1857. Params[1].PVal = PVal2;
  1858. RpcpErrorAddRecord (GeneratingComponent,
  1859. Status,
  1860. DetectionLocation,
  1861. 2,
  1862. Params);
  1863. }
  1864. void
  1865. RpcpErrorAddRecord (
  1866. IN ULONG GeneratingComponent,
  1867. IN ULONG Status,
  1868. IN USHORT DetectionLocation,
  1869. IN ULONGLONG PVal1,
  1870. IN ULONG LVal1
  1871. )
  1872. /*++
  1873. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1874. USHORT, int, ExtendedErrorParam*) above
  1875. --*/
  1876. {
  1877. ExtendedErrorParam Params[2];
  1878. Params[0].Type = eeptiPointerVal;
  1879. Params[0].PVal = PVal1;
  1880. Params[1].Type = eeptiLongVal;
  1881. Params[1].PVal = LVal1;
  1882. RpcpErrorAddRecord (GeneratingComponent,
  1883. Status,
  1884. DetectionLocation,
  1885. 2,
  1886. Params);
  1887. }
  1888. void
  1889. RpcpErrorAddRecord (
  1890. IN ULONG GeneratingComponent,
  1891. IN ULONG Status,
  1892. IN USHORT DetectionLocation,
  1893. IN ULONG Long,
  1894. IN ULONGLONG PVal1
  1895. )
  1896. /*++
  1897. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1898. USHORT, int, ExtendedErrorParam*) above
  1899. --*/
  1900. {
  1901. ExtendedErrorParam Params[2];
  1902. Params[0].Type = eeptiLongVal;
  1903. Params[0].LVal = Long;
  1904. Params[1].Type = eeptiPointerVal;
  1905. Params[1].PVal = PVal1;
  1906. RpcpErrorAddRecord (GeneratingComponent,
  1907. Status,
  1908. DetectionLocation,
  1909. 2,
  1910. Params);
  1911. }
  1912. void
  1913. RpcpErrorAddRecord (
  1914. IN ULONG GeneratingComponent,
  1915. IN ULONG Status,
  1916. IN USHORT DetectionLocation,
  1917. IN ULONG Long,
  1918. IN ULONGLONG PVal1,
  1919. IN ULONGLONG PVal2
  1920. )
  1921. /*++
  1922. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1923. USHORT, int, ExtendedErrorParam*) above
  1924. --*/
  1925. {
  1926. ExtendedErrorParam Params[3];
  1927. Params[0].Type = eeptiLongVal;
  1928. Params[0].LVal = (long)Long;
  1929. Params[1].Type = eeptiPointerVal;
  1930. Params[1].PVal = PVal1;
  1931. Params[2].Type = eeptiPointerVal;
  1932. Params[2].PVal = PVal2;
  1933. RpcpErrorAddRecord (GeneratingComponent,
  1934. Status,
  1935. DetectionLocation,
  1936. 3,
  1937. Params);
  1938. }
  1939. void
  1940. RpcpErrorAddRecord (
  1941. IN ULONG GeneratingComponent,
  1942. IN ULONG Status,
  1943. IN USHORT DetectionLocation,
  1944. IN ULONG Long
  1945. )
  1946. /*++
  1947. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1948. USHORT, int, ExtendedErrorParam*) above
  1949. --*/
  1950. {
  1951. ExtendedErrorParam Params[1];
  1952. Params[0].Type = eeptiLongVal;
  1953. Params[0].LVal = (long)Long;
  1954. RpcpErrorAddRecord (GeneratingComponent,
  1955. Status,
  1956. DetectionLocation,
  1957. 1,
  1958. Params);
  1959. }
  1960. void
  1961. RpcpErrorAddRecord (
  1962. IN ULONG GeneratingComponent,
  1963. IN ULONG Status,
  1964. IN USHORT DetectionLocation,
  1965. IN ULONG LVal1,
  1966. IN ULONGLONG PVal1,
  1967. IN ULONG LVal2
  1968. )
  1969. /*++
  1970. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1971. USHORT, int, ExtendedErrorParam*) above
  1972. --*/
  1973. {
  1974. ExtendedErrorParam Params[3];
  1975. Params[0].Type = eeptiLongVal;
  1976. Params[0].LVal = (long)LVal1;
  1977. Params[1].Type = eeptiPointerVal;
  1978. Params[1].PVal = PVal1;
  1979. Params[2].Type = eeptiLongVal;
  1980. Params[2].LVal = (long)LVal2;
  1981. RpcpErrorAddRecord (GeneratingComponent,
  1982. Status,
  1983. DetectionLocation,
  1984. 3,
  1985. Params);
  1986. }
  1987. void
  1988. RpcpErrorAddRecord (
  1989. IN ULONG GeneratingComponent,
  1990. IN ULONG Status,
  1991. IN USHORT DetectionLocation,
  1992. IN ULONG LVal1,
  1993. IN ULONG LVal2,
  1994. IN ULONG LVal3,
  1995. IN ULONGLONG PVal1
  1996. )
  1997. /*++
  1998. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1999. USHORT, int, ExtendedErrorParam*) above
  2000. --*/
  2001. {
  2002. ExtendedErrorParam Params[4];
  2003. Params[0].Type = eeptiLongVal;
  2004. Params[0].LVal = (long)LVal1;
  2005. Params[1].Type = eeptiLongVal;
  2006. Params[1].LVal = (long)LVal2;
  2007. Params[2].Type = eeptiLongVal;
  2008. Params[2].LVal = (long)LVal3;
  2009. Params[3].Type = eeptiPointerVal;
  2010. Params[3].PVal = PVal1;
  2011. RpcpErrorAddRecord (GeneratingComponent,
  2012. Status,
  2013. DetectionLocation,
  2014. 3,
  2015. Params);
  2016. }
  2017. void
  2018. RpcpErrorAddRecord (
  2019. IN ULONG GeneratingComponent,
  2020. IN ULONG Status,
  2021. IN USHORT DetectionLocation,
  2022. IN ULONG LVal1,
  2023. IN ULONG LVal2,
  2024. IN ULONG LVal3,
  2025. IN ULONG LVal4
  2026. )
  2027. /*++
  2028. See description of RpcpErrorAddRecord(ULONG, ULONG,
  2029. USHORT, int, ExtendedErrorParam*) above
  2030. --*/
  2031. {
  2032. ExtendedErrorParam Params[4];
  2033. Params[0].Type = eeptiLongVal;
  2034. Params[0].LVal = (long)LVal1;
  2035. Params[1].Type = eeptiLongVal;
  2036. Params[1].LVal = (long)LVal2;
  2037. Params[2].Type = eeptiLongVal;
  2038. Params[2].LVal = (long)LVal3;
  2039. Params[3].Type = eeptiLongVal;
  2040. Params[3].PVal = LVal4;
  2041. RpcpErrorAddRecord (GeneratingComponent,
  2042. Status,
  2043. DetectionLocation,
  2044. 3,
  2045. Params);
  2046. }
  2047. RPCRTAPI
  2048. RPC_STATUS
  2049. RPC_ENTRY
  2050. RpcErrorAddRecord (
  2051. IN RPC_EXTENDED_ERROR_INFO *ErrorInfo
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. Adds the supplied record to the top of the chain in the teb
  2056. Arguments:
  2057. ErrorInfo - the eeinfo record to add to the chain
  2058. Return Value:
  2059. RPC_S_OK or RPC_S_* error
  2060. --*/
  2061. {
  2062. ExtendedErrorInfo *NewRecord;
  2063. RPC_STATUS RpcStatus;
  2064. if (ErrorInfo->Version != RPC_EEINFO_VERSION)
  2065. return ERROR_INVALID_PARAMETER;
  2066. if (ErrorInfo->ComputerName != NULL)
  2067. return ERROR_INVALID_PARAMETER;
  2068. if (ErrorInfo->Flags != 0)
  2069. return ERROR_INVALID_PARAMETER;
  2070. if (ErrorInfo->NumberOfParameters < 0)
  2071. return ERROR_INVALID_PARAMETER;
  2072. if (ErrorInfo->NumberOfParameters > MaxNumberOfEEInfoParams)
  2073. return ERROR_INVALID_PARAMETER;
  2074. if (ErrorInfo->DetectionLocation != 0)
  2075. return ERROR_INVALID_PARAMETER;
  2076. // EEInfoGCCOM can come externally. If it's not EEInfoGCCOM, it must be 0
  2077. if ((ErrorInfo->GeneratingComponent != 0) && (ErrorInfo->GeneratingComponent != EEInfoGCCOM))
  2078. return ERROR_INVALID_PARAMETER;
  2079. if (ErrorInfo->ProcessID != 0)
  2080. return ERROR_INVALID_PARAMETER;
  2081. NewRecord = AllocateExtendedErrorInfoRecord(ErrorInfo->NumberOfParameters);
  2082. if (NewRecord == NULL)
  2083. return RPC_S_OUT_OF_MEMORY;
  2084. RpcStatus = ConvertPublicEEInfoToPrivateEEInfo(ErrorInfo, EEInfoDLApi, NewRecord);
  2085. if (RpcStatus != RPC_S_OK)
  2086. {
  2087. FreeEEInfoRecordShallow(NewRecord);
  2088. return RpcStatus;
  2089. }
  2090. RpcStatus = AddPrivateRecord(NewRecord);
  2091. if (RpcStatus != RPC_S_OK)
  2092. {
  2093. FreeEEInfoRecord(NewRecord);
  2094. }
  2095. return RpcStatus;
  2096. }
  2097. RPCRTAPI
  2098. void
  2099. RPC_ENTRY
  2100. RpcErrorClearInformation (
  2101. void
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. Clears the existing eeinfo on the teb (if any)
  2106. Arguments:
  2107. void
  2108. Return Value:
  2109. void
  2110. --*/
  2111. {
  2112. ExtendedErrorInfo *EEInfo;
  2113. THREAD *Thread;
  2114. Thread = RpcpGetThreadPointer();
  2115. if (Thread == NULL)
  2116. return;
  2117. EEInfo = Thread->GetEEInfo();
  2118. Thread->SetEEInfo(NULL);
  2119. FreeEEInfoChain(EEInfo);
  2120. }
  2121. BOOL
  2122. KnockOffLastButOneEEInfoRecord (
  2123. IN ExtendedErrorInfo *EEInfo
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. Will delete the last-but-one record from the chain. If there
  2128. are two or less record, nothing is deleted, and FALSE gets
  2129. returned.
  2130. Arguments:
  2131. EEInfo - the extended error info chain
  2132. Return Value:
  2133. TRUE - a record was deleted
  2134. FALSE - there were two or less records, and nothing was deleted.
  2135. --*/
  2136. {
  2137. ExtendedErrorInfo *NextRecord, *LastButOneRecord;
  2138. ExtendedErrorInfo *PreviousRecord;
  2139. LastButOneRecord = NextRecord = EEInfo;
  2140. while ((NextRecord != NULL) && (NextRecord->Next != NULL))
  2141. {
  2142. PreviousRecord = LastButOneRecord;
  2143. LastButOneRecord = NextRecord;
  2144. NextRecord = NextRecord->Next;
  2145. }
  2146. if ((NextRecord == EEInfo) || (LastButOneRecord == EEInfo))
  2147. {
  2148. return FALSE;
  2149. }
  2150. PreviousRecord->Next = NextRecord;
  2151. // indicate that the chain has been broken
  2152. PreviousRecord->Flags |= EEInfoNextRecordsMissing;
  2153. NextRecord->Flags |= EEInfoPreviousRecordsMissing;
  2154. // move the computer name up if necessary
  2155. if ((LastButOneRecord->ComputerName.Type == eecnpPresent)
  2156. && (NextRecord->ComputerName.Type == eecnpNotPresent))
  2157. {
  2158. // N.B. Not covered by unit tests
  2159. LastButOneRecord->ComputerName.Type = eecnpNotPresent;
  2160. NextRecord->ComputerName.Type = eecnpPresent;
  2161. NextRecord->ComputerName.Name.nLength = LastButOneRecord->ComputerName.Name.nLength;
  2162. NextRecord->ComputerName.Name.pString = LastButOneRecord->ComputerName.Name.pString;
  2163. }
  2164. FreeEEInfoRecord(LastButOneRecord);
  2165. return TRUE;
  2166. }
  2167. RPC_STATUS
  2168. TrimEEInfoToLengthByRemovingRecords (
  2169. IN ExtendedErrorInfo *EEInfo,
  2170. IN size_t MaxLength,
  2171. OUT BOOL *fTrimmedEnough,
  2172. OUT size_t *NeededLength
  2173. )
  2174. /*++
  2175. Routine Description:
  2176. This function removes records, until either two records are
  2177. left, or the pickled length drops below MaxLength. If the
  2178. pickled length is below the MaxLength to start with, no
  2179. records should be dropped. The records are dropped starting
  2180. from the last-but-one, and going backwards (towards the
  2181. current record). The previous and next records should
  2182. have their chain broken flags set, and the computer name
  2183. should be moved up the chain, if the last record has
  2184. no computer name.
  2185. Arguments:
  2186. EEInfo - the EE chain
  2187. MaxLength - the length that we need to trim to.
  2188. fTrimmedEnough - will be set to TRUE if the pickled length
  2189. on return from this function fits in MaxLength. Undefined
  2190. if the return value is not RPC_S_OK
  2191. NeededLength - if fTrimmedEnough was set to TRUE, and the
  2192. return value is RPC_S_OK, the current pickled length.
  2193. Otherwise, this value must not be touched (i.e. use
  2194. a local variable until you're sure that both conditions
  2195. are true).
  2196. Return Value:
  2197. RPC_S_OK on success.
  2198. != RPC_S_OK on error. On error, fTrimmedEnough is undefined, and
  2199. NeededLength is not touched.
  2200. --*/
  2201. {
  2202. ULONG EncodedSize;
  2203. handle_t PickleHandle = NULL;
  2204. char *TempBuffer;
  2205. RPC_STATUS RpcStatus;
  2206. ExtendedErrorInfoPtr *EEInfoPtr;
  2207. PVOID Buffer = NULL;
  2208. size_t CurrentlyNeededLength;
  2209. size_t PickleLength;
  2210. size_t BufferLength;
  2211. BOOL Result;
  2212. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  2213. if (RpcStatus != RPC_S_OK)
  2214. {
  2215. return RpcStatus;
  2216. }
  2217. // our first goal is to drive the pickled length to less than 2 times
  2218. // the MaxLength. Since the actual pickling often takes less than the
  2219. // estimated, we will do the fine tuning by actually pickling and measuring
  2220. // the resulting size. For the rough tuning, we will use the estimate, and
  2221. // knock off it, if we are over the estimate
  2222. CurrentlyNeededLength = MaxLength * 2;
  2223. while (TRUE)
  2224. {
  2225. EEInfoPtr = &EEInfo;
  2226. // get the estimated size
  2227. PickleLength = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  2228. if (PickleLength <= CurrentlyNeededLength)
  2229. {
  2230. break;
  2231. }
  2232. // knock off the last-but-one element
  2233. Result = KnockOffLastButOneEEInfoRecord(EEInfo);
  2234. if (Result == FALSE)
  2235. {
  2236. *fTrimmedEnough = FALSE;
  2237. goto SuccessCleanupAndExit;
  2238. }
  2239. }
  2240. // here, the PickleHandle should be valid, and ready for actual pickling
  2241. // do the fine-tuned trimming - actually pickle, and see whether it fits
  2242. Buffer = MIDL_user_allocate(PickleLength);
  2243. if (Buffer == NULL)
  2244. {
  2245. RpcStatus = RPC_S_OUT_OF_MEMORY;
  2246. goto CleanupAndExit;
  2247. }
  2248. BufferLength = PickleLength;
  2249. TempBuffer = (char *)Buffer;
  2250. CurrentlyNeededLength = MaxLength;
  2251. while (TRUE)
  2252. {
  2253. // re-initialize the handle to fixed buffer
  2254. RpcStatus = MesBufferHandleReset(PickleHandle,
  2255. MES_FIXED_BUFFER_HANDLE,
  2256. MES_ENCODE,
  2257. &TempBuffer,
  2258. BufferLength,
  2259. &EncodedSize);
  2260. if (RpcStatus != RPC_S_OK)
  2261. {
  2262. goto CleanupAndExit;
  2263. }
  2264. RpcTryExcept
  2265. {
  2266. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2267. }
  2268. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2269. {
  2270. RpcStatus = RpcExceptionCode();
  2271. }
  2272. RpcEndExcept
  2273. if (RpcStatus != RPC_S_OK)
  2274. {
  2275. goto CleanupAndExit;
  2276. }
  2277. if (EncodedSize <= CurrentlyNeededLength)
  2278. {
  2279. *fTrimmedEnough = TRUE;
  2280. *NeededLength = EncodedSize;
  2281. goto SuccessCleanupAndExit;
  2282. }
  2283. Result = KnockOffLastButOneEEInfoRecord(EEInfo);
  2284. if (Result == FALSE)
  2285. {
  2286. *fTrimmedEnough = FALSE;
  2287. goto SuccessCleanupAndExit;
  2288. }
  2289. }
  2290. SuccessCleanupAndExit:
  2291. RpcStatus = RPC_S_OK;
  2292. CleanupAndExit:
  2293. if (Buffer != NULL)
  2294. {
  2295. MIDL_user_free(Buffer);
  2296. }
  2297. if (PickleHandle != NULL)
  2298. {
  2299. MesHandleFree(PickleHandle);
  2300. }
  2301. return RpcStatus;
  2302. }
  2303. RPC_STATUS
  2304. GetLengthOfPickledEEInfo (
  2305. IN ExtendedErrorInfo *EEInfo,
  2306. OUT size_t *NeededLength
  2307. )
  2308. /*++
  2309. Routine Description:
  2310. Calculate the length of the given eeinfo when pickled. It
  2311. does that by pickling it in a temporary buffer and
  2312. checking the resulting length.
  2313. Arguments:
  2314. ErrorInfo - the eeinfo chain whose length we need to calculate
  2315. NeededLength - the length in bytes
  2316. Return Value:
  2317. RPC_S_OK or RPC_S_* error
  2318. --*/
  2319. {
  2320. ULONG EncodedSize;
  2321. handle_t PickleHandle = NULL;
  2322. char *TempBuffer;
  2323. RPC_STATUS RpcStatus;
  2324. ExtendedErrorInfoPtr *EEInfoPtr;
  2325. PVOID Buffer = NULL;
  2326. size_t MarshallSize;
  2327. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  2328. if (RpcStatus != RPC_S_OK)
  2329. {
  2330. return RpcStatus;
  2331. }
  2332. EEInfoPtr = &EEInfo;
  2333. // get the estimated size
  2334. MarshallSize = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  2335. Buffer = MIDL_user_allocate(MarshallSize);
  2336. if (Buffer == NULL)
  2337. {
  2338. RpcStatus = RPC_S_OUT_OF_MEMORY;
  2339. goto CleanupAndExit;
  2340. }
  2341. TempBuffer = (char *)Buffer;
  2342. // re-initialize the handle to fixed buffer
  2343. RpcStatus = MesBufferHandleReset(PickleHandle,
  2344. MES_FIXED_BUFFER_HANDLE,
  2345. MES_ENCODE,
  2346. &TempBuffer,
  2347. MarshallSize,
  2348. &EncodedSize);
  2349. if (RpcStatus != RPC_S_OK)
  2350. {
  2351. goto CleanupAndExit;
  2352. }
  2353. RpcTryExcept
  2354. {
  2355. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2356. }
  2357. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2358. {
  2359. RpcStatus = RpcExceptionCode();
  2360. }
  2361. RpcEndExcept
  2362. if (RpcStatus != RPC_S_OK)
  2363. {
  2364. goto CleanupAndExit;
  2365. }
  2366. *NeededLength = EncodedSize;
  2367. CleanupAndExit:
  2368. if (Buffer != NULL)
  2369. {
  2370. MIDL_user_free(Buffer);
  2371. }
  2372. if (PickleHandle != NULL)
  2373. {
  2374. MesHandleFree(PickleHandle);
  2375. }
  2376. return RpcStatus;
  2377. }
  2378. RPC_STATUS
  2379. TrimEEInfoToLengthByRemovingStrings (
  2380. IN ExtendedErrorInfo *EEInfo,
  2381. IN size_t MaxLength,
  2382. OUT BOOL *fTrimmedEnough,
  2383. OUT size_t *NeededLength
  2384. )
  2385. /*++
  2386. Routine Description:
  2387. Try to trim the eeinfo to the given length by whacking any
  2388. strings in the eeinfo chain. After each string is whacked
  2389. a re-measurement is made
  2390. Arguments:
  2391. ErrorInfo - the eeinfo chain that we need to fit in MaxLength
  2392. bytes.
  2393. MaxLength - the length we need to trim to
  2394. fTrimmedEnough - non-zero if we were able to trim the length below
  2395. MaxLength.
  2396. NeededLength - the length in bytes of the trimmed eeinfo. Not
  2397. touched if fTrimmedEnough is FALSE.
  2398. N.B. This function should only be called after
  2399. TrimEEInfoToLengthByRemovingRecords
  2400. Return Value:
  2401. RPC_S_OK or RPC_S_* error
  2402. --*/
  2403. {
  2404. ExtendedErrorInfo *CurrentRecord;
  2405. size_t CurrentLength;
  2406. int i;
  2407. RPC_STATUS RpcStatus;
  2408. BOOL TrimLongParam;
  2409. void *ParameterToTrim;
  2410. // we shouldn't be here if there are more than two records
  2411. if (EEInfo->Next && EEInfo->Next->Next)
  2412. {
  2413. ASSERT(0);
  2414. }
  2415. CurrentRecord = EEInfo;
  2416. while (CurrentRecord != NULL)
  2417. {
  2418. // trim the parameters and remeasure. If still nothing, move on to
  2419. // the computer name.
  2420. for (i = 0; i < EEInfo->nLen; i ++)
  2421. {
  2422. TrimLongParam = FALSE;
  2423. if ((CurrentRecord->Params[i].Type == eeptiAnsiString)
  2424. || (CurrentRecord->Params[i].Type == eeptiUnicodeString))
  2425. {
  2426. TrimLongParam = TRUE;
  2427. // both string pointers occupy the same memory location,
  2428. // so it is ok to free either
  2429. ParameterToTrim = CurrentRecord->Params[i].AnsiString.pString;
  2430. }
  2431. else if (CurrentRecord->Params[i].Type == eeptiBinary)
  2432. {
  2433. TrimLongParam = TRUE;
  2434. ParameterToTrim = CurrentRecord->Params[i].Blob.pBlob;
  2435. }
  2436. if (TrimLongParam)
  2437. {
  2438. MIDL_user_free(CurrentRecord->Params[i].AnsiString.pString);
  2439. CurrentRecord->Params[i].Type = eeptiNone;
  2440. // remeasure
  2441. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &CurrentLength);
  2442. if (RpcStatus != RPC_S_OK)
  2443. return RpcStatus;
  2444. if (CurrentLength <= MaxLength)
  2445. {
  2446. *NeededLength = CurrentLength;
  2447. *fTrimmedEnough = TRUE;
  2448. return RPC_S_OK;
  2449. }
  2450. }
  2451. }
  2452. // if the computer name is there, try to trim it. If nothing,
  2453. // move on to the next record
  2454. if (CurrentRecord->ComputerName.Type == eecnpPresent)
  2455. {
  2456. // N.B. Not covered by unit tests
  2457. MIDL_user_free(CurrentRecord->ComputerName.Name.pString);
  2458. CurrentRecord->ComputerName.Type = eecnpNotPresent;
  2459. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &CurrentLength);
  2460. if (RpcStatus != RPC_S_OK)
  2461. return RpcStatus;
  2462. if (CurrentLength <= MaxLength)
  2463. {
  2464. // N.B. Not covered by unit tests
  2465. *NeededLength = CurrentLength;
  2466. *fTrimmedEnough = TRUE;
  2467. return RPC_S_OK;
  2468. }
  2469. // N.B. Not covered by unit tests
  2470. }
  2471. CurrentRecord = CurrentRecord->Next;
  2472. }
  2473. // N.B. In the current implementation, the minimum fragment length
  2474. // belongs to LRPC, and is 0xb8. At this length, two records
  2475. // with strings stripped always fit. Therefore, we can never be
  2476. // here. The code below is untested, and is left only for future
  2477. // work where we have a transport supporting fragment length
  2478. // which doesn't hold two records with strings stripped
  2479. ASSERT(0);
  2480. // if we are here, obviously we couldn't trim enough
  2481. *fTrimmedEnough = FALSE;
  2482. return RPC_S_OK;
  2483. }
  2484. void
  2485. TrimEEInfoToLength (
  2486. IN size_t MaxLength,
  2487. OUT size_t *NeededLength
  2488. )
  2489. /*++
  2490. Routine Description:
  2491. Some protocols don't allow transmitting arbitrary lengths
  2492. of information. This function will attempt to trim the pickled
  2493. length of the existing error information so as to fit MaxLength.
  2494. First, it will try to knock off records, starting from the
  2495. last-but-one, and going back. If this is not sufficient, it will
  2496. whack any string arguments/computer names in the record. If this
  2497. is also, not sufficient, it should drop the top record. This should
  2498. leave the total length to be about 128 bytes. All protocols must
  2499. be able to transmit that, as this routine cannot trim it any
  2500. further.
  2501. If MaxLength is larger than the current pickled length, no trimming
  2502. is done, and the actual pickled length will be returned in
  2503. NeededLength
  2504. Arguments:
  2505. MaxLength - the maximum length for this chain.
  2506. NeededLength - on success, how much we actually need to transfer
  2507. the existing extended error info. This must be less than
  2508. MaxLength. If the function cannot get estimation for some
  2509. reason (probably out-of-memory), or there is no extended
  2510. error information, it will return 0 in this parameter.
  2511. Return Value:
  2512. void
  2513. --*/
  2514. {
  2515. RPC_STATUS RpcStatus;
  2516. BOOL fTrimmedEnough;
  2517. ExtendedErrorInfo *EEInfo;
  2518. THREAD *Thread;
  2519. ExtendedErrorInfo *LastRecord;
  2520. ASSERT(MaxLength >= MinimumTransportEEInfoLength);
  2521. *NeededLength = 0;
  2522. Thread = RpcpGetThreadPointer();
  2523. if (Thread == NULL)
  2524. return;
  2525. EEInfo = Thread->GetEEInfo();
  2526. if (EEInfo == NULL)
  2527. return;
  2528. RpcStatus = TrimEEInfoToLengthByRemovingRecords(EEInfo, MaxLength, &fTrimmedEnough, NeededLength);
  2529. if (RpcStatus != RPC_S_OK)
  2530. return;
  2531. // if fTrimmedEnough is set, NeededLength should have been set
  2532. if (fTrimmedEnough == TRUE)
  2533. {
  2534. ASSERT(*NeededLength <= MaxLength);
  2535. return;
  2536. }
  2537. ASSERT(*NeededLength == 0);
  2538. RpcStatus = TrimEEInfoToLengthByRemovingStrings(EEInfo, MaxLength, &fTrimmedEnough, NeededLength);
  2539. if (RpcStatus != RPC_S_OK)
  2540. return;
  2541. // if fTrimmedEnough is set, NeededLength should have been set
  2542. if (fTrimmedEnough == TRUE)
  2543. {
  2544. ASSERT(*NeededLength <= MaxLength);
  2545. return;
  2546. }
  2547. // N.B. In the current implementation, the minimum fragment length
  2548. // belongs to LRPC, and is 0xb8. At this length, two records
  2549. // with strings stripped always fit. Therefore, we can never be
  2550. // here. The code below is untested, and is left only for future
  2551. // work where we have a transport supporting fragment length
  2552. // which doesn't hold two records with strings stripped
  2553. ASSERT(0);
  2554. // again, we couldn't trim it enough
  2555. // drop the first record
  2556. // make sure there are exactly two records
  2557. // this is so, because if we have only one record,
  2558. // it should have fit by now. If we had more than two
  2559. // records, there is a bug in the trimming records code
  2560. ASSERT(EEInfo->Next);
  2561. ASSERT(EEInfo->Next->Next == NULL);
  2562. LastRecord = EEInfo->Next;
  2563. FreeEEInfoRecord(EEInfo);
  2564. EEInfo = LastRecord;
  2565. Thread->SetEEInfo(LastRecord);
  2566. #if DBG
  2567. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, NeededLength);
  2568. if (RpcStatus != RPC_S_OK)
  2569. return;
  2570. ASSERT(*NeededLength <= MaxLength);
  2571. #endif
  2572. }
  2573. size_t
  2574. EstimateSizeOfEEInfo (
  2575. void
  2576. )
  2577. /*++
  2578. Routine Description:
  2579. Takes the EEInfo from the teb (if any) and calculates the size
  2580. of the pickled eeinfo
  2581. Arguments:
  2582. void
  2583. Return Value:
  2584. the size or 0 if it fails
  2585. --*/
  2586. {
  2587. ExtendedErrorInfo *EEInfo;
  2588. THREAD *Thread;
  2589. RPC_STATUS RpcStatus;
  2590. size_t NeededLength;
  2591. Thread = RpcpGetThreadPointer();
  2592. if (Thread == NULL)
  2593. return 0;
  2594. EEInfo = Thread->GetEEInfo();
  2595. if (EEInfo == NULL)
  2596. return 0;
  2597. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &NeededLength);
  2598. if (RpcStatus != RPC_S_OK)
  2599. return 0;
  2600. return NeededLength;
  2601. }
  2602. RPC_STATUS
  2603. PickleEEInfo (
  2604. IN ExtendedErrorInfo *EEInfo,
  2605. IN OUT unsigned char *Buffer,
  2606. IN size_t BufferSize
  2607. )
  2608. /*++
  2609. Routine Description:
  2610. This routine does the actual pickling in a user supplied buffer.
  2611. The buffer must have been allocated large enough to hold all
  2612. pickled data. Some of the other functions should have been
  2613. used to get the size of the pickled data and the buffer
  2614. should have been allocated appropriately
  2615. Arguments:
  2616. Buffer - the actual Buffer to pickle into
  2617. BufferSize - the size of the Buffer.
  2618. Return Value:
  2619. RPC_S_OK if the pickling was successful.
  2620. other RPC_S_* codes if it failed.
  2621. --*/
  2622. {
  2623. ULONG EncodedSize;
  2624. handle_t PickleHandle = NULL;
  2625. RPC_STATUS RpcStatus;
  2626. ExtendedErrorInfoPtr *EEInfoPtr;
  2627. ASSERT(((ULONG_PTR)Buffer & 0x7) == 0);
  2628. RpcStatus = MesEncodeFixedBufferHandleCreate((char *)Buffer, BufferSize, &EncodedSize, &PickleHandle);
  2629. if (RpcStatus != RPC_S_OK)
  2630. {
  2631. return RpcStatus;
  2632. }
  2633. EEInfoPtr = &EEInfo;
  2634. RpcTryExcept
  2635. {
  2636. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2637. }
  2638. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2639. {
  2640. RpcStatus = RpcExceptionCode();
  2641. }
  2642. RpcEndExcept
  2643. ASSERT(EncodedSize <= BufferSize);
  2644. MesHandleFree(PickleHandle);
  2645. return RpcStatus;
  2646. }
  2647. RPC_STATUS
  2648. UnpickleEEInfo (
  2649. IN OUT unsigned char *Buffer,
  2650. IN size_t BufferSize,
  2651. OUT ExtendedErrorInfo **NewEEInfo
  2652. )
  2653. /*++
  2654. Routine Description:
  2655. This routine does the actual pickling in a user supplied buffer.
  2656. The buffer must have been allocated large enough to hold all
  2657. pickled data. Some of the other functions should have been
  2658. used to get the size of the pickled data and the buffer
  2659. should have been allocated appropriately
  2660. Arguments:
  2661. Buffer - the actual Buffer to pickle into
  2662. BufferSize - the size of the Buffer.
  2663. Return Value:
  2664. RPC_S_OK if the pickling was successful.
  2665. other RPC_S_* codes if it failed.
  2666. --*/
  2667. {
  2668. ExtendedErrorInfo *EEInfo;
  2669. handle_t PickleHandle;
  2670. RPC_STATUS RpcStatus;
  2671. ExtendedErrorInfoPtr *EEInfoPtr;
  2672. RpcStatus = MesDecodeBufferHandleCreate((char *)Buffer, BufferSize, &PickleHandle);
  2673. if (RpcStatus != RPC_S_OK)
  2674. {
  2675. return RpcStatus;
  2676. }
  2677. EEInfoPtr = &EEInfo;
  2678. EEInfo = NULL;
  2679. RpcTryExcept
  2680. {
  2681. ExtendedErrorInfoPtr_Decode(PickleHandle, EEInfoPtr);
  2682. }
  2683. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2684. {
  2685. RpcStatus = RpcExceptionCode();
  2686. }
  2687. RpcEndExcept
  2688. MesHandleFree(PickleHandle);
  2689. if (RpcStatus == RPC_S_OK)
  2690. *NewEEInfo = EEInfo;
  2691. return RpcStatus;
  2692. }
  2693. void
  2694. NukeStaleEEInfoIfNecessary (
  2695. IN RPC_STATUS exception
  2696. )
  2697. /*++
  2698. Routine Description:
  2699. Matches the given error code to the error code in the
  2700. first record of the eeinfo chain in the teb. If they match
  2701. or if there is *no* Win32<->NT_STATUS correspondence b/n them
  2702. the eeinfo in the teb is nuked
  2703. Arguments:
  2704. exception - the error code to match against
  2705. Return Value:
  2706. void
  2707. --*/
  2708. {
  2709. THREAD *Thread;
  2710. ExtendedErrorInfo *EEInfo;
  2711. long ExceptionNtStatus;
  2712. long EEInfoNtStatus;
  2713. Thread = RpcpGetThreadPointer();
  2714. if (Thread)
  2715. {
  2716. EEInfo = Thread->GetEEInfo();
  2717. if (EEInfo && Thread->Context)
  2718. {
  2719. // there is extended info - try to match it to what we have
  2720. ExceptionNtStatus = I_RpcMapWin32Status(exception);
  2721. EEInfoNtStatus = I_RpcMapWin32Status(EEInfo->Status);
  2722. if (EEInfoNtStatus != ExceptionNtStatus)
  2723. {
  2724. // they are not the same - nuke the stale info
  2725. // to prevent confusion
  2726. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  2727. }
  2728. }
  2729. }
  2730. }
  2731. LPWSTR
  2732. AllocateAndGetComputerName (
  2733. IN ComputerNameAllocators AllocatorToUse,
  2734. IN COMPUTER_NAME_FORMAT NameToRetrieve,
  2735. IN size_t ExtraBytes,
  2736. IN int StartingOffset,
  2737. OUT DWORD *Size
  2738. )
  2739. /*++
  2740. Routine Description:
  2741. Allocates space for the computer name and gets it
  2742. Arguments:
  2743. Size - on output the size of the string, including
  2744. the terminating NULL
  2745. Return Value:
  2746. The computer name or NULL of out-of-memory
  2747. --*/
  2748. {
  2749. DWORD LocalSize = 0;
  2750. BOOL Result;
  2751. LPWSTR Buffer = NULL;
  2752. DWORD LastError;
  2753. Result = GetComputerNameEx(NameToRetrieve,
  2754. Buffer,
  2755. &LocalSize);
  2756. ASSERT(Result == 0);
  2757. LastError = GetLastError();
  2758. if (LastError == ERROR_MORE_DATA)
  2759. {
  2760. if (AllocatorToUse == cnaMidl)
  2761. {
  2762. Buffer = (LPWSTR)MIDL_user_allocate(LocalSize * sizeof(RPC_CHAR) + ExtraBytes);
  2763. }
  2764. else
  2765. {
  2766. ASSERT(AllocatorToUse == cnaNew);
  2767. Buffer = (RPC_CHAR *)new char[LocalSize * sizeof(RPC_CHAR) + ExtraBytes];
  2768. }
  2769. if (Buffer)
  2770. {
  2771. Result = GetComputerNameEx(NameToRetrieve,
  2772. (RPC_CHAR *)((char *)Buffer + StartingOffset),
  2773. &LocalSize);
  2774. if (Result == 0)
  2775. {
  2776. if (AllocatorToUse == cnaMidl)
  2777. {
  2778. MIDL_user_free(Buffer);
  2779. }
  2780. else
  2781. {
  2782. delete Buffer;
  2783. }
  2784. Buffer = NULL;
  2785. }
  2786. else
  2787. {
  2788. // sometimes GetComputerNameEx returns the size
  2789. // without the terminating NULL regardless of what
  2790. // the MSDN says. The base group (Earhart, NeillC)
  2791. // know about it but won't change it for now.
  2792. // Code it in such a way that it works regardless
  2793. // of when and if they change it.
  2794. *Size = wcslen((RPC_CHAR *)((char *)Buffer + StartingOffset)) + 1;
  2795. }
  2796. }
  2797. }
  2798. return Buffer;
  2799. }
  2800. void
  2801. AddComputerNameToChain (
  2802. ExtendedErrorInfo *EEInfo
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. Checks the first record in eeinfo, and if it doesn't have
  2807. a computer name to it, adds it.
  2808. Arguments:
  2809. EEInfo - the eeinfo chain to add the computer name to
  2810. Return Value:
  2811. void - best effort - no guarantees.
  2812. --*/
  2813. {
  2814. LPWSTR Buffer;
  2815. DWORD Size;
  2816. if (EEInfo->ComputerName.Type == eecnpNotPresent)
  2817. {
  2818. Buffer = AllocateAndGetComputerName(cnaMidl,
  2819. ComputerNamePhysicalDnsHostname,
  2820. 0, // extra bytes
  2821. 0, // starting offset
  2822. &Size);
  2823. if (Buffer)
  2824. {
  2825. EEInfo->ComputerName.Type = eecnpPresent;
  2826. EEInfo->ComputerName.Name.nLength = (CSHORT)Size;
  2827. EEInfo->ComputerName.Name.pString = Buffer;
  2828. }
  2829. }
  2830. }
  2831. void
  2832. StripComputerNameIfRedundant (
  2833. ExtendedErrorInfo *EEInfo
  2834. )
  2835. /*++
  2836. Routine Description:
  2837. Checks the first record in eeinfo, and if it does have
  2838. a computer name to it and it is the same as the computer
  2839. name of this machine, remove it. This is done to keep
  2840. the length of the chain short during local calls using
  2841. remote protocols
  2842. Arguments:
  2843. EEInfo - the eeinfo chain to remove the computer name from
  2844. Return Value:
  2845. void
  2846. --*/
  2847. {
  2848. LPWSTR Buffer = NULL;
  2849. DWORD Size;
  2850. if (EEInfo->ComputerName.Type == eecnpPresent)
  2851. {
  2852. Buffer = AllocateAndGetComputerName(cnaMidl,
  2853. ComputerNamePhysicalDnsHostname,
  2854. 0, // extra bytes
  2855. 0, // starting offset
  2856. &Size);
  2857. if (Buffer)
  2858. {
  2859. if (Size != (DWORD)EEInfo->ComputerName.Name.nLength)
  2860. goto CleanupAndExit;
  2861. // The strings are Unicode - need to multiply by two
  2862. if (RpcpMemoryCompare(Buffer, EEInfo->ComputerName.Name.pString, Size * 2) == 0)
  2863. {
  2864. MIDL_user_free(EEInfo->ComputerName.Name.pString);
  2865. EEInfo->ComputerName.Type = eecnpNotPresent;
  2866. }
  2867. }
  2868. }
  2869. CleanupAndExit:
  2870. if (Buffer)
  2871. {
  2872. MIDL_user_free(Buffer);
  2873. }
  2874. }