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.

726 lines
23 KiB

  1. //
  2. // Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: server.c
  5. //
  6. // PURPOSE: Implements the body of the Relstat RPC service
  7. //
  8. // FUNCTIONS:
  9. // Called by service.c:
  10. // ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
  11. // ServiceStop( );
  12. //
  13. // Called by RPC:
  14. //
  15. // COMMENTS: The ServerStart and ServerStop functions implemented here are
  16. // prototyped in service.h. The other functions are RPC manager
  17. // functions prototypes in relstat.h
  18. //
  19. //
  20. // AUTHOR: Anitha Panapakkam
  21. //
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #include <windows.h>
  26. #include <assert.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <ctype.h>
  31. #include <io.h>
  32. #include <srvfsctl.h>
  33. #include <tchar.h>
  34. #include <rpc.h>
  35. #include "service.h"
  36. #include "relstat.h"
  37. //
  38. // RPC configuration.
  39. //
  40. // This service listens to all the protseqs listed in this array.
  41. // This should be read from the service's configuration in the
  42. // registery.
  43. TCHAR *ProtocolArray[] = { TEXT("ncalrpc"),
  44. TEXT("ncacn_ip_tcp"),
  45. TEXT("ncacn_np"),
  46. TEXT("ncadg_ip_udp")
  47. };
  48. #define BUFFER_SIZE2 256*1024
  49. // Used in RpcServerUseProtseq, for some protseqs
  50. // this is used as a hint for buffer size.
  51. ULONG ProtocolBuffer = 3;
  52. // Use in RpcServerListen(). More threads will increase performance,
  53. // but use more memory.
  54. ULONG MinimumThreads = 3;
  55. BOOLEAN
  56. CheckFilters (
  57. PSYSTEM_POOLTAG TagInfo,
  58. LPCSTR szTag
  59. );
  60. //
  61. // FUNCTION: ServiceStart
  62. //
  63. // PURPOSE: Actual code of the service
  64. // that does the work.
  65. //
  66. // PARAMETERS:
  67. // dwArgc - number of command line arguments
  68. // lpszArgv - array of command line arguments
  69. //
  70. // RETURN VALUE:
  71. // none
  72. //
  73. // COMMENTS:
  74. // Starts the service listening for RPC requests.
  75. //
  76. VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
  77. {
  78. UINT i;
  79. RPC_BINDING_VECTOR *pbindingVector = 0;
  80. RPC_STATUS status;
  81. BOOL fListening = FALSE;
  82. ///////////////////////////////////////////////////
  83. //
  84. // Service initialization
  85. //
  86. //
  87. // Use protocol sequences (protseqs) specified in ProtocolArray.
  88. //
  89. for(i = 0; i < sizeof(ProtocolArray)/sizeof(TCHAR *); i++)
  90. {
  91. // Report the status to the service control manager.
  92. if (!ReportStatusToSCMgr(
  93. SERVICE_START_PENDING, // service state
  94. NO_ERROR, // exit code
  95. 3000)) // wait hint
  96. return;
  97. status = RpcServerUseProtseq(ProtocolArray[i],
  98. ProtocolBuffer,
  99. 0);
  100. if (status == RPC_S_OK)
  101. {
  102. fListening = TRUE;
  103. }
  104. }
  105. if (!fListening)
  106. {
  107. // Unable to listen to any protocol!
  108. //
  109. AddToMessageLog(TEXT("RpcServerUseProtseq() failed\n"));
  110. return;
  111. }
  112. // Report the status to the service control manager.
  113. //
  114. if (!ReportStatusToSCMgr(
  115. SERVICE_START_PENDING, // service state
  116. NO_ERROR, // exit code
  117. 3000)) // wait hint
  118. return;
  119. // Register the services interface(s).
  120. //
  121. status = RpcServerRegisterIf(RelstatRPCService_ServerIfHandle, // from relstat.h
  122. 0,
  123. 0);
  124. if (status != RPC_S_OK)
  125. return;
  126. // Report the status to the service control manager.
  127. //
  128. if (!ReportStatusToSCMgr(
  129. SERVICE_START_PENDING, // service state
  130. NO_ERROR, // exit code
  131. 3000)) // wait hint
  132. return;
  133. // Register interface(s) and binding(s) (endpoints) with
  134. // the endpoint mapper.
  135. //
  136. status = RpcServerInqBindings(&pbindingVector);
  137. if (status != RPC_S_OK)
  138. {
  139. return;
  140. }
  141. status = RpcEpRegister(RelstatRPCService_ServerIfHandle, // from rpcsvc.h
  142. pbindingVector,
  143. 0,
  144. 0);
  145. if (status != RPC_S_OK)
  146. {
  147. return;
  148. }
  149. // Report the status to the service control manager.
  150. //
  151. if (!ReportStatusToSCMgr(
  152. SERVICE_START_PENDING, // service state
  153. NO_ERROR, // exit code
  154. 3000)) // wait hint
  155. return;
  156. // Enable NT LM Security Support Provider (NtLmSsp service)
  157. //
  158. status = RpcServerRegisterAuthInfo(0,
  159. RPC_C_AUTHN_WINNT,
  160. 0,
  161. 0
  162. );
  163. if (status != RPC_S_OK)
  164. {
  165. return;
  166. }
  167. // Report the status to the service control manager.
  168. //
  169. if (!ReportStatusToSCMgr(
  170. SERVICE_START_PENDING, // service state
  171. NO_ERROR, // exit code
  172. 3000)) // wait hint
  173. return;
  174. // Start accepting client calls.
  175. //
  176. status = RpcServerListen(MinimumThreads,
  177. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // rpcdce.h
  178. TRUE); // don't block.
  179. if (status != RPC_S_OK)
  180. {
  181. return;
  182. }
  183. // Report the status to the service control manager.
  184. //
  185. if (!ReportStatusToSCMgr(
  186. SERVICE_RUNNING, // service state
  187. NO_ERROR, // exit code
  188. 0)) // wait hint
  189. return;
  190. //
  191. // End of initialization
  192. //
  193. ////////////////////////////////////////////////////////////
  194. ////////////////////////////////////////////////////////////
  195. //
  196. // Cleanup
  197. //
  198. // RpcMgmtWaitServerListen() will block until the server has
  199. // stopped listening. If this service had something better to
  200. // do with this thread, it would delay this call until
  201. // ServiceStop() had been called. (Set an event in ServiceStop()).
  202. //
  203. status = RpcMgmtWaitServerListen();
  204. // ASSERT(status == RPC_S_OK)
  205. // Remove entries from the endpoint mapper database.
  206. //
  207. RpcEpUnregister(RelstatRPCService_ServerIfHandle, // from rpcsvc.h
  208. pbindingVector,
  209. 0);
  210. // Delete the binding vector
  211. //
  212. RpcBindingVectorFree(&pbindingVector);
  213. //
  214. ////////////////////////////////////////////////////////////
  215. return;
  216. }
  217. //
  218. // FUNCTION: ServiceStop
  219. //
  220. // PURPOSE: Stops the service
  221. //
  222. // PARAMETERS:
  223. // none
  224. //
  225. // RETURN VALUE:
  226. // none
  227. //
  228. // COMMENTS:
  229. // If a ServiceStop procedure is going to
  230. // take longer than 3 seconds to execute,
  231. // it should spawn a thread to execute the
  232. // stop code, and return. Otherwise, the
  233. // ServiceControlManager will believe that
  234. // the service has stopped responding.
  235. //
  236. VOID ServiceStop()
  237. {
  238. // Stop's the server, wakes the main thread.
  239. RpcMgmtStopServerListening(0);
  240. }
  241. error_status_t
  242. RelStatProcessInfo(
  243. handle_t h,
  244. LONG Pid,
  245. ULONG *pNumberOfProcesses,
  246. PRELSTAT_PROCESS_INFO *ppRelStatProcessInfo)
  247. {
  248. PSYSTEM_PROCESS_INFORMATION pProcessInfo = NULL;
  249. PRELSTAT_PROCESS_INFO pProcessArray = NULL;
  250. ULONG TotalOffset=0;
  251. ULONG NumberOfProcesses = 1; //atleast one process
  252. ULONG NumAlloc = 0;
  253. ULONG i,index,dwMatches = 0;
  254. PBYTE pProcessBuffer = NULL;
  255. NTSTATUS Status= STATUS_INFO_LENGTH_MISMATCH;
  256. DWORD ByteCount = 32768; //TODO : tune it on a "typical system"
  257. DWORD RequiredByteCount = 0;
  258. BOOL fCheck = FALSE;
  259. HANDLE hProcess; // process handle
  260. //two iterations of NtQuerySystemInformation will happen
  261. //can see if there is any other way to allocate a big buffer.
  262. while ( Status == STATUS_INFO_LENGTH_MISMATCH)
  263. {
  264. //
  265. // Allocate a buffer
  266. //
  267. pProcessBuffer = MIDL_user_allocate(ByteCount);
  268. if (pProcessBuffer == NULL)
  269. {
  270. Status = STATUS_NO_MEMORY;
  271. *pNumberOfProcesses = 0;
  272. *ppRelStatProcessInfo = NULL;
  273. break;
  274. }
  275. //
  276. // Perform process enumeration.
  277. //
  278. Status = NtQuerySystemInformation( SystemProcessInformation,
  279. (PVOID)pProcessBuffer,
  280. ByteCount,
  281. &RequiredByteCount );
  282. if (Status == STATUS_INFO_LENGTH_MISMATCH)
  283. {
  284. ByteCount = RequiredByteCount+4096;
  285. if (pProcessBuffer)
  286. LocalFree(pProcessBuffer);
  287. }
  288. }
  289. if (Status == STATUS_SUCCESS)
  290. {
  291. //walk the returned buffer to get the # of processes
  292. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  293. TotalOffset = 0;
  294. //client has specified a Pid
  295. if (Pid >= 0)
  296. fCheck = TRUE;
  297. while(pProcessInfo->NextEntryOffset != 0)
  298. {
  299. if ((fCheck == TRUE) &&
  300. (PtrToLong(pProcessInfo->UniqueProcessId) == Pid))
  301. {
  302. //Pid matched. exit from the while loop
  303. // no need to count the processes anymore
  304. //fExit = TRUE;
  305. dwMatches++;
  306. break;
  307. }
  308. NumberOfProcesses++;
  309. TotalOffset += pProcessInfo->NextEntryOffset;
  310. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  311. &pProcessBuffer[TotalOffset];
  312. }
  313. printf("Num Processes = %ul, Matches %d \n",NumberOfProcesses,
  314. dwMatches);
  315. if (dwMatches > 0)
  316. NumAlloc = dwMatches;
  317. else
  318. NumAlloc = NumberOfProcesses;
  319. pProcessArray = MIDL_user_allocate(NumAlloc *
  320. sizeof (RELSTAT_PROCESS_INFO));
  321. if (pProcessArray == NULL)
  322. {
  323. printf("No memory for pProcessArray\n");
  324. Status = STATUS_NO_MEMORY;
  325. LocalFree(pProcessBuffer);
  326. pProcessBuffer = NULL;
  327. }
  328. else
  329. {
  330. RtlZeroMemory(pProcessArray, NumAlloc *
  331. sizeof(RELSTAT_PROCESS_INFO));
  332. Status = STATUS_SUCCESS;
  333. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  334. TotalOffset = 0;
  335. //walk the returned buffer and copy to pProcessArray
  336. for(i=0;i<NumberOfProcesses;i++)
  337. {
  338. if (dwMatches > 0)
  339. {
  340. if(PtrToLong(pProcessInfo->UniqueProcessId) != Pid)
  341. goto End;
  342. else
  343. index = dwMatches-1;
  344. }
  345. else
  346. index = i;
  347. pProcessArray[index].NumberOfThreads = pProcessInfo->NumberOfThreads;
  348. pProcessArray[index].CreateTime = pProcessInfo->CreateTime;
  349. pProcessArray[index].UserTime = pProcessInfo->UserTime;
  350. pProcessArray[index].KernelTime = pProcessInfo->KernelTime;
  351. //create a null terminated imagename string
  352. pProcessArray[index].szImageName = MIDL_user_allocate((pProcessInfo->ImageName.Length+1)*2);
  353. if (pProcessInfo->ImageName.Length > 0)
  354. {
  355. wcsncpy(pProcessArray[index].szImageName,
  356. pProcessInfo->ImageName.Buffer,
  357. pProcessInfo->ImageName.Length);
  358. }
  359. pProcessArray[index].szImageName[pProcessInfo->ImageName.Length] = L'\0';
  360. pProcessArray[index].BasePriority = pProcessInfo->BasePriority;
  361. pProcessArray[index].UniqueProcessId = PtrToLong(pProcessInfo->UniqueProcessId);
  362. pProcessArray[index].InheritedFromUniqueProcessId = PtrToLong(pProcessInfo->InheritedFromUniqueProcessId);
  363. pProcessArray[index].HandleCount = pProcessInfo->HandleCount;
  364. pProcessArray[index].SessionId = pProcessInfo->SessionId;
  365. pProcessArray[index].PeakVirtualSize = pProcessInfo->PeakVirtualSize;
  366. pProcessArray[index].VirtualSize = pProcessInfo->VirtualSize;
  367. pProcessArray[index].PageFaultCount = pProcessInfo->PageFaultCount;
  368. pProcessArray[index].PeakWorkingSetSize = pProcessInfo->PeakWorkingSetSize;
  369. pProcessArray[index].WorkingSetSize = pProcessInfo->WorkingSetSize;
  370. pProcessArray[index].QuotaPeakPagedPoolUsage = pProcessInfo->QuotaPeakPagedPoolUsage;
  371. pProcessArray[index].QuotaPagedPoolUsage = pProcessInfo->QuotaPagedPoolUsage;
  372. pProcessArray[index].QuotaPeakNonPagedPoolUsage = pProcessInfo->QuotaPeakNonPagedPoolUsage;
  373. pProcessArray[index].QuotaNonPagedPoolUsage = pProcessInfo->QuotaNonPagedPoolUsage;
  374. pProcessArray[index].PagefileUsage = pProcessInfo->PagefileUsage;
  375. pProcessArray[index].PeakPagefileUsage = pProcessInfo->PeakPagefileUsage;
  376. pProcessArray[index].PrivatePageCount = pProcessInfo->PrivatePageCount;
  377. pProcessArray[index].ReadOperationCount = pProcessInfo->ReadOperationCount;
  378. pProcessArray[index].WriteOperationCount = pProcessInfo->WriteOperationCount;
  379. pProcessArray[index].OtherOperationCount = pProcessInfo->OtherOperationCount;
  380. pProcessArray[index].ReadTransferCount = pProcessInfo->ReadTransferCount;
  381. pProcessArray[index].WriteTransferCount = pProcessInfo->WriteTransferCount;
  382. pProcessArray[index].OtherTransferCount = pProcessInfo->OtherTransferCount;
  383. pProcessArray[index].GdiHandleCount = 0;
  384. hProcess= OpenProcess( PROCESS_QUERY_INFORMATION,
  385. FALSE,
  386. PtrToUlong(pProcessInfo->UniqueProcessId) );
  387. if( hProcess ) {
  388. pProcessArray[index].GdiHandleCount = GetGuiResources( hProcess, GR_GDIOBJECTS );
  389. pProcessArray[index].UsrHandleCount= GetGuiResources( hProcess, GR_USEROBJECTS );
  390. CloseHandle( hProcess );
  391. }
  392. End:
  393. TotalOffset += pProcessInfo->NextEntryOffset;
  394. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pProcessBuffer[TotalOffset];
  395. } //end of for loop
  396. } //end of else
  397. } //end of if
  398. if (NT_SUCCESS(Status))
  399. {
  400. *pNumberOfProcesses = NumAlloc;
  401. *ppRelStatProcessInfo = pProcessArray;
  402. //print some debug messages
  403. printf("Query system info passed\n");
  404. printf("%d number of processes \n",*pNumberOfProcesses);
  405. /*
  406. for(i=0; i< *pNumberOfProcesses; i++)
  407. {
  408. printf("%d%10u%10u%10u%10u%10u%10u%10u\n",
  409. pProcessArray[i].UniqueProcessId,
  410. pProcessArray[i].WorkingSetSize,
  411. pProcessArray[i].QuotaPagedPoolUsage,
  412. pProcessArray[i].QuotaNonPagedPoolUsage,
  413. pProcessArray[i].PagefileUsage,
  414. pProcessArray[i].PrivatePageCount,
  415. pProcessArray[i].HandleCount,
  416. pProcessArray[i].NumberOfThreads);
  417. }
  418. */
  419. }
  420. else
  421. {
  422. *pNumberOfProcesses = 0;
  423. *ppRelStatProcessInfo = NULL;
  424. if (pProcessArray)
  425. LocalFree(pProcessArray);
  426. pProcessArray = NULL;
  427. printf("Query system info failed\n");
  428. }
  429. if (pProcessBuffer)
  430. LocalFree(pProcessBuffer);
  431. pProcessBuffer = NULL;
  432. //print a debug message to catch errors in case of marshalling or anything
  433. //else
  434. printf("Fine before return\n");
  435. return (RtlNtStatusToDosError(Status));
  436. }
  437. error_status_t
  438. RelStatPoolTagInfo(
  439. handle_t h,
  440. LPSTR szPoolTag,
  441. ULONG *pNumberOfPoolTags,
  442. PRELSTAT_POOLTAG_INFO *ppRelStatPoolTagInfo)
  443. {
  444. PSYSTEM_POOLTAG_INFORMATION PoolInfo;
  445. #define BUFFER_SIZE 128*1024
  446. UCHAR CurrentBuffer[BUFFER_SIZE];
  447. NTSTATUS Status; // status from NT api
  448. ULONG i;
  449. PRELSTAT_POOLTAG_INFO pPoolTagArray=NULL;
  450. PRELSTAT_POOLTAG_INFO pPoolTagMatchArray=NULL;
  451. BOOLEAN filter = FALSE;
  452. DWORD dwMatchCount = 0;
  453. printf("Filter specified is %S \n", szPoolTag);
  454. Status = NtQuerySystemInformation(
  455. SystemPoolTagInformation,
  456. CurrentBuffer,
  457. BUFFER_SIZE,
  458. NULL
  459. );
  460. PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
  461. printf("Query Info returned %x\n",Status);
  462. if (szPoolTag) //check to see if pooltag filter specified
  463. filter = TRUE;
  464. if(NT_SUCCESS(Status) && (PoolInfo->Count > 0))
  465. {
  466. printf("%u Number of Tags \n",PoolInfo->Count);
  467. pPoolTagArray = MIDL_user_allocate(PoolInfo->Count *
  468. sizeof(SYSTEM_POOLTAG));
  469. if (!pPoolTagArray)
  470. {
  471. Status = STATUS_NO_MEMORY;
  472. printf("System out of memory for pooltaginfo\n");
  473. }
  474. else
  475. {
  476. for(i=0 ; i < PoolInfo->Count ; i++)
  477. {
  478. if (filter && !CheckFilters(&PoolInfo->TagInfo[i],szPoolTag))
  479. continue;
  480. memcpy(pPoolTagArray[dwMatchCount].Tag, PoolInfo->TagInfo[i].Tag, 4);
  481. pPoolTagArray[dwMatchCount].PagedAllocs = PoolInfo->TagInfo[i].PagedAllocs;
  482. pPoolTagArray[dwMatchCount].PagedFrees = PoolInfo->TagInfo[i].PagedFrees;
  483. pPoolTagArray[dwMatchCount].PagedUsed = PoolInfo->TagInfo[i].PagedUsed;
  484. pPoolTagArray[dwMatchCount].NonPagedAllocs =PoolInfo->TagInfo[i].NonPagedAllocs;
  485. pPoolTagArray[dwMatchCount].NonPagedFrees = PoolInfo->TagInfo[i].NonPagedFrees;
  486. pPoolTagArray[dwMatchCount].NonPagedUsed = PoolInfo->TagInfo[i].NonPagedUsed;
  487. dwMatchCount++;
  488. //need to include union info
  489. }
  490. }
  491. }
  492. if (NT_SUCCESS(Status))
  493. {
  494. if ((filter) && (dwMatchCount < PoolInfo->Count))
  495. {
  496. //allocate and copy only the matched pooltags
  497. pPoolTagMatchArray = MIDL_user_allocate(dwMatchCount *
  498. sizeof(SYSTEM_POOLTAG));
  499. if (!pPoolTagMatchArray)
  500. {
  501. Status = STATUS_NO_MEMORY;
  502. printf("System out of memory for pooltaginfo matches\n");
  503. }
  504. for(i=0;i<dwMatchCount;i++)
  505. {
  506. memcpy(pPoolTagMatchArray[i].Tag, pPoolTagArray[i].Tag,4);
  507. pPoolTagMatchArray[i].PagedAllocs = pPoolTagArray[i].PagedAllocs;
  508. pPoolTagMatchArray[i].PagedFrees = pPoolTagArray[i].PagedFrees;
  509. pPoolTagMatchArray[i].PagedUsed = pPoolTagArray[i].PagedUsed;
  510. pPoolTagMatchArray[i].NonPagedAllocs = pPoolTagArray[i].NonPagedAllocs;
  511. pPoolTagMatchArray[i].NonPagedFrees = pPoolTagArray[i].NonPagedFrees;
  512. pPoolTagMatchArray[i].NonPagedUsed = pPoolTagArray[i].NonPagedUsed;
  513. }
  514. *ppRelStatPoolTagInfo = pPoolTagMatchArray;
  515. *pNumberOfPoolTags = dwMatchCount;
  516. printf("RelStatPoolTagInfo returned TRUE \n");
  517. printf("%u Number of Tags \n",*pNumberOfPoolTags);
  518. MIDL_user_free(pPoolTagArray);
  519. }
  520. else
  521. { // no filter specified or all the tags need to be sent
  522. *ppRelStatPoolTagInfo = pPoolTagArray;
  523. *pNumberOfPoolTags = PoolInfo->Count;
  524. printf("RelStatPoolTagInfo returned TRUE \n");
  525. printf("%u Number of Tags \n",*pNumberOfPoolTags);
  526. }
  527. }
  528. else
  529. {
  530. *ppRelStatPoolTagInfo = NULL;
  531. *pNumberOfPoolTags = 0;
  532. printf("RelStatPoolTagInfo returned FALSE %x \n",Status);
  533. }
  534. return (RtlNtStatusToDosError(Status));
  535. // return ( (NT_SUCCESS(*pResult))?TRUE : FALSE);
  536. }
  537. error_status_t
  538. RelStatBuildNumber(handle_t h,
  539. ULONG* ulBuildNumber)
  540. {
  541. OSVERSIONINFO osVer;
  542. osVer.dwOSVersionInfoSize = sizeof(osVer);
  543. if (GetVersionEx(&osVer))
  544. {
  545. *ulBuildNumber = osVer.dwBuildNumber;
  546. return ERROR_SUCCESS;
  547. }
  548. return RtlNtStatusToDosError(GetLastError());
  549. }
  550. error_status_t
  551. RelStatTickCount(handle_t h,
  552. ULONG* ulTickCount)
  553. {
  554. *ulTickCount = GetTickCount();
  555. return ERROR_SUCCESS;
  556. }
  557. BOOLEAN
  558. CheckSingleFilter (
  559. PCHAR Tag,
  560. LPCSTR Filter
  561. )
  562. {
  563. ULONG i;
  564. CHAR tc;
  565. CHAR fc;
  566. for ( i = 0; i < 4; i++ ) {
  567. tc = *Tag++;
  568. fc = *Filter++;
  569. if ( fc == '*' ) return TRUE;
  570. if ( fc == '?' ) continue;
  571. if ( tc != fc ) return FALSE;
  572. }
  573. return TRUE;
  574. }
  575. BOOLEAN
  576. CheckFilters (
  577. PSYSTEM_POOLTAG TagInfo,
  578. LPCSTR szTag
  579. )
  580. {
  581. BOOLEAN pass = FALSE;
  582. ULONG i;
  583. PCHAR tag;
  584. tag = TagInfo->Tag;
  585. if ( CheckSingleFilter( tag, szTag ))
  586. pass = TRUE;
  587. return pass;
  588. }
  589. //
  590. // FUNCTIONS: MIDL_user_allocate and MIDL_user_free
  591. //
  592. // PURPOSE: Used by stubs to allocate and free memory
  593. // in standard RPC calls. Not used when
  594. // [enable_allocate] is specified in the .acf.
  595. //
  596. //
  597. // PARAMETERS:
  598. // See documentations.
  599. //
  600. // RETURN VALUE:
  601. // Exceptions on error. This is not required,
  602. // you can use -error allocation on the midl.exe
  603. // command line instead.
  604. //
  605. //
  606. void * __RPC_USER MIDL_user_allocate(size_t size)
  607. {
  608. return(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size));
  609. }
  610. void __RPC_USER MIDL_user_free( void *pointer)
  611. {
  612. HeapFree(GetProcessHeap(), 0, pointer);
  613. }