Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
18 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. winperfp.h
  5. Abstract:
  6. Private header file used by various internal components related to perflib
  7. and associated tools.
  8. NOTE: At least one source file must include this with _INIT_WINPERFP_ defined
  9. and also include <initguid.h> so that storage for global variables and
  10. proper routines are included.
  11. To use debug tracing, just call WinPerfStartTrace(hKey), where hKey can be
  12. an opened key to HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib.
  13. If hKey is NULL, the routine will open it automatically.
  14. --*/
  15. #ifndef _WINPERFP_H_
  16. #define _WINPERFP_H_
  17. #if _MSC_VER > 1000
  18. #pragma once
  19. #endif
  20. #include <pshpack8.h>
  21. #include <setupbat.h>
  22. // Increasing debug trace levels. Higher level always includes tracing lower levels.
  23. #define WINPERF_DBG_TRACE_NONE 0 // no trace
  24. #define WINPERF_DBG_TRACE_FATAL 1 // Print fatal error traces only
  25. #define WINPERF_DBG_TRACE_ERROR 2 // All errors
  26. #define WINPERF_DBG_TRACE_WARNING 3 // Warnings as well
  27. #define WINPERF_DBG_TRACE_INFO 4 // Informational traces as well
  28. #define WINPERF_DBG_TRACE_ALL 255 // All traces
  29. // Data structure definitions.
  30. //
  31. // PERFLIB Tracing routines definition. Starts from 10
  32. //
  33. #define PERF_OPEN_KEY 10 // PerfOpenKey
  34. #define PERF_REG_QUERY_VALUE 11 // PerfRegQueryValue
  35. #define PERF_REG_CLOSE_KEY 12 // PerfRegCloseKey
  36. #define PERF_REG_SET_VALUE 13 // PerfRegSetValue
  37. #define PERG_REG_ENUM_KEY 14 // PerfRegEnumKey
  38. #define PERF_REG_QUERY_INFO_KEY 15 // PerfRegQueryInfoKey
  39. #define PERF_REG_ENUM_VALUE 16 // PerfRegEnumValue
  40. #define PERF_ENUM_TEXT_VALUE 17 // PerfEnumTextValue
  41. #define PERF_ALLOC_INIT_EXT 18 // AllocateAndInitializeExtObject
  42. #define PERF_OPEN_EXT_OBJS 19 // OpenExtensibleObjects
  43. #define PERF_SERVICE_IS_TRUSTED 20 // ServiceIsTrustedByDefault
  44. #define PERF_CLOSE_EXTOBJLIB 21 // CloseExtObjectLibrary
  45. #define PERF_OPEN_EXTOBJLIB 22 // OpenExtObjectLibrary
  46. #define PERF_QUERY_EXTDATA 23 // QueryExtensibleData
  47. #define PERF_GET_NAMES 24 // PerfGetNames
  48. #define PERF_GET_PERFLIBVALUE 25 // GetPerflibKeyValue
  49. #define PERF_TIMER_FUNCTION 26 // PerflibTimerFunction
  50. #define PERF_START_TIMER_FUNCTION 27 // StartPerflibFunctionTimer
  51. #define PERF_DESTROY_TIMER_FUNCTION 28 // DestroyPerflibFunctionTimer
  52. #define PERF_GET_DDLINFO 29 // GetPerfDllFileInfo
  53. #define PERF_DISABLE_PERFLIB 30 // DisablePerfLibrary
  54. #define PERF_DISABLE_LIBRARY 31 // DisableLibrary
  55. #define PERF_UPDATE_ERROR_COUNT 32 // PerfUpdateErrorCount
  56. #define PERF_TIMERFUNCTION 33
  57. #define PERF_STARTFUNCTIONTIMER 34
  58. #define PERF_KILLFUNCTIONTIMER 35
  59. #define PERF_DESTROYFUNCTIONTIMER 36
  60. // LOADPERF trace routine definition, starts from 10
  61. //
  62. #define LOADPERF_DLLENTRYPOINT 10
  63. #define LOADPERF_GETSTRINGRESOURCE 11
  64. #define LOADPERF_GETFORMATRESOURCE 12
  65. #define LOADPERF_DISPLAYCOMMANDHELP 13
  66. #define LOADPERF_TRIMSPACES 14
  67. #define LOADPERF_ISDELIMITER 15
  68. #define LOADPERF_GETITEMFROMSTRING 16
  69. #define LOADPERF_REPORTLOADPERFEVENT 17
  70. #define LOADPERF_LOADPERFGRABMUTEX 18
  71. #define LOADPERF_LOADPERFSTARTEVENTLOG 19
  72. #define LOADPERF_LOADPERFDBGTRACE 20
  73. #define LOADPERF_VERIFYREGISTRY 21
  74. #define LOADPERF_SIGNALWMIWITHNEWDATA 25
  75. #define LOADPERF_LODCTRCOMPILEMOFFILE 26
  76. #define LOADPERF_LODCTRCOMPILEMOFBUFFER 27
  77. #define LOADPERF_DUMPNAMETABLE 30
  78. #define LOADPERF_DUMPPERFSERVICEENTRIES 31
  79. #define LOADPERF_DUMPPERFLIBENTRIES 32
  80. #define LOADPERF_BUILDSERVICELISTS 33
  81. #define LOADPERF_BACKUPPERFREGISTRYTOFILEW 34
  82. #define LOADPERF_RESTOREPERFREGISTRYFROMFILEW 35
  83. #define LOADPERF_REPAIRPERFREGISTRY 36
  84. #define LOADPERF_FORMATPERFNAME 40
  85. #define LOADPERF_GETPERFTYPEINFO 41
  86. #define LOADPERF_GETPERFOBJECTGUID 42
  87. #define LOADPERF_GENERATEMOFHEADER 43
  88. #define LOADPERF_GENERATEMOFOBJECT 44
  89. #define LOADPERF_GENERATEMOFOBJECTTAIL 45
  90. #define LOADPERF_GENERATEMOFCOUNTER 46
  91. #define LOADPERF_GENERATEMOFINSTANCES 47
  92. #define LOADPERF_UNLODCTR_BUILDNAMETABLE 50
  93. #define LOADPERF_GETDRIVERFROMCOMMANDLINE 51
  94. #define LOADPERF_FIXNAMES 52
  95. #define LOADPERF_UNLOADCOUNTERNAMES 53
  96. #define LOADPERF_UNLOADPERFCOUNTERTEXTSTRINGS 54
  97. #define LOADPERF_MAKETEMPFILENAME 60
  98. #define LOADPERF_WRITEWIDESTRINGTOANSIFILE 61
  99. #define LOADPERF_LODCTR_BUILDNAMETABLE 62
  100. #define LOADPERF_MAKEBACKUPCOPYOFLANGUAGEFILES 63
  101. #define LOADPERF_GETFILEFROMCOMMANDLINE 64
  102. #define LOADPERF_LODCTRSERSERVICEASTRUSTED 65
  103. #define LOADPERF_GETDRIVERNAME 66
  104. #define LOADPERF_BUILDLANGUAGETABLES 67
  105. #define LOADPERF_LOADINCLUDEFILE 68
  106. #define LOADPERF_PARSETEXTID 69
  107. #define LOADPERF_FINDLANGUAGE 70
  108. #define LOADPERF_GETVALUE 71
  109. #define LOADPERF_GETVALUEFROMINIKEY 72
  110. #define LOADPERF_ADDENTRYTOLANGUAGE 73
  111. #define LOADPERF_CREATEOBJECTLIST 74
  112. #define LOADPERF_LOADLANGUAGELISTS 75
  113. #define LOADPERF_SORTLANGUAGETABLES 76
  114. #define LOADPERF_GETINSTALLEDLANGUAGELIST 77
  115. #define LOADPERF_CHECKNAMETABLE 78
  116. #define LOADPERF_UPDATEEACHLANGUAGE 79
  117. #define LOADPERF_UPDATEREGISTRY 80
  118. #define LOADPERF_GETMOFFILEFROMINI 81
  119. #define LOADPERF_OPENCOUNTERANDBUILDMOFFILE 82
  120. #define LOADPERF_INSTALLPERFDLL 83
  121. #define LOADPERF_LOADPERFCOUNTERTEXTSTRINGS 84
  122. #define LOADPERF_LOADMOFFROMINSTALLEDSERVICE 85
  123. #define LOADPERF_UPDATEPERFNAMEFILES 86
  124. #define LOADPERF_SETSERVICEASTRUSTED 87
  125. #define LOADPERF_GETINCLUDEFILENAME 90
  126. #define LOADPERF_BACKUPINIFILE 91
  127. #define LOADPERF_CHECKANDCREATEPATH 92
  128. #define LOADPERF_CHECKANDCOPYFILE 93
  129. //
  130. // Convenient macros to determine string sizes
  131. //
  132. // Macro to compute the actual size of a WCHAR or DBCS string
  133. #define WSTRSIZE(str) (ULONG) ( (str) ? ((PCHAR) &str[wcslen(str)] - (PCHAR)str) + sizeof(UNICODE_NULL) : 0 )
  134. #define STRSIZE(str) (ULONG) ( (str) ? ((PCHAR) &str[strlen(str)] - (PCHAR)str) + 1 : 0 )
  135. #define TRACE_WSTR(str) str, WSTRSIZE(str)
  136. #define TRACE_STR(str) str, STRSIZE(str)
  137. #define TRACE_DWORD(dwValue) & dwValue, sizeof(dwValue)
  138. //
  139. // For debug tracing
  140. //
  141. #define TRACE(L, X) if (g_dwTraceLevel >= L) WinPerfDbgTrace X
  142. VOID
  143. WinPerfDbgTrace(
  144. IN LPCGUID Guid,
  145. IN ULONG LineNumber,
  146. IN ULONG ModuleNumber,
  147. IN ULONG OptArgs,
  148. IN ULONG Status,
  149. ...
  150. );
  151. #define ARG_TYPE_ULONG 0
  152. #define ARG_TYPE_WSTR 1
  153. #define ARG_TYPE_STR 2
  154. #define ARG_TYPE_ULONG64 3
  155. // n must be 1 through 8. x is the one of above types
  156. #define ARG_DEF(x, n) (x << ((n-1) * 4))
  157. ULONG
  158. WinPerfStartTrace(
  159. IN HKEY hKey
  160. );
  161. DEFINE_GUID( /* 51af3adb-28b1-4ba5-b59a-3aeec16deb3c */
  162. PerflibGuid,
  163. 0x51af3adb,
  164. 0x28b1,
  165. 0x4ba5,
  166. 0xb5, 0x9a, 0x3a, 0xee, 0xc1, 0x6d, 0xeb, 0x3c
  167. );
  168. DEFINE_GUID( /* 275a79bb-9980-42ba-bafe-a92ded1192cf */
  169. LoadPerfGuid,
  170. 0x275a79bb,
  171. 0x9980,
  172. 0x42ba,
  173. 0xba, 0xfe, 0xa9, 0x2d, 0xed, 0x11, 0x92, 0xcf);
  174. extern const WCHAR cszTraceLevel[];
  175. extern const WCHAR cszTraceLogName[];
  176. extern const WCHAR cszTraceFileValue[];
  177. extern const WCHAR cszDefaultTraceFileName[];
  178. extern TRACEHANDLE g_hTraceHandle;
  179. extern DWORD g_dwTraceLevel;
  180. #ifdef _PERFLIB_H_
  181. #define WinperfQueryValueEx(a,b,c,d,e,f) PrivateRegQueryValueExT(a, (LPVOID)b, c, d, e, f, TRUE)
  182. #else
  183. #define WinperfQueryValueEx RegQueryValueExW
  184. #endif
  185. //
  186. // Below is necessary for global variables and routine to
  187. // be included to each dll or exe
  188. //
  189. #ifdef _INIT_WINPERFP_
  190. const WCHAR cszTraceLevel[] = L"DebugTraceLevel";
  191. const WCHAR cszTraceFileValue[] = L"DebugTraceFile";
  192. const WCHAR cszPerfDebugTraceLevel[] = L"PerfDebugTraceLevel";
  193. const WCHAR cszTraceLogName[] = L"PerfDbg Logger";
  194. const WCHAR cszDefaultTraceFile[] = L"PerfDbg.Etl";
  195. const WCHAR cszDefaultTraceFileName[] = L"C:\\perfdbg.etl";
  196. TRACEHANDLE g_hTraceHandle = 0;
  197. DWORD g_dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  198. LONG g_lDbgStarted = 0;
  199. ULONG
  200. WinPerfStartTrace(
  201. IN HKEY hKey // Key to Perflib or NULL
  202. )
  203. {
  204. CHAR Buffer[1024];
  205. PCHAR ptr;
  206. DWORD status, dwType, dwSize;
  207. PEVENT_TRACE_PROPERTIES Properties;
  208. TRACEHANDLE TraceHandle;
  209. BOOL bLocalKey = FALSE;
  210. BOOL bUseDefault = TRUE;
  211. WCHAR FileName[MAX_PATH + 1];
  212. LPWSTR szTraceFileName = NULL;
  213. ULONG lFileNameSize = 0;
  214. DWORD dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  215. HKEY hKeySetup;
  216. HKEY hLocalKey = hKey;
  217. DWORD dwSetupInProgress = 0;
  218. HRESULT hError = S_OK;
  219. if (InterlockedCompareExchange(& g_lDbgStarted, 1, 0) != 0) {
  220. return g_dwTraceLevel;
  221. }
  222. status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  223. L"SYSTEM\\Setup",
  224. 0L,
  225. KEY_READ,
  226. & hKeySetup);
  227. if (status == ERROR_SUCCESS) {
  228. dwSize = sizeof(DWORD);
  229. dwType = 0;
  230. status = WinperfQueryValueEx(hKeySetup,
  231. L"SystemSetupInProgress",
  232. NULL,
  233. & dwType,
  234. (LPBYTE) & dwSetupInProgress,
  235. & dwSize);
  236. if (status == ERROR_SUCCESS && dwType == REG_DWORD
  237. && dwSetupInProgress != 0) {
  238. // System setup in progress, check whether "PerfDebugTraceLevel"
  239. // is defined in [UserData] section of setup answer file
  240. // $winnt$.inf;
  241. //
  242. WCHAR szAnswerFile[MAX_PATH + 1];
  243. ZeroMemory(szAnswerFile, sizeof(WCHAR) * (MAX_PATH + 1));
  244. GetSystemDirectoryW(szAnswerFile, MAX_PATH);
  245. #ifdef _STRSAFE_H_INCLUDED_
  246. hError = StringCchCatW(szAnswerFile, MAX_PATH, L"\\");
  247. if (SUCCEEDED(hError)) {
  248. hError = StringCchCatW(szAnswerFile, MAX_PATH, WINNT_GUI_FILE_W);
  249. }
  250. #else
  251. lstrcatW(szAnswerFile, L"\\");
  252. lstrcatW(szAnswerFile, WINNT_GUI_FILE_W);
  253. #endif
  254. if (SUCCEEDED(hError)) {
  255. dwTraceLevel = GetPrivateProfileIntW(
  256. WINNT_USERDATA_W, cszPerfDebugTraceLevel, WINPERF_DBG_TRACE_NONE, szAnswerFile);
  257. }
  258. else {
  259. dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  260. }
  261. }
  262. CloseHandle(hKeySetup);
  263. }
  264. status = ERROR_SUCCESS;
  265. if (hLocalKey == NULL) {
  266. status = RegOpenKeyExW(
  267. HKEY_LOCAL_MACHINE,
  268. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
  269. 0L,
  270. KEY_READ,
  271. & hLocalKey);
  272. if (status == ERROR_SUCCESS) {
  273. bLocalKey = TRUE;
  274. }
  275. else {
  276. hLocalKey = NULL;
  277. }
  278. }
  279. if (dwTraceLevel == WINPERF_DBG_TRACE_NONE) {
  280. if (hLocalKey != NULL) {
  281. dwSize = sizeof(DWORD);
  282. dwType = 0;
  283. status = WinperfQueryValueEx(hLocalKey,
  284. cszTraceLevel,
  285. NULL,
  286. & dwType,
  287. (LPBYTE) & dwTraceLevel,
  288. & dwSize);
  289. if ((status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  290. dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  291. if (bLocalKey) {
  292. CloseHandle(hLocalKey);
  293. }
  294. }
  295. }
  296. }
  297. if (dwTraceLevel == WINPERF_DBG_TRACE_NONE)
  298. return WINPERF_DBG_TRACE_NONE;
  299. if (hLocalKey != NULL) {
  300. dwType = 0;
  301. dwSize = (MAX_PATH + 1) * sizeof(WCHAR);
  302. status = WinperfQueryValueEx(hLocalKey,
  303. cszTraceFileValue,
  304. NULL,
  305. & dwType,
  306. (LPBYTE) FileName,
  307. & dwSize);
  308. if ((status == ERROR_SUCCESS) && (dwType == REG_SZ)) {
  309. bUseDefault = FALSE;
  310. }
  311. if (bLocalKey) {
  312. CloseHandle(hLocalKey);
  313. }
  314. }
  315. if (! bUseDefault) {
  316. szTraceFileName = & FileName[0];
  317. lFileNameSize = WSTRSIZE(FileName);
  318. }
  319. else {
  320. if (GetSystemWindowsDirectoryW(FileName, MAX_PATH) > 0) {
  321. #ifdef _STRSAFE_H_INCLUDED_
  322. hError = StringCchCatW(FileName, MAX_PATH + 1, L"\\");
  323. if (SUCCEEDED(hError)) {
  324. hError = StringCchCatW(FileName, MAX_PATH + 1, cszDefaultTraceFile);
  325. }
  326. #else
  327. lstrcatW(FileName, L"\\");
  328. lstrcatW(FileName, cszDefaultTraceFile);
  329. #endif
  330. if (SUCCEEDED(hError)) {
  331. szTraceFileName = & FileName[0];
  332. lFileNameSize = WSTRSIZE(FileName);
  333. }
  334. else {
  335. szTraceFileName = (LPWSTR) &cszDefaultTraceFileName[0];
  336. lFileNameSize = sizeof(cszDefaultTraceFileName);
  337. }
  338. }
  339. else {
  340. szTraceFileName = (LPWSTR) &cszDefaultTraceFileName[0];
  341. lFileNameSize = sizeof(cszDefaultTraceFileName);
  342. }
  343. }
  344. if (sizeof(EVENT_TRACE_PROPERTIES) + sizeof(cszTraceLogName) + lFileNameSize > 1024) {
  345. // static buffer cannot hold information for QueryTrace()/StartTrace() call,
  346. // bail out and don't turn on debug event tracing.
  347. //
  348. g_dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  349. return WINPERF_DBG_TRACE_NONE;
  350. }
  351. g_dwTraceLevel = dwTraceLevel;
  352. RtlZeroMemory(Buffer, 1024);
  353. Properties = (PEVENT_TRACE_PROPERTIES) &Buffer[0];
  354. Properties->Wnode.BufferSize = 1024;
  355. Properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  356. Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  357. Properties->LogFileNameOffset = Properties->LoggerNameOffset +
  358. sizeof(cszTraceLogName);
  359. ptr = (PCHAR) ((PCHAR) &Buffer[0] + Properties->LoggerNameOffset);
  360. RtlCopyMemory(ptr, cszTraceLogName, sizeof(cszTraceLogName));
  361. ptr = (PCHAR) ((PCHAR) &Buffer[0] + Properties->LogFileNameOffset);
  362. RtlCopyMemory(ptr, szTraceFileName, lFileNameSize);
  363. status = QueryTraceW(0, cszTraceLogName, Properties);
  364. if (status == ERROR_SUCCESS) {
  365. g_hTraceHandle = (TRACEHANDLE) Properties->Wnode.HistoricalContext;
  366. return dwTraceLevel;
  367. }
  368. //
  369. // Reinitialize structure again for StartTrace()
  370. //
  371. RtlZeroMemory(Buffer, 1024);
  372. Properties->Wnode.BufferSize = 1024;
  373. Properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  374. Properties->BufferSize = 64;
  375. Properties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL |
  376. EVENT_TRACE_USE_PAGED_MEMORY |
  377. EVENT_TRACE_FILE_MODE_APPEND;
  378. Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  379. Properties->LogFileNameOffset = Properties->LoggerNameOffset +
  380. sizeof(cszTraceLogName);
  381. ptr = (PCHAR) ((PCHAR) &Buffer[0] + Properties->LoggerNameOffset);
  382. RtlCopyMemory(ptr, cszTraceLogName, sizeof(cszTraceLogName));
  383. ptr = (PCHAR) ((PCHAR) &Buffer[0] + Properties->LogFileNameOffset);
  384. RtlCopyMemory(ptr, szTraceFileName, lFileNameSize);
  385. status = StartTraceW(& TraceHandle, cszTraceLogName, Properties);
  386. if (status == ERROR_SUCCESS) {
  387. g_hTraceHandle = TraceHandle;
  388. return dwTraceLevel;
  389. }
  390. g_dwTraceLevel = WINPERF_DBG_TRACE_NONE;
  391. g_hTraceHandle = (TRACEHANDLE) 0;
  392. return WINPERF_DBG_TRACE_NONE;
  393. }
  394. VOID
  395. WinPerfDbgTrace(
  396. IN LPCGUID Guid,
  397. IN ULONG LineNumber,
  398. IN ULONG ModuleNumber,
  399. IN ULONG OptArgs,
  400. IN ULONG Status,
  401. ...
  402. )
  403. {
  404. ULONG ErrorCode;
  405. struct _MY_EVENT {
  406. EVENT_TRACE_HEADER Header;
  407. MOF_FIELD MofField[MAX_MOF_FIELDS];
  408. } MyEvent;
  409. ULONG i;
  410. va_list ArgList;
  411. PVOID source;
  412. SIZE_T len;
  413. DWORD dwLastError;
  414. dwLastError = GetLastError();
  415. RtlZeroMemory(& MyEvent, sizeof(EVENT_TRACE_HEADER));
  416. va_start(ArgList, Status);
  417. for (i = 3; i < MAX_MOF_FIELDS; i ++) {
  418. source = va_arg(ArgList, PVOID);
  419. if (source == NULL)
  420. break;
  421. len = va_arg(ArgList, SIZE_T);
  422. if (len == 0)
  423. break;
  424. MyEvent.MofField[i].DataPtr = (ULONGLONG) source;
  425. MyEvent.MofField[i].Length = (ULONG) len;
  426. }
  427. va_end(ArgList);
  428. MyEvent.Header.Class.Type = (UCHAR) ModuleNumber;
  429. MyEvent.Header.Size = (USHORT) (sizeof(EVENT_TRACE_HEADER) + (i * sizeof(MOF_FIELD)));
  430. MyEvent.Header.Flags = WNODE_FLAG_TRACED_GUID |
  431. WNODE_FLAG_USE_MOF_PTR |
  432. WNODE_FLAG_USE_GUID_PTR;
  433. MyEvent.Header.GuidPtr = (ULONGLONG) Guid;
  434. MyEvent.MofField[0].DataPtr = (ULONGLONG) &LineNumber;
  435. MyEvent.MofField[0].Length = sizeof(LineNumber);
  436. MyEvent.MofField[1].DataPtr = (ULONGLONG) &Status;
  437. MyEvent.MofField[1].Length = sizeof(Status);
  438. MyEvent.MofField[2].DataPtr = (ULONGLONG) &OptArgs;
  439. MyEvent.MofField[2].Length = sizeof(OptArgs);
  440. __try {
  441. ErrorCode = TraceEvent(g_hTraceHandle, (PEVENT_TRACE_HEADER) & MyEvent);
  442. } __except (EXCEPTION_EXECUTE_HANDLER) {
  443. ErrorCode = GetLastError();
  444. }
  445. SetLastError(dwLastError);
  446. }
  447. #endif // _INIT_WINPERFP_
  448. #include <poppack.h>
  449. #endif // _WINPERFP_H_