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.

539 lines
16 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. }
  111. if (!NT_SUCCESS( Status )) {
  112. BaseSetLastNTError( Status );
  113. Result = 0;
  114. } else {
  115. //
  116. // Ajust return value, since Result contains Unicode char counts,
  117. // we have to adjust it to ANSI char counts
  118. //
  119. Result = AnsiString.Length;
  120. }
  121. } else {
  122. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  123. UnicodeBuffer = NULL;
  124. }
  125. }
  126. if (UnicodeBuffer != NULL) {
  127. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
  128. }
  129. return Result;
  130. }
  131. DWORD
  132. APIENTRY
  133. FormatMessageW(
  134. DWORD dwFlags,
  135. LPCVOID lpSource,
  136. DWORD dwMessageId,
  137. DWORD dwLanguageId,
  138. PWSTR lpBuffer,
  139. DWORD nSize,
  140. va_list *lpArguments
  141. )
  142. {
  143. return BaseDllFormatMessage( FALSE,
  144. dwFlags,
  145. (LPVOID)lpSource,
  146. dwMessageId,
  147. dwLanguageId,
  148. lpBuffer,
  149. nSize,
  150. lpArguments
  151. );
  152. }
  153. BOOLEAN
  154. CreateVirtualBuffer(
  155. OUT PVIRTUAL_BUFFER Buffer,
  156. IN ULONG CommitSize OPTIONAL,
  157. IN ULONG ReserveSize OPTIONAL
  158. )
  159. {
  160. MEMORY_BASIC_INFORMATION MemoryInformation;
  161. SIZE_T MemoryInformationLength;
  162. if (!ARGUMENT_PRESENT( LongToPtr(CommitSize) )) {
  163. CommitSize = 1;
  164. }
  165. if (!ARGUMENT_PRESENT( LongToPtr(ReserveSize) )) {
  166. ReserveSize = ROUND_UP( CommitSize, 0x10000 );
  167. }
  168. Buffer->Base = VirtualAlloc( NULL,
  169. ReserveSize,
  170. MEM_RESERVE,
  171. PAGE_READWRITE
  172. );
  173. if (Buffer->Base == NULL) {
  174. return FALSE;
  175. }
  176. MemoryInformationLength = VirtualQuery( Buffer->Base,
  177. &MemoryInformation,
  178. sizeof( MemoryInformation )
  179. );
  180. if (MemoryInformationLength == sizeof( MemoryInformation )) {
  181. ReserveSize = (ULONG)MemoryInformation.RegionSize;
  182. if (VirtualAlloc( Buffer->Base,
  183. CommitSize,
  184. MEM_COMMIT,
  185. PAGE_READWRITE
  186. ) != NULL
  187. ) {
  188. MemoryInformationLength = VirtualQuery( Buffer->Base,
  189. &MemoryInformation,
  190. sizeof( MemoryInformation )
  191. );
  192. if (MemoryInformationLength == sizeof( MemoryInformation )) {
  193. CommitSize = (ULONG)MemoryInformation.RegionSize;
  194. Buffer->CommitLimit = (PVOID)
  195. ((char *)Buffer->Base + CommitSize);
  196. Buffer->ReserveLimit = (PVOID)
  197. ((char *)Buffer->Base + ReserveSize);
  198. return TRUE;
  199. }
  200. }
  201. }
  202. VirtualFree( Buffer->Base, 0, MEM_RELEASE );
  203. return FALSE;
  204. }
  205. BOOLEAN
  206. ExtendVirtualBuffer(
  207. IN PVIRTUAL_BUFFER Buffer,
  208. IN PVOID Address
  209. )
  210. {
  211. SIZE_T NewCommitSize;
  212. PVOID NewCommitLimit;
  213. if (Address >= Buffer->Base) {
  214. if (Address < Buffer->CommitLimit) {
  215. return TRUE;
  216. }
  217. if (Address >= Buffer->ReserveLimit) {
  218. return FALSE;
  219. }
  220. NewCommitSize =
  221. ((SIZE_T)ROUND_UP_TO_PAGES( (ULONG_PTR)Address + 1 ) - (ULONG_PTR)Buffer->CommitLimit);
  222. NewCommitLimit = VirtualAlloc( Buffer->CommitLimit,
  223. NewCommitSize,
  224. MEM_COMMIT,
  225. PAGE_READWRITE
  226. );
  227. if (NewCommitLimit != NULL) {
  228. Buffer->CommitLimit = (PVOID)
  229. ((ULONG_PTR)NewCommitLimit + NewCommitSize);
  230. return TRUE;
  231. }
  232. }
  233. return FALSE;
  234. }
  235. BOOLEAN
  236. TrimVirtualBuffer(
  237. IN PVIRTUAL_BUFFER Buffer
  238. )
  239. {
  240. Buffer->CommitLimit = Buffer->Base;
  241. return (BOOLEAN)VirtualFree( Buffer->Base, 0, MEM_DECOMMIT );
  242. }
  243. BOOLEAN
  244. FreeVirtualBuffer(
  245. IN PVIRTUAL_BUFFER Buffer
  246. )
  247. {
  248. return (BOOLEAN)VirtualFree( Buffer->Base, 0, MEM_RELEASE );
  249. }
  250. int
  251. VirtualBufferExceptionHandler(
  252. IN DWORD ExceptionCode,
  253. IN PEXCEPTION_POINTERS ExceptionInfo,
  254. IN OUT PVIRTUAL_BUFFER Buffer
  255. )
  256. {
  257. PVOID BadAddress;
  258. //
  259. // If this is an access violation touching memory within
  260. // our reserved buffer, but outside of the committed portion
  261. // of the buffer, then we are going to take this exception.
  262. //
  263. if (ExceptionCode == STATUS_ACCESS_VIOLATION) {
  264. BadAddress = (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
  265. if (BadAddress >= Buffer->CommitLimit &&
  266. BadAddress < Buffer->ReserveLimit
  267. ) {
  268. //
  269. // This is our exception. If there is room to commit
  270. // more memory, try to do so. If no room or unable
  271. // to commit, then execute the exception handler.
  272. // Otherwise we were able to commit the additional
  273. // buffer space, so update the commit limit on the
  274. // caller's stack and retry the faulting instruction.
  275. //
  276. if (ExtendVirtualBuffer( Buffer, BadAddress )) {
  277. return EXCEPTION_CONTINUE_EXECUTION;
  278. } else {
  279. return EXCEPTION_EXECUTE_HANDLER;
  280. }
  281. }
  282. }
  283. //
  284. // Not an exception we care about, so pass it up the chain.
  285. //
  286. return EXCEPTION_CONTINUE_SEARCH;
  287. }
  288. HMODULE BasepNetMsg;
  289. DWORD
  290. APIENTRY
  291. BaseDllFormatMessage(
  292. BOOLEAN ArgumentsAreAnsi,
  293. DWORD dwFlags,
  294. LPVOID lpSource,
  295. DWORD dwMessageId,
  296. DWORD dwLanguageId,
  297. PWSTR lpBuffer,
  298. DWORD nSize,
  299. va_list *arglist
  300. )
  301. {
  302. VIRTUAL_BUFFER Buffer;
  303. NTSTATUS Status;
  304. PVOID DllHandle;
  305. ULONG MaximumWidth;
  306. ULONG LengthNeeded, Result;
  307. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  308. ANSI_STRING AnsiString;
  309. UNICODE_STRING UnicodeString;
  310. PWSTR MessageFormat;
  311. PWSTR lpAllocedBuffer;
  312. PWSTR lpDst;
  313. BOOLEAN IgnoreInserts;
  314. BOOLEAN ArgumentsAreAnArray;
  315. /* If this is a Win32 error wrapped as an OLE HRESULT then unwrap it */
  316. if (((dwMessageId & 0xffff0000) == 0x80070000) &&
  317. (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) &&
  318. !(dwFlags & FORMAT_MESSAGE_FROM_HMODULE) &&
  319. !(dwFlags & FORMAT_MESSAGE_FROM_STRING)) {
  320. dwMessageId &= 0x0000ffff;
  321. }
  322. if (lpBuffer == NULL) {
  323. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  324. return 0;
  325. }
  326. lpAllocedBuffer = NULL;
  327. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  328. *(PVOID *)lpBuffer = NULL;
  329. }
  330. if (!CreateVirtualBuffer( &Buffer, nSize + 1, 0 )) {
  331. return 0;
  332. }
  333. if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
  334. IgnoreInserts = TRUE;
  335. } else {
  336. IgnoreInserts = FALSE;
  337. }
  338. if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
  339. ArgumentsAreAnArray = TRUE;
  340. } else {
  341. ArgumentsAreAnArray = FALSE;
  342. }
  343. Result = 0;
  344. try {
  345. UnicodeString.Buffer = NULL;
  346. MaximumWidth = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
  347. if (MaximumWidth == FORMAT_MESSAGE_MAX_WIDTH_MASK) {
  348. MaximumWidth = 0xFFFFFFFF;
  349. }
  350. UnicodeString.Buffer = NULL;
  351. if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
  352. MessageFormat = lpSource;
  353. } else {
  354. if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
  355. DllHandle = BasepMapModuleHandle( (HMODULE)lpSource, TRUE );
  356. } else
  357. if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
  358. retrySystem:
  359. DllHandle = (PVOID)BaseDllHandle;
  360. } else {
  361. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  362. leave;
  363. }
  364. retrySystem2:
  365. Status = RtlFindMessage( DllHandle,
  366. PtrToUlong(RT_MESSAGETABLE),
  367. (ULONG)dwLanguageId,
  368. dwMessageId,
  369. &MessageEntry
  370. );
  371. if (!NT_SUCCESS( Status )) {
  372. if (Status == STATUS_MESSAGE_NOT_FOUND) {
  373. if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE &&
  374. dwFlags & FORMAT_MESSAGE_FROM_SYSTEM
  375. ) {
  376. dwFlags &= ~FORMAT_MESSAGE_FROM_HMODULE;
  377. goto retrySystem;
  378. }
  379. if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM &&
  380. DllHandle == (PVOID)BaseDllHandle
  381. ) {
  382. //
  383. // The message isn't in kernel32.dll, conditionally
  384. // load netmsg.dll to see if the message is there.
  385. // Leave the dll mapped for subsequent message lookups
  386. //
  387. if (!BasepNetMsg) {
  388. BasepNetMsg = LoadLibraryExW(L"netmsg.dll",NULL,LOAD_LIBRARY_AS_DATAFILE);
  389. }
  390. if (BasepNetMsg) {
  391. DllHandle = BasepNetMsg;
  392. goto retrySystem2;
  393. }
  394. }
  395. SetLastError( ERROR_MR_MID_NOT_FOUND );
  396. } else {
  397. BaseSetLastNTError( Status );
  398. }
  399. leave;
  400. }
  401. if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
  402. RtlInitAnsiString( &AnsiString, MessageEntry->Text );
  403. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
  404. if (!NT_SUCCESS( Status )) {
  405. BaseSetLastNTError( Status );
  406. leave;
  407. }
  408. MessageFormat = UnicodeString.Buffer;
  409. } else {
  410. MessageFormat = (PWSTR)MessageEntry->Text;
  411. }
  412. }
  413. Status = RtlFormatMessage( MessageFormat,
  414. MaximumWidth,
  415. IgnoreInserts,
  416. ArgumentsAreAnsi,
  417. ArgumentsAreAnArray,
  418. arglist,
  419. Buffer.Base,
  420. (ULONG)((PCHAR)Buffer.ReserveLimit - (PCHAR)Buffer.Base),
  421. &LengthNeeded
  422. );
  423. RtlFreeUnicodeString( &UnicodeString );
  424. if (NT_SUCCESS( Status )) {
  425. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
  426. lpAllocedBuffer = (PWSTR)LocalAlloc( LMEM_FIXED, LengthNeeded );
  427. if (lpAllocedBuffer == NULL) {
  428. BaseSetLastNTError( STATUS_NO_MEMORY );
  429. leave;
  430. }
  431. lpDst = lpAllocedBuffer;
  432. } else
  433. if ((LengthNeeded / sizeof( WCHAR )) > nSize) {
  434. BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
  435. leave;
  436. } else {
  437. lpDst = lpBuffer;
  438. }
  439. RtlMoveMemory( lpDst, Buffer.Base, LengthNeeded );
  440. Result = (LengthNeeded - sizeof( WCHAR )) / sizeof( WCHAR );
  441. } else {
  442. BaseSetLastNTError( Status );
  443. }
  444. }
  445. except( VirtualBufferExceptionHandler( GetExceptionCode(),
  446. GetExceptionInformation(),
  447. &Buffer
  448. )
  449. ) {
  450. if (GetExceptionCode() == STATUS_ACCESS_VIOLATION) {
  451. BaseSetLastNTError( STATUS_NO_MEMORY );
  452. } else {
  453. BaseSetLastNTError( GetExceptionCode() );
  454. }
  455. Result = 0;
  456. }
  457. if (lpAllocedBuffer != NULL) {
  458. if (Result) {
  459. *(PVOID *)lpBuffer = lpAllocedBuffer;
  460. } else {
  461. LocalFree( lpAllocedBuffer );
  462. }
  463. }
  464. FreeVirtualBuffer( &Buffer );
  465. return ( Result );
  466. }