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.

547 lines
17 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. message.c
  5. Abstract:
  6. This module contains the Win32 Message Management APIs
  7. Author:
  8. Steve Wood (stevewo) 24-Jan-1991
  9. Revision History:
  10. 02-May-94 BruceMa Fix FormatMessage to accept Win32 status
  11. codes wrapped as HRESULTS
  12. --*/
  13. #include "basedll.h"
  14. DWORD
  15. APIENTRY
  16. BaseDllFormatMessage(
  17. BOOLEAN ArgumentsAreAnsi,
  18. DWORD dwFlags,
  19. LPVOID lpSource,
  20. DWORD dwMessageId,
  21. DWORD dwLanguageId,
  22. PWSTR lpBuffer,
  23. DWORD nSize,
  24. va_list *arglist
  25. );
  26. DWORD
  27. APIENTRY
  28. FormatMessageA(
  29. DWORD dwFlags,
  30. LPCVOID lpSource,
  31. DWORD dwMessageId,
  32. DWORD dwLanguageId,
  33. LPSTR lpBuffer,
  34. DWORD nSize,
  35. va_list *lpArguments
  36. )
  37. {
  38. NTSTATUS Status;
  39. DWORD Result;
  40. PWSTR UnicodeSource;
  41. PWSTR UnicodeBuffer;
  42. UNICODE_STRING UnicodeString;
  43. ANSI_STRING AnsiString;
  44. if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
  45. if (strlen (lpSource) >= MAXSHORT) {
  46. Status = STATUS_INVALID_PARAMETER;
  47. } else {
  48. RtlInitAnsiString( &AnsiString, lpSource );
  49. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
  50. }
  51. if (!NT_SUCCESS( Status )) {
  52. BaseSetLastNTError( Status );
  53. return 0;
  54. }
  55. UnicodeSource = UnicodeString.Buffer;
  56. } else {
  57. UnicodeSource = (PWSTR)lpSource;
  58. }
  59. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  60. UnicodeBuffer = (PWSTR)lpBuffer;
  61. } else {
  62. UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(),
  63. MAKE_TAG( TMP_TAG ),
  64. nSize * sizeof( WCHAR )
  65. );
  66. }
  67. if (UnicodeBuffer != NULL) {
  68. Result = BaseDllFormatMessage( TRUE,
  69. dwFlags,
  70. (LPVOID)UnicodeSource,
  71. dwMessageId,
  72. dwLanguageId,
  73. UnicodeBuffer,
  74. nSize,
  75. lpArguments
  76. );
  77. } else {
  78. BaseSetLastNTError( STATUS_NO_MEMORY );
  79. Result = 0;
  80. }
  81. if (UnicodeSource != (PWSTR)lpSource) {
  82. RtlFreeUnicodeString( &UnicodeString );
  83. }
  84. if (Result != 0) {
  85. UnicodeString.Length = (USHORT)(Result * sizeof( WCHAR ));
  86. UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + sizeof( UNICODE_NULL ));
  87. if (Result >= MAXSHORT) {
  88. Status = STATUS_INVALID_PARAMETER;
  89. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  90. UnicodeBuffer = *(PWSTR *)lpBuffer;
  91. *(LPSTR *)lpBuffer = NULL;
  92. }
  93. } else {
  94. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  95. UnicodeString.Buffer = *(PWSTR *)lpBuffer;
  96. UnicodeBuffer = UnicodeString.Buffer;
  97. Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, TRUE );
  98. if (NT_SUCCESS( Status )) {
  99. *(LPSTR *)lpBuffer = AnsiString.Buffer;
  100. } else {
  101. *(LPSTR *)lpBuffer = NULL;
  102. }
  103. } else {
  104. UnicodeString.Buffer = UnicodeBuffer;
  105. AnsiString.Buffer = lpBuffer;
  106. AnsiString.Length = 0;
  107. AnsiString.MaximumLength = (USHORT)nSize;
  108. Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE );
  109. //
  110. // Convert the error to be concistent.
  111. //
  112. if (Status == STATUS_BUFFER_OVERFLOW) {
  113. Status = STATUS_BUFFER_TOO_SMALL;
  114. }
  115. }
  116. }
  117. if (!NT_SUCCESS( Status )) {
  118. BaseSetLastNTError( Status );
  119. Result = 0;
  120. } else {
  121. //
  122. // Ajust return value, since Result contains Unicode char counts,
  123. // we have to adjust it to ANSI char counts
  124. //
  125. Result = AnsiString.Length;
  126. }
  127. } else {
  128. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  129. UnicodeBuffer = NULL;
  130. }
  131. }
  132. if (UnicodeBuffer != NULL) {
  133. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  134. }
  135. return Result;
  136. }
  137. DWORD
  138. APIENTRY
  139. FormatMessageW(
  140. DWORD dwFlags,
  141. LPCVOID lpSource,
  142. DWORD dwMessageId,
  143. DWORD dwLanguageId,
  144. PWSTR lpBuffer,
  145. DWORD nSize,
  146. va_list *lpArguments
  147. )
  148. {
  149. return BaseDllFormatMessage( FALSE,
  150. dwFlags,
  151. (LPVOID)lpSource,
  152. dwMessageId,
  153. dwLanguageId,
  154. lpBuffer,
  155. nSize,
  156. lpArguments
  157. );
  158. }
  159. BOOLEAN
  160. CreateVirtualBuffer(
  161. OUT PVIRTUAL_BUFFER Buffer,
  162. IN ULONG CommitSize OPTIONAL,
  163. IN ULONG ReserveSize OPTIONAL
  164. )
  165. {
  166. MEMORY_BASIC_INFORMATION MemoryInformation;
  167. SIZE_T MemoryInformationLength;
  168. if (!ARGUMENT_PRESENT( LongToPtr(CommitSize) )) {
  169. CommitSize = 1;
  170. }
  171. if (!ARGUMENT_PRESENT( LongToPtr(ReserveSize) )) {
  172. ReserveSize = ROUND_UP( CommitSize, 0x10000 );
  173. }
  174. Buffer->Base = VirtualAlloc( NULL,
  175. ReserveSize + BASE_SYSINFO.PageSize,
  176. MEM_RESERVE,
  177. PAGE_READWRITE
  178. );
  179. if (Buffer->Base == NULL) {
  180. return FALSE;
  181. }
  182. MemoryInformationLength = VirtualQuery( Buffer->Base,
  183. &MemoryInformation,
  184. sizeof( MemoryInformation )
  185. );
  186. if (MemoryInformationLength == sizeof( MemoryInformation )) {
  187. ReserveSize = (ULONG)MemoryInformation.RegionSize - BASE_SYSINFO.PageSize;
  188. if (VirtualAlloc( Buffer->Base,
  189. CommitSize,
  190. MEM_COMMIT,
  191. PAGE_READWRITE
  192. ) != NULL
  193. ) {
  194. MemoryInformationLength = VirtualQuery( Buffer->Base,
  195. &MemoryInformation,
  196. sizeof( MemoryInformation )
  197. );
  198. if (MemoryInformationLength == sizeof( MemoryInformation )) {
  199. CommitSize = (ULONG)MemoryInformation.RegionSize;
  200. Buffer->CommitLimit = (PVOID)
  201. ((char *)Buffer->Base + CommitSize);
  202. Buffer->ReserveLimit = (PVOID)
  203. ((char *)Buffer->Base + ReserveSize);
  204. return TRUE;
  205. }
  206. }
  207. }
  208. VirtualFree( Buffer->Base, 0, MEM_RELEASE );
  209. return FALSE;
  210. }
  211. BOOLEAN
  212. ExtendVirtualBuffer(
  213. IN PVIRTUAL_BUFFER Buffer,
  214. IN PVOID Address
  215. )
  216. {
  217. SIZE_T NewCommitSize;
  218. PVOID NewCommitLimit;
  219. if (Address >= Buffer->Base) {
  220. if (Address < Buffer->CommitLimit) {
  221. return TRUE;
  222. }
  223. if (Address >= Buffer->ReserveLimit) {
  224. return FALSE;
  225. }
  226. NewCommitSize =
  227. ((SIZE_T)ROUND_UP_TO_PAGES( (ULONG_PTR)Address + 1 ) - (ULONG_PTR)Buffer->CommitLimit);
  228. NewCommitLimit = VirtualAlloc( Buffer->CommitLimit,
  229. NewCommitSize,
  230. MEM_COMMIT,
  231. PAGE_READWRITE
  232. );
  233. if (NewCommitLimit != NULL) {
  234. Buffer->CommitLimit = (PVOID)
  235. ((ULONG_PTR)NewCommitLimit + NewCommitSize);
  236. return TRUE;
  237. }
  238. }
  239. return FALSE;
  240. }
  241. BOOLEAN
  242. TrimVirtualBuffer(
  243. IN PVIRTUAL_BUFFER Buffer
  244. )
  245. {
  246. Buffer->CommitLimit = Buffer->Base;
  247. return (BOOLEAN)VirtualFree( Buffer->Base, 0, MEM_DECOMMIT );
  248. }
  249. BOOLEAN
  250. FreeVirtualBuffer(
  251. IN PVIRTUAL_BUFFER Buffer
  252. )
  253. {
  254. return (BOOLEAN)VirtualFree( Buffer->Base, 0, MEM_RELEASE );
  255. }
  256. int
  257. VirtualBufferExceptionHandler(
  258. IN DWORD ExceptionCode,
  259. IN PEXCEPTION_POINTERS ExceptionInfo,
  260. IN OUT PVIRTUAL_BUFFER Buffer
  261. )
  262. {
  263. PVOID BadAddress;
  264. //
  265. // If this is an access violation touching memory within
  266. // our reserved buffer, but outside of the committed portion
  267. // of the buffer, then we are going to take this exception.
  268. //
  269. if (ExceptionCode == STATUS_ACCESS_VIOLATION) {
  270. BadAddress = (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
  271. if (BadAddress >= Buffer->CommitLimit &&
  272. BadAddress < Buffer->ReserveLimit
  273. ) {
  274. //
  275. // This is our exception. If there is room to commit
  276. // more memory, try to do so. If no room or unable
  277. // to commit, then execute the exception handler.
  278. // Otherwise we were able to commit the additional
  279. // buffer space, so update the commit limit on the
  280. // caller's stack and retry the faulting instruction.
  281. //
  282. if (ExtendVirtualBuffer( Buffer, BadAddress )) {
  283. return EXCEPTION_CONTINUE_EXECUTION;
  284. } else {
  285. return EXCEPTION_EXECUTE_HANDLER;
  286. }
  287. }
  288. }
  289. //
  290. // Not an exception we care about, so pass it up the chain.
  291. //
  292. return EXCEPTION_CONTINUE_SEARCH;
  293. }
  294. HMODULE BasepNetMsg;
  295. DWORD
  296. APIENTRY
  297. BaseDllFormatMessage(
  298. BOOLEAN ArgumentsAreAnsi,
  299. DWORD dwFlags,
  300. LPVOID lpSource,
  301. DWORD dwMessageId,
  302. DWORD dwLanguageId,
  303. PWSTR lpBuffer,
  304. DWORD nSize,
  305. va_list *arglist
  306. )
  307. {
  308. VIRTUAL_BUFFER Buffer;
  309. NTSTATUS Status;
  310. PVOID DllHandle;
  311. ULONG MaximumWidth;
  312. ULONG LengthNeeded, Result;
  313. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  314. ANSI_STRING AnsiString;
  315. UNICODE_STRING UnicodeString;
  316. PWSTR MessageFormat;
  317. PWSTR lpAllocedBuffer;
  318. PWSTR lpDst;
  319. BOOLEAN IgnoreInserts;
  320. BOOLEAN ArgumentsAreAnArray;
  321. /* If this is a Win32 error wrapped as an OLE HRESULT then unwrap it */
  322. if (((dwMessageId & 0xffff0000) == 0x80070000) &&
  323. (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) &&
  324. !(dwFlags & FORMAT_MESSAGE_FROM_HMODULE) &&
  325. !(dwFlags & FORMAT_MESSAGE_FROM_STRING)) {
  326. dwMessageId &= 0x0000ffff;
  327. }
  328. if (lpBuffer == NULL) {
  329. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  330. return 0;
  331. }
  332. lpAllocedBuffer = NULL;
  333. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  334. *(PVOID *)lpBuffer = NULL;
  335. }
  336. if (!CreateVirtualBuffer( &Buffer,
  337. (nSize + 1)*sizeof (WCHAR),
  338. 0 )) {
  339. return 0;
  340. }
  341. if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
  342. IgnoreInserts = TRUE;
  343. } else {
  344. IgnoreInserts = FALSE;
  345. }
  346. if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
  347. ArgumentsAreAnArray = TRUE;
  348. } else {
  349. ArgumentsAreAnArray = FALSE;
  350. }
  351. Result = 0;
  352. try {
  353. UnicodeString.Buffer = NULL;
  354. MaximumWidth = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
  355. if (MaximumWidth == FORMAT_MESSAGE_MAX_WIDTH_MASK) {
  356. MaximumWidth = 0xFFFFFFFF;
  357. }
  358. UnicodeString.Buffer = NULL;
  359. if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
  360. MessageFormat = lpSource;
  361. } else {
  362. if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
  363. DllHandle = BasepMapModuleHandle( (HMODULE)lpSource, TRUE );
  364. } else
  365. if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
  366. retrySystem:
  367. DllHandle = (PVOID)BaseDllHandle;
  368. } else {
  369. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  370. leave;
  371. }
  372. retrySystem2:
  373. Status = RtlFindMessage( DllHandle,
  374. PtrToUlong(RT_MESSAGETABLE),
  375. (ULONG)dwLanguageId,
  376. dwMessageId,
  377. &MessageEntry
  378. );
  379. if (!NT_SUCCESS( Status )) {
  380. if (Status == STATUS_MESSAGE_NOT_FOUND) {
  381. if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE &&
  382. dwFlags & FORMAT_MESSAGE_FROM_SYSTEM
  383. ) {
  384. dwFlags &= ~FORMAT_MESSAGE_FROM_HMODULE;
  385. goto retrySystem;
  386. }
  387. if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM &&
  388. DllHandle == (PVOID)BaseDllHandle
  389. ) {
  390. //
  391. // The message isn't in kernel32.dll, conditionally
  392. // load netmsg.dll to see if the message is there.
  393. // Leave the dll mapped for subsequent message lookups
  394. //
  395. if (!BasepNetMsg) {
  396. BasepNetMsg = LoadLibraryExW(L"netmsg.dll",NULL,LOAD_LIBRARY_AS_DATAFILE);
  397. }
  398. if (BasepNetMsg) {
  399. DllHandle = BasepNetMsg;
  400. goto retrySystem2;
  401. }
  402. }
  403. SetLastError( ERROR_MR_MID_NOT_FOUND );
  404. } else {
  405. BaseSetLastNTError( Status );
  406. }
  407. leave;
  408. }
  409. if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
  410. RtlInitAnsiString( &AnsiString, MessageEntry->Text );
  411. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
  412. if (!NT_SUCCESS( Status )) {
  413. BaseSetLastNTError( Status );
  414. leave;
  415. }
  416. MessageFormat = UnicodeString.Buffer;
  417. } else {
  418. MessageFormat = (PWSTR)MessageEntry->Text;
  419. }
  420. }
  421. Status = RtlFormatMessage( MessageFormat,
  422. MaximumWidth,
  423. IgnoreInserts,
  424. ArgumentsAreAnsi,
  425. ArgumentsAreAnArray,
  426. arglist,
  427. Buffer.Base,
  428. (ULONG)((PCHAR)Buffer.ReserveLimit - (PCHAR)Buffer.Base),
  429. &LengthNeeded
  430. );
  431. RtlFreeUnicodeString( &UnicodeString );
  432. if (NT_SUCCESS( Status )) {
  433. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  434. lpAllocedBuffer = (PWSTR)LocalAlloc( LMEM_FIXED, LengthNeeded );
  435. if (lpAllocedBuffer == NULL) {
  436. BaseSetLastNTError( STATUS_NO_MEMORY );
  437. leave;
  438. }
  439. lpDst = lpAllocedBuffer;
  440. } else
  441. if ((LengthNeeded / sizeof( WCHAR )) > nSize) {
  442. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  443. leave;
  444. } else {
  445. lpDst = lpBuffer;
  446. }
  447. RtlMoveMemory( lpDst, Buffer.Base, LengthNeeded );
  448. Result = (LengthNeeded - sizeof( WCHAR )) / sizeof( WCHAR );
  449. } else {
  450. BaseSetLastNTError( Status );
  451. }
  452. }
  453. except( VirtualBufferExceptionHandler( GetExceptionCode(),
  454. GetExceptionInformation(),
  455. &Buffer
  456. )
  457. ) {
  458. if (GetExceptionCode() == STATUS_ACCESS_VIOLATION) {
  459. BaseSetLastNTError( STATUS_NO_MEMORY );
  460. } else {
  461. BaseSetLastNTError( GetExceptionCode() );
  462. }
  463. Result = 0;
  464. }
  465. if (lpAllocedBuffer != NULL) {
  466. if (Result) {
  467. *(PVOID *)lpBuffer = lpAllocedBuffer;
  468. } else {
  469. LocalFree( lpAllocedBuffer );
  470. }
  471. }
  472. FreeVirtualBuffer( &Buffer );
  473. return ( Result );
  474. }