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.

890 lines
25 KiB

  1. /******************************************************************************
  2. * HELPERS.C
  3. *
  4. * Various helper functions.
  5. *
  6. * Copyright Citrix Systems Inc. 1994
  7. * Copyright (C) 1997-1999 Microsoft Corp.
  8. *******************************************************************************/
  9. #include <nt.h>
  10. #include <ntrtl.h>
  11. #include <nturtl.h>
  12. #include <windows.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <winstaw.h>
  16. #include <utilsub.h>
  17. #include <tchar.h>
  18. #define PERCENT TEXT('%')
  19. #define NULLC TEXT('\0')
  20. #define MAXCBMSGBUFFER 2048
  21. TCHAR MsgBuf[MAXCBMSGBUFFER];
  22. HANDLE NtDllHandle = NULL;
  23. TCHAR *
  24. mystrchr(TCHAR const *string, int c);
  25. int
  26. PutMsg(unsigned int MsgNum, unsigned int NumOfArgs, va_list *arglist);
  27. /*******************************************************************************
  28. *
  29. * CalculateCrc16
  30. *
  31. * Calculates a 16-bit CRC of the specified buffer.
  32. *
  33. * ENTRY:
  34. * pBuffer (input)
  35. * Points to buffer to calculate CRC for.
  36. * length (input)
  37. * Length in bytes of the buffer.
  38. *
  39. * EXIT:
  40. * (USHORT)
  41. * The 16-bit CRC of the buffer.
  42. *
  43. ******************************************************************************/
  44. /*
  45. * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
  46. * NOTE: First argument must be in range 0 to 255.
  47. * Second argument is referenced twice.
  48. *
  49. * Programmers may incorporate any or all code into their programs,
  50. * giving proper credit within the source. Publication of the
  51. * source routines is permitted so long as proper credit is given
  52. * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
  53. * Omen Technology.
  54. */
  55. #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
  56. /* crctab calculated by Mark G. Mendel, Network Systems Corporation */
  57. unsigned short crctab[256] = {
  58. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  59. 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  60. 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  61. 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  62. 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  63. 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  64. 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  65. 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  66. 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  67. 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  68. 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  69. 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  70. 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  71. 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  72. 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  73. 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  74. 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  75. 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  76. 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  77. 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  78. 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  79. 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  80. 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  81. 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  82. 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  83. 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  84. 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  85. 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  86. 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  87. 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  88. 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  89. 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  90. };
  91. USHORT WINAPI
  92. CalculateCrc16( PBYTE pBuffer,
  93. USHORT length )
  94. {
  95. USHORT Crc = 0;
  96. USHORT Data;
  97. while ( length-- ) {
  98. Data = (USHORT) *pBuffer++;
  99. Crc = updcrc( Data, Crc );
  100. }
  101. return(Crc);
  102. } /* CalculateCrc16() */
  103. /*****************************************************************************
  104. *
  105. * ExecProgram
  106. * Build a command line argument string and execute a program.
  107. *
  108. * ENTRY:
  109. * pProgCall (input)
  110. * ptr to PROGRAMCALL structure with program to execute.
  111. * argc (input)
  112. * count of the command line arguments.
  113. * argv (input)
  114. * vector of strings containing the command line arguments.
  115. *
  116. * EXIT:
  117. * (int)
  118. * 0 for success; 1 for error. An error message will have already
  119. * been output on error.
  120. *
  121. *****************************************************************************/
  122. #define ARGS_LEN 512 // maximum # of characters on command line
  123. // for CreateProcess() call.
  124. INT WINAPI
  125. ExecProgram( PPROGRAMCALL pProgCall,
  126. INT argc,
  127. WCHAR **argv )
  128. {
  129. int count;
  130. WCHAR program[50];
  131. WCHAR args[ARGS_LEN];
  132. PWCHAR pCurrArg;
  133. STARTUPINFO StartInfo;
  134. PROCESS_INFORMATION ProcInfo;
  135. BOOL flag;
  136. DWORD Status;
  137. wcscpy(program, pProgCall->Program);
  138. wcscpy(args, program);
  139. if (pProgCall->Args != NULL) {
  140. wcscat(args, L" ");
  141. wcscat(args, pProgCall->Args);
  142. }
  143. for (count = 0; count < argc; count++) {
  144. pCurrArg = argv[count];
  145. if ( (int)(wcslen(pCurrArg) + wcslen(args) + 3) > ARGS_LEN ) {
  146. fwprintf(stderr, L"Maximum command line length exceeded\n");
  147. return(1);
  148. }
  149. wcscat(args, L" ");
  150. wcscat(args, pCurrArg);
  151. }
  152. /*
  153. * Setup the NT CreateProcess parameters
  154. */
  155. memset( &StartInfo, 0, sizeof(StartInfo) );
  156. StartInfo.cb = sizeof(STARTUPINFO);
  157. StartInfo.lpReserved = NULL;
  158. StartInfo.lpTitle = NULL; // Use the program name
  159. StartInfo.dwFlags = 0; // no extra flags
  160. StartInfo.cbReserved2 = 0;
  161. StartInfo.lpReserved2 = NULL;
  162. /*
  163. * Confusing NT DOC: If program name is set, it does not do a search using
  164. * PATH. If program is NULL, then program is specified from args, and will
  165. * search using the PATH. Some programs may be using the argv[0] trick. If
  166. * they do, then we have to put back in the OS/2 method of defining search
  167. * directories rooted on GetSystemDirectory() since NT can boot from
  168. * multiple locations on a disk.
  169. */
  170. flag = CreateProcess(NULL, // program, // Program name
  171. args, // program name and arguments
  172. NULL, // lpsaProcess
  173. NULL, // lpsaThread
  174. TRUE, // Allow handles to be inherited
  175. 0, // No additional creation flags
  176. NULL, // inherit parent environment block
  177. NULL, // inherit parent directory
  178. &StartInfo,
  179. &ProcInfo);
  180. if ( !flag ) {
  181. Status = GetLastError();
  182. if(Status == ERROR_FILE_NOT_FOUND) {
  183. fwprintf(stderr, L"Terminal Server System Utility %s Not Found\n", program);
  184. return(1);
  185. } else if ( Status == ERROR_INVALID_NAME ) {
  186. fwprintf(stderr, L"Bad Internal Program Name :%s:, args :%s:\n", program, args);
  187. return(1);
  188. }
  189. fwprintf(stderr, L"CreateProcess Failed, Status %u\n", Status);
  190. return(1);
  191. }
  192. /*
  193. * Wait for the process to terminate
  194. */
  195. Status = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
  196. if ( Status == WAIT_FAILED ) {
  197. Status = GetLastError();
  198. fwprintf(stderr, L"WaitForSingle Object Failed, Status %u\n", Status);
  199. return(1);
  200. }
  201. /*
  202. * Close the process and thread handles
  203. */
  204. CloseHandle(ProcInfo.hThread);
  205. CloseHandle(ProcInfo.hProcess);
  206. return(0);
  207. } /* ExecProgram() */
  208. /*****************************************************************************
  209. *
  210. * ProgramUsage
  211. * Output a standard 'usage' message for the given program.
  212. *
  213. * ENTRY:
  214. * pProgramName (input)
  215. * Points to string of program's name.
  216. * pProgramCommands (input)
  217. * Points to an array of PROGRAMCALL structures defining the
  218. * valid commands for the program. The last element in the array
  219. * will contain all 0 or NULL items.
  220. * fError (input)
  221. * If TRUE, will output message with fwprintf to stderr; otherwise,
  222. * will output message to stdout via wprintf.
  223. *
  224. * EXIT:
  225. *
  226. * Only commands not flagged as 'alias' commands will be output in the
  227. * usage message.
  228. *
  229. *****************************************************************************/
  230. VOID WINAPI
  231. ProgramUsage( LPCWSTR pProgramName,
  232. PPROGRAMCALL pProgramCommands,
  233. BOOLEAN fError )
  234. {
  235. WCHAR szUsage[83]; // 80 characters per line + newline chars & null
  236. PPROGRAMCALL pProg;
  237. BOOL bFirst;
  238. int i, namelen = wcslen(pProgramName);
  239. i = wsprintf(szUsage, L"%s {", pProgramName);
  240. for ( pProg = pProgramCommands->pFirst, bFirst = TRUE;
  241. pProg != NULL;
  242. pProg = pProg->pNext ) {
  243. if ( !pProg->fAlias ) {
  244. if ( (i + wcslen(pProg->Command) + (bFirst ? 1 : 3)) >= 80 ) {
  245. wcscat(szUsage, L"\n");
  246. if ( fError )
  247. fwprintf(stderr, szUsage);
  248. else
  249. wprintf(szUsage);
  250. bFirst = TRUE;
  251. for ( i=0; i < namelen; i++)
  252. szUsage[i] = L' ';
  253. }
  254. i += wsprintf( &(szUsage[i]),
  255. bFirst ? L" %s" : L" | %s",
  256. pProg->Command );
  257. bFirst = FALSE;
  258. }
  259. }
  260. wcscat(szUsage, L" }\n");
  261. if ( fError )
  262. fwprintf(stderr, szUsage);
  263. else
  264. wprintf(szUsage);
  265. }
  266. /*******************************************************************************
  267. *
  268. * Message
  269. * Display a message to stdout with variable arguments. Message
  270. * format string comes from the application resources.
  271. *
  272. * ENTRY:
  273. * nResourceID (input)
  274. * Resource ID of the format string to use in the message.
  275. * ... (input)
  276. * Optional additional arguments to be used with format string.
  277. *
  278. * EXIT:
  279. *
  280. ******************************************************************************/
  281. VOID WINAPI
  282. Message( int nResourceID, ...)
  283. {
  284. WCHAR sz1[256], sz2[512];
  285. va_list args;
  286. va_start( args, nResourceID );
  287. if ( LoadString( NULL, nResourceID, sz1, 256 ) ) {
  288. vswprintf( sz2, sz1, args );
  289. wprintf( sz2 );
  290. } else {
  291. fwprintf( stderr, L"{Message(): LoadString failed, Error %ld, (0x%08X)}\n",
  292. GetLastError(), GetLastError() );
  293. }
  294. va_end(args);
  295. } /* Message() */
  296. /*******************************************************************************
  297. *
  298. * ErrorPrintf
  299. * Output an error message to stderr with variable arguments. Message
  300. * format string comes from the application resources.
  301. *
  302. * ENTRY:
  303. * nErrorResourceID (input)
  304. * Resource ID of the format string to use in the error message.
  305. * ... (input)
  306. * Optional additional arguments to be used with format string.
  307. *
  308. * EXIT:
  309. *
  310. ******************************************************************************/
  311. VOID WINAPI
  312. ErrorPrintf( int nErrorResourceID, ...)
  313. {
  314. WCHAR sz1[256], sz2[512];
  315. va_list args;
  316. va_start( args, nErrorResourceID );
  317. if ( LoadString( NULL, nErrorResourceID, sz1, 256 ) ) {
  318. vswprintf( sz2, sz1, args );
  319. fwprintf( stderr, sz2 );
  320. } else {
  321. fwprintf( stderr, L"{ErrorPrintf(): LoadString failed, Error %ld, (0x%08X)}\n",
  322. GetLastError(), GetLastError() );
  323. PutStdErr( GetLastError(), 0 );
  324. }
  325. va_end(args);
  326. } /* ErrorPrintf() */
  327. /*******************************************************************************
  328. *
  329. * TruncateString
  330. *
  331. * This routine truncates given string with elipsis '...' suffix, if needed.
  332. *
  333. *
  334. * ENTRY:
  335. * pString (input/output)
  336. * pointer to string to truncate
  337. * MaxLength (input)
  338. * maximum length of string
  339. *
  340. * EXIT:
  341. * nothing
  342. *
  343. ******************************************************************************/
  344. VOID WINAPI
  345. TruncateString( PWCHAR pString, int MaxLength )
  346. {
  347. /*
  348. * if string is too long, trucate it
  349. */
  350. if ( (int)wcslen(pString) > MaxLength && MaxLength > 2 ) {
  351. wcscpy( pString + MaxLength - 3, L"..." );
  352. }
  353. } /* TruncateString() */
  354. /*******************************************************************************
  355. *
  356. * EnumerateDevices
  357. *
  358. * Perform PD device enumeration for the specified PD DLL.
  359. *
  360. * ENTRY:
  361. * pDllName (input)
  362. * Pointer to DLLNAME string specifying the PD DLL to enumerate.
  363. * pEntries (output)
  364. * Points to variable to return number of devices that were enumerated.
  365. *
  366. * EXIT:
  367. * (PPDPARAMS) Points to a malloc()'ed PDPARAMS array containing the
  368. * enumeration results if sucessful. The caller must perform
  369. * free of this array when done. NULL if error.
  370. *
  371. ******************************************************************************/
  372. /*
  373. * Typedefs for PdEnumerate function (from ...WINDOWS\INC\CITRIX\PDAPI.H)
  374. */
  375. typedef NTSTATUS (APIENTRY * PPDENUMERATE)(PULONG, PPDPARAMS, PULONG);
  376. #define INITIAL_ENUMERATION_COUNT 30
  377. PPDPARAMS WINAPI
  378. EnumerateDevices( PDLLNAME pDllName,
  379. PULONG pEntries )
  380. {
  381. PPDENUMERATE pPdEnumerate;
  382. HANDLE Handle;
  383. ULONG ByteCount;
  384. NTSTATUS Status;
  385. int i;
  386. PPDPARAMSW pPdParams = NULL;
  387. /*
  388. * Load the specified PD DLL.
  389. */
  390. if ( (Handle = LoadLibrary(pDllName)) == NULL ) {
  391. fwprintf(
  392. stderr,
  393. L"Device enumeration failure:\n\tCan't load the %s DLL for device enumeration\n",
  394. pDllName );
  395. goto CantLoad;
  396. }
  397. /*
  398. * Get the PD enumeration function's load entry pointer.
  399. */
  400. if ( (pPdEnumerate =
  401. (PPDENUMERATE)GetProcAddress((HMODULE)Handle, "PdEnumerate"))
  402. == NULL ) {
  403. fwprintf(
  404. stderr,
  405. L"Device enumeration failure:\n\tDLL %s has no enumeration entry point\n",
  406. pDllName );
  407. goto EnumerateMissing;
  408. }
  409. /*
  410. * Call enumerate in loop till we hit enough buffer entries to handle
  411. * a complete enumeration.
  412. */
  413. for ( i = INITIAL_ENUMERATION_COUNT; ; i *= 2 ) {
  414. if ( pPdParams == NULL ) {
  415. pPdParams =
  416. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  417. } else {
  418. free(pPdParams);
  419. pPdParams =
  420. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  421. }
  422. if ( pPdParams == NULL ) {
  423. fwprintf(stderr, L"Error allocating memory\n");
  424. goto OutOfMemory;
  425. }
  426. /*
  427. * Perform enumeration and break loop if successful.
  428. */
  429. if ( (Status = (*pPdEnumerate)(pEntries, pPdParams, &ByteCount))
  430. == STATUS_SUCCESS )
  431. break;
  432. /*
  433. * If we received any other error other than 'buffer too small',
  434. * complain and quit.
  435. */
  436. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  437. fwprintf(
  438. stderr,
  439. L"Device enumeration failure\n\tDLL %s, Error 0x%08lX\n",
  440. pDllName, Status );
  441. goto BadEnumerate;
  442. }
  443. }
  444. /*
  445. * Close the DLL handle and return the PDPARAMS pointer.
  446. */
  447. CloseHandle(Handle);
  448. return(pPdParams);
  449. /*-------------------------------------
  450. * Error cleanup and return
  451. */
  452. BadEnumerate:
  453. free(pPdParams);
  454. OutOfMemory:
  455. EnumerateMissing:
  456. CloseHandle( Handle );
  457. CantLoad:
  458. return(NULL);
  459. } /* EnumerateDevices() */
  460. /******************************************************************************
  461. *
  462. * wfopen
  463. *
  464. * UNICODE version of fopen
  465. *
  466. * ENTRY:
  467. * filename (input)
  468. * UNICODE filename to open.
  469. * mode (input)
  470. * UNICODE file open mode string.
  471. *
  472. * EXIT:
  473. * Pointer to FILE or NULL if open error.
  474. *
  475. *****************************************************************************/
  476. FILE * WINAPI
  477. wfopen( LPCWSTR filename, LPCWSTR mode )
  478. {
  479. PCHAR FileBuf, ModeBuf;
  480. FILE *pFile;
  481. if ( !(FileBuf = (PCHAR)malloc((wcslen(filename)+1) * sizeof(CHAR))) )
  482. goto BadFileBufAlloc;
  483. if ( !(ModeBuf = (PCHAR)malloc((wcslen(mode)+1) * sizeof(CHAR))) )
  484. goto BadModeBufAlloc;
  485. /*
  486. * Convert UNICODE strings to ANSI and call ANSI fopen.
  487. */
  488. wcstombs(FileBuf, filename, wcslen(filename)+1);
  489. wcstombs(ModeBuf, mode, wcslen(mode)+1);
  490. pFile = fopen(FileBuf, ModeBuf);
  491. /*
  492. * Clean up and return
  493. */
  494. free(FileBuf);
  495. free(ModeBuf);
  496. return(pFile);
  497. /*-------------------------------------
  498. * Error cleanup and return
  499. */
  500. BadModeBufAlloc:
  501. free(FileBuf);
  502. BadFileBufAlloc:
  503. return(NULL);
  504. } /* wfopen() */
  505. /******************************************************************************
  506. *
  507. * wfgets
  508. *
  509. * UNICODE version of fgets
  510. *
  511. * ENTRY:
  512. * Buffer (output)
  513. * Buffer to place string retreived from stream
  514. * Len (input)
  515. * Maximum number of WCHARs in buffer.
  516. * Stream (input)
  517. * STDIO file stream for input
  518. *
  519. * EXIT:
  520. * Pointer to Buffer or NULL.
  521. *
  522. *****************************************************************************/
  523. PWCHAR WINAPI
  524. wfgets( PWCHAR Buffer, int Len, FILE *Stream )
  525. {
  526. PCHAR AnsiBuf, pRet;
  527. int count;
  528. if ( !(AnsiBuf = (PCHAR)malloc(Len * sizeof(CHAR))) )
  529. goto BadAnsiBufAlloc;
  530. /*
  531. * Get the ANSI version of the string from the stream
  532. */
  533. if ( !(pRet = fgets(AnsiBuf, Len, Stream)) )
  534. goto NullFgets;
  535. /*
  536. * Convert to UNICODE string in user's buffer.
  537. */
  538. count = mbstowcs(Buffer, AnsiBuf, strlen(AnsiBuf)+1);
  539. /*
  540. * Clean up and return
  541. */
  542. free(AnsiBuf);
  543. return(Buffer);
  544. /*-------------------------------------
  545. * Error cleanup and return
  546. */
  547. NullFgets:
  548. free(AnsiBuf);
  549. BadAnsiBufAlloc:
  550. return(NULL);
  551. } /* wfgets() */
  552. /*** PutStdErr - Print a message to STDERR
  553. *
  554. * Purpose:
  555. * Calls PutMsg sending STDERR as the handle to which the message
  556. * will be written.
  557. *
  558. * int PutStdErr(unsigned MsgNum, unsigned NumOfArgs, ...)
  559. *
  560. * Args:
  561. * MsgNum - the number of the message to print
  562. * NumOfArgs - the number of total arguments
  563. * ... - the additonal arguments for the message
  564. *
  565. * Returns:
  566. * Return value from PutMsg() M026
  567. *
  568. */
  569. int WINAPI
  570. PutStdErr(unsigned int MsgNum, unsigned int NumOfArgs, ...)
  571. {
  572. int Result;
  573. va_list arglist;
  574. va_start(arglist, NumOfArgs);
  575. Result = PutMsg(MsgNum, NumOfArgs, &arglist);
  576. va_end(arglist);
  577. return Result;
  578. }
  579. int
  580. FindMsg(unsigned MsgNum, PTCHAR NullArg, unsigned NumOfArgs, va_list *arglist)
  581. {
  582. unsigned msglen;
  583. DWORD msgsource;
  584. TCHAR *Inserts[ 2 ];
  585. CHAR numbuf[ 32 ];
  586. TCHAR wnumbuf[ 32 ];
  587. //
  588. // find message without doing argument substitution
  589. //
  590. if (MsgNum == ERROR_MR_MID_NOT_FOUND) {
  591. msglen = 0;
  592. }
  593. else {
  594. #ifdef LATER
  595. msgsource = MsgNum >= IDS_ERROR_MALLOC ?
  596. FORMAT_MESSAGE_FROM_HMODULE :
  597. FORMAT_MESSAGE_FROM_SYSTEM;
  598. #endif
  599. msgsource = FORMAT_MESSAGE_FROM_SYSTEM;
  600. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  601. NULL,
  602. MsgNum,
  603. 0,
  604. MsgBuf,
  605. MAXCBMSGBUFFER,
  606. NULL
  607. );
  608. if (msglen == 0) {
  609. if (NtDllHandle == NULL) {
  610. NtDllHandle = GetModuleHandle( TEXT("NTDLL") );
  611. }
  612. msgsource = FORMAT_MESSAGE_FROM_HMODULE;
  613. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  614. (LPVOID)NtDllHandle,
  615. MsgNum,
  616. 0,
  617. MsgBuf,
  618. MAXCBMSGBUFFER,
  619. NULL
  620. );
  621. }
  622. }
  623. if (msglen == 0) {
  624. //
  625. // didn't find message
  626. //
  627. msgsource = FORMAT_MESSAGE_FROM_SYSTEM |
  628. FORMAT_MESSAGE_ARGUMENT_ARRAY;
  629. _ultoa( MsgNum, numbuf, 16 );
  630. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
  631. Inserts[ 0 ]= wnumbuf;
  632. #ifdef LATER
  633. Inserts[ 1 ]= (MsgNum >= IDS_ERROR_MALLOC ? TEXT("Application") : TEXT("System"));
  634. #endif
  635. Inserts[ 1 ]= TEXT("System");
  636. MsgNum = ERROR_MR_MID_NOT_FOUND;
  637. msglen = FormatMessage(msgsource,
  638. NULL,
  639. MsgNum,
  640. 0,
  641. MsgBuf,
  642. MAXCBMSGBUFFER,
  643. (va_list *)Inserts
  644. );
  645. }
  646. else {
  647. // see how many arguments are expected and make sure we have enough
  648. PTCHAR tmp;
  649. ULONG count;
  650. tmp=MsgBuf;
  651. count = 0;
  652. while (tmp = mystrchr(tmp, PERCENT)) {
  653. tmp++;
  654. if (*tmp >= TEXT('1') && *tmp <= TEXT('9')) {
  655. count += 1;
  656. }
  657. else if (*tmp == PERCENT) {
  658. tmp++;
  659. }
  660. }
  661. if (count > NumOfArgs) {
  662. PTCHAR *LocalArgList;
  663. ULONG i;
  664. LocalArgList = (PTCHAR*)malloc(sizeof(PTCHAR) * count);
  665. for (i=0; i<count; i++) {
  666. if (i < NumOfArgs) {
  667. LocalArgList[i] = (PTCHAR)va_arg( *arglist, ULONG );
  668. }
  669. else {
  670. LocalArgList[i] = NullArg;
  671. }
  672. }
  673. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  674. NULL,
  675. MsgNum,
  676. 0,
  677. MsgBuf,
  678. MAXCBMSGBUFFER,
  679. (va_list *)LocalArgList
  680. );
  681. free(LocalArgList);
  682. }
  683. else {
  684. msglen = FormatMessage(msgsource,
  685. NULL,
  686. MsgNum,
  687. 0,
  688. MsgBuf,
  689. MAXCBMSGBUFFER,
  690. arglist
  691. );
  692. }
  693. }
  694. return msglen;
  695. }
  696. /*** PutMsg - Print a message to a handle
  697. *
  698. * Purpose:
  699. * PutMsg is the work routine which interfaces command.com with the
  700. * DOS message retriever. This routine is called by PutStdOut and
  701. * PutStdErr.
  702. *
  703. * int PutMsg(unsigned MsgNum, unsigned Handle, unsigned NumOfArgs, ...)
  704. *
  705. * Args:
  706. * MsgNum - the number of the message to print
  707. * NumOfArgs - the number of total arguments
  708. * Handle - the handle to print to
  709. * Arg1 [Arg2...] - the additonal arguments for the message
  710. *
  711. * Returns:
  712. * Return value from DOSPUTMESSAGE M026
  713. *
  714. * Notes:
  715. * - PutMsg builds an argument table which is passed to DOSGETMESSAGE;
  716. * this table contains the variable information which the DOS routine
  717. * inserts into the message.
  718. * - If more than one Arg is sent into PutMsg, it (or they) are taken
  719. * from the stack in the first for loop.
  720. * - M020 MsgBuf is a static array of 2K length. It is temporary and
  721. * will be replaced by a more efficient method when decided upon.
  722. *
  723. */
  724. int
  725. PutMsg(unsigned int MsgNum, unsigned int NumOfArgs, va_list *arglist)
  726. {
  727. unsigned msglen;
  728. PTCHAR NullArg = TEXT(" ");
  729. msglen = FindMsg(MsgNum,NullArg,NumOfArgs,arglist);
  730. fwprintf( stderr, L"Error [%u]: ", MsgNum );
  731. fwprintf( stderr, MsgBuf );
  732. return NO_ERROR;
  733. }
  734. /***
  735. * mystrchr(string, c) - search a string for a character
  736. *
  737. * mystrchr will search through string and return a pointer to the first
  738. * occurance of the character c. This version of mystrchr knows about
  739. * double byte characters. Note that c must be a single byte character.
  740. *
  741. */
  742. TCHAR *
  743. mystrchr(TCHAR const *string, int c)
  744. {
  745. /* handle null seperatly to make main loop easier to code */
  746. if (string == NULL)
  747. return(NULL);
  748. if (c == NULLC)
  749. return((TCHAR *)(string + wcslen(string)));
  750. return wcschr( string, (TCHAR)c );
  751. }