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.

1323 lines
36 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. /******************************************************************************
  3. *
  4. * HELPERS.C
  5. *
  6. * Various helper functions.
  7. *
  8. *
  9. *******************************************************************************/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. //#include <ntddvdeo.h>
  14. #include <ntddkbd.h>
  15. #include <ntddmou.h>
  16. #include <windows.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <winstaw.h>
  20. #include <utilsub.h>
  21. #include <tchar.h>
  22. #include "utilsubres.h" // resources refrenced in this file.
  23. #define PERCENT TEXT('%')
  24. #define NULLC TEXT('\0')
  25. #define MAXCBMSGBUFFER 2048
  26. TCHAR MsgBuf[MAXCBMSGBUFFER];
  27. HANDLE NtDllHandle = NULL;
  28. TCHAR *
  29. mystrchr(TCHAR const *string, int c);
  30. /* makarp, #259849
  31. we cannot put an rc file in this file.
  32. so we need to keep all the string resources referenced in this file in
  33. utildll.dll.
  34. */
  35. /* this function returns the string resource from utildll.dll */
  36. BOOL GetResourceStringFromUtilDll(UINT uID, LPTSTR szBuffer, int iBufferSize)
  37. {
  38. HINSTANCE hUtilDll = LoadLibrary(TEXT("utildll.dll"));
  39. if (hUtilDll)
  40. {
  41. int iReturn = LoadString(hUtilDll, uID, szBuffer, iBufferSize);
  42. int iLastError = GetLastError();
  43. FreeLibrary( hUtilDll );
  44. if ( iReturn != 0 && iReturn < iBufferSize)
  45. {
  46. // we have got the string
  47. return TRUE;
  48. }
  49. else if (iReturn == 0)
  50. {
  51. _ftprintf( stderr, _T("GetResourceStringFromUtilDll: LoadString failed, Error %ld\n"), iLastError);
  52. return FALSE;
  53. }
  54. else
  55. {
  56. // we have provided insufficient buffer.
  57. _ftprintf(stderr, _T("GetResourceStringFromUtilDll: Insufficient buffer for resource string"));
  58. return FALSE;
  59. }
  60. }
  61. else
  62. {
  63. _ftprintf(stderr, _T("GetResourceStringFromUtilDll: LoadLibrary failed for utildll.dll, %ld"), GetLastError());
  64. return FALSE;
  65. }
  66. }
  67. /* this function is used internally.
  68. it prints an error message on stderr
  69. its like ErrorPrintf except it looks for
  70. the resource into utildll.dll
  71. This function accepts the arguments in WCHAR.
  72. */
  73. void ErrorOutFromResource(UINT uiStringResource, ...)
  74. {
  75. WCHAR szBufferString[512];
  76. WCHAR szBufferMessage[1024];
  77. va_list args;
  78. va_start( args, uiStringResource);
  79. if (GetResourceStringFromUtilDll(uiStringResource, szBufferString, 512))
  80. {
  81. vswprintf( szBufferMessage, szBufferString, args );
  82. My_fwprintf( stderr, szBufferMessage);
  83. }
  84. else
  85. {
  86. fwprintf( stderr, L"ErrorOutFromResource:GetResourceStringFromUtilDll failed, Error %ld\n", GetLastError());
  87. PutStdErr( GetLastError(), 0 );
  88. }
  89. va_end(args);
  90. }
  91. int
  92. PutMsg(unsigned int MsgNum, unsigned int NumOfArgs, va_list *arglist);
  93. /*******************************************************************************
  94. *
  95. * CalculateCrc16
  96. *
  97. * Calculates a 16-bit CRC of the specified buffer.
  98. *
  99. * ENTRY:
  100. * pBuffer (input)
  101. * Points to buffer to calculate CRC for.
  102. * length (input)
  103. * Length in bytes of the buffer.
  104. *
  105. * EXIT:
  106. * (USHORT)
  107. * The 16-bit CRC of the buffer.
  108. *
  109. ******************************************************************************/
  110. /*
  111. * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
  112. * NOTE: First argument must be in range 0 to 255.
  113. * Second argument is referenced twice.
  114. *
  115. * Programmers may incorporate any or all code into their programs,
  116. * giving proper credit within the source. Publication of the
  117. * source routines is permitted so long as proper credit is given
  118. * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
  119. * Omen Technology.
  120. */
  121. #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
  122. /* crctab calculated by Mark G. Mendel, Network Systems Corporation */
  123. unsigned short crctab[256] = {
  124. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  125. 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  126. 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  127. 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  128. 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  129. 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  130. 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  131. 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  132. 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  133. 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  134. 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  135. 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  136. 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  137. 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  138. 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  139. 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  140. 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  141. 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  142. 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  143. 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  144. 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  145. 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  146. 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  147. 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  148. 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  149. 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  150. 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  151. 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  152. 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  153. 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  154. 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  155. 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  156. };
  157. USHORT WINAPI
  158. CalculateCrc16( PBYTE pBuffer,
  159. USHORT length )
  160. {
  161. USHORT Crc = 0;
  162. USHORT Data;
  163. while ( length-- ) {
  164. Data = (USHORT) *pBuffer++;
  165. Crc = updcrc( Data, Crc );
  166. }
  167. return(Crc);
  168. } /* CalculateCrc16() */
  169. /*****************************************************************************
  170. *
  171. * ExecProgram
  172. * Build a command line argument string and execute a program.
  173. *
  174. * ENTRY:
  175. * pProgCall (input)
  176. * ptr to PROGRAMCALL structure with program to execute.
  177. * argc (input)
  178. * count of the command line arguments.
  179. * argv (input)
  180. * vector of strings containing the command line arguments.
  181. *
  182. * EXIT:
  183. * (int)
  184. * 0 for success; 1 for error. An error message will have already
  185. * been output on error.
  186. *
  187. *****************************************************************************/
  188. #define ARGS_LEN 512 // maximum # of characters on command line
  189. // for CreateProcess() call.
  190. INT WINAPI
  191. ExecProgram( PPROGRAMCALL pProgCall,
  192. INT argc,
  193. WCHAR **argv )
  194. {
  195. int count;
  196. WCHAR program[50];
  197. PWCHAR pCurrArg;
  198. STARTUPINFO StartInfo;
  199. PROCESS_INFORMATION ProcInfo;
  200. BOOL flag;
  201. DWORD Status;
  202. WCHAR wszFullPath[MAX_PATH]; //contains the full path name of the program
  203. WCHAR wszCmdLine[MAX_PATH + ARGS_LEN + 5]; //for the quoted string and NULL
  204. PWSTR pwstrFilePart;
  205. wcscpy(program, pProgCall->Program);
  206. //
  207. //Fix 330770 TS: Suspicious CreateProcess call using no program name might execute c:\program.exe AdamO 02/28/2001
  208. //get the full path of the program
  209. //search in the same way as createprocess would
  210. //
  211. if (!SearchPath(NULL, program, NULL, MAX_PATH, wszFullPath, &pwstrFilePart)) {
  212. ErrorOutFromResource(IDS_TS_SYS_UTIL_NOT_FOUND, program);
  213. // fwprintf(stderr, L"Terminal Server System Utility %s Not Found\n", program);
  214. return(1);
  215. }
  216. //
  217. //create the command line args
  218. //
  219. wcscpy(wszCmdLine, L"\"");
  220. wcscat(wszCmdLine, wszFullPath);
  221. wcscat(wszCmdLine, L"\"");
  222. if (pProgCall->Args != NULL) {
  223. wcscat(wszCmdLine, L" ");
  224. if ( (wcslen(pProgCall->Args) + wcslen(wszCmdLine) + 3) > sizeof(wszCmdLine)) {
  225. // IDS_MAX_CMDLINE_EXCEEDED
  226. ErrorOutFromResource(IDS_MAX_CMDLINE_EXCEEDED);
  227. // fwprintf(stderr, L"Maximum command line length exceeded\n");
  228. return(1);
  229. }
  230. wcscat(wszCmdLine, pProgCall->Args);
  231. }
  232. for (count = 0; count < argc; count++) {
  233. pCurrArg = argv[count];
  234. if ( (int)(wcslen(pCurrArg) + wcslen(wszCmdLine) + 3) > sizeof(wszCmdLine) ) {
  235. // IDS_MAX_CMDLINE_EXCEEDED
  236. ErrorOutFromResource(IDS_MAX_CMDLINE_EXCEEDED);
  237. // fwprintf(stderr, L"Maximum command line length exceeded\n");
  238. return(1);
  239. }
  240. wcscat(wszCmdLine, L" ");
  241. wcscat(wszCmdLine, pCurrArg);
  242. }
  243. /*
  244. * Setup the NT CreateProcess parameters
  245. */
  246. memset( &StartInfo, 0, sizeof(StartInfo) );
  247. StartInfo.cb = sizeof(STARTUPINFO);
  248. StartInfo.lpReserved = NULL;
  249. StartInfo.lpTitle = NULL; // Use the program name
  250. StartInfo.dwFlags = 0; // no extra flags
  251. StartInfo.cbReserved2 = 0;
  252. StartInfo.lpReserved2 = NULL;
  253. flag = CreateProcess(wszFullPath, // full path of the program
  254. wszCmdLine, // arguments
  255. NULL, // lpsaProcess
  256. NULL, // lpsaThread
  257. TRUE, // Allow handles to be inherited
  258. 0, // No additional creation flags
  259. NULL, // inherit parent environment block
  260. NULL, // inherit parent directory
  261. &StartInfo,
  262. &ProcInfo);
  263. if ( !flag ) {
  264. Status = GetLastError();
  265. if(Status == ERROR_FILE_NOT_FOUND) {
  266. ErrorOutFromResource(IDS_TS_SYS_UTIL_NOT_FOUND, program);
  267. // fwprintf(stderr, L"Terminal Server System Utility %s Not Found\n", program);
  268. return(1);
  269. } else if ( Status == ERROR_INVALID_NAME ) {
  270. ErrorOutFromResource(IDS_BAD_INTERNAL_PROGNAME, program, wszCmdLine);
  271. // fwprintf(stderr, L"Bad Internal Program Name :%s:, args :%s:\n", program, wszCmdLine);
  272. return(1);
  273. }
  274. ErrorOutFromResource(IDS_CREATEPROCESS_FAILED, Status);
  275. // fwprintf(stderr, L"CreateProcess Failed, Status %u\n", Status);
  276. return(1);
  277. }
  278. /*
  279. * Wait for the process to terminate
  280. */
  281. Status = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
  282. if ( Status == WAIT_FAILED ) {
  283. Status = GetLastError();
  284. ErrorOutFromResource(IDS_WAITFORSINGLEOBJECT_FAILED, Status);
  285. // fwprintf(stderr, L"WaitForSingle Object Failed, Status %u\n", Status);
  286. return(1);
  287. }
  288. /*
  289. * Close the process and thread handles
  290. */
  291. CloseHandle(ProcInfo.hThread);
  292. CloseHandle(ProcInfo.hProcess);
  293. return(0);
  294. } /* ExecProgram() */
  295. /*****************************************************************************
  296. *
  297. * ProgramUsage
  298. * Output a standard 'usage' message for the given program.
  299. *
  300. * ENTRY:
  301. * pProgramName (input)
  302. * Points to string of program's name.
  303. * pProgramCommands (input)
  304. * Points to an array of PROGRAMCALL structures defining the
  305. * valid commands for the program. The last element in the array
  306. * will contain all 0 or NULL items.
  307. * fError (input)
  308. * If TRUE, will output message with fwprintf to stderr; otherwise,
  309. * will output message to stdout via wprintf.
  310. *
  311. * EXIT:
  312. *
  313. * Only commands not flagged as 'alias' commands will be output in the
  314. * usage message.
  315. *
  316. *****************************************************************************/
  317. VOID WINAPI
  318. ProgramUsage( LPCWSTR pProgramName,
  319. PPROGRAMCALL pProgramCommands,
  320. BOOLEAN fError )
  321. {
  322. WCHAR szUsage[83]; // 80 characters per line + newline chars & null
  323. PPROGRAMCALL pProg;
  324. BOOL bFirst;
  325. int i, namelen = wcslen(pProgramName);
  326. i = wsprintf(szUsage, L"%s {", pProgramName);
  327. for ( pProg = pProgramCommands->pFirst, bFirst = TRUE;
  328. pProg != NULL;
  329. pProg = pProg->pNext ) {
  330. if ( !pProg->fAlias ) {
  331. if ( (i + wcslen(pProg->Command) + (bFirst ? 1 : 3)) >= 80 ) {
  332. wcscat(szUsage, L"\n");
  333. if ( fError )
  334. My_fwprintf(stderr, szUsage);
  335. else
  336. My_wprintf(szUsage);
  337. bFirst = TRUE;
  338. for ( i=0; i < namelen; i++)
  339. szUsage[i] = L' ';
  340. }
  341. i += wsprintf( &(szUsage[i]),
  342. bFirst ? L" %s" : L" | %s",
  343. pProg->Command );
  344. bFirst = FALSE;
  345. }
  346. }
  347. wcscat(szUsage, L" }\n");
  348. if ( fError )
  349. My_fwprintf(stderr, szUsage);
  350. else
  351. My_wprintf(szUsage);
  352. }
  353. /*******************************************************************************
  354. * ScanPrintfString
  355. * Scans a string, detects any % and double it
  356. * (Use it for any string argument before calling ErrorPrintf)
  357. *
  358. *******************************************************************************/
  359. #define PERCENTCHAR L'%'
  360. BOOLEAN ScanPrintfString(PWCHAR pSource, PWCHAR *ppDest)
  361. {
  362. ULONG i, j = 0, k = 0, n = 0;
  363. ULONG SourceLength, DestLength;
  364. PWCHAR pDest = NULL;
  365. if ( (pSource == 0) || (ppDest == 0))
  366. {
  367. SetLastError(ERROR_INVALID_PARAMETER);
  368. return (FALSE);
  369. }
  370. SourceLength = wcslen(pSource);
  371. for (i = 0; i < SourceLength; i++)
  372. {
  373. if (pSource[i] == PERCENTCHAR)
  374. {
  375. n++;
  376. }
  377. }
  378. if (n != 0) // at least one %, we need to build a new string.
  379. {
  380. pDest = (PWCHAR)malloc((SourceLength + n + 1) * sizeof(WCHAR));
  381. *ppDest = pDest;
  382. if (pDest == NULL)
  383. {
  384. return FALSE;
  385. }
  386. else
  387. {
  388. //
  389. // rescan and copy
  390. //
  391. for (i = 0; i < SourceLength; i++)
  392. {
  393. if (pSource[i] == PERCENTCHAR)
  394. {
  395. if ( i > j )
  396. {
  397. memcpy(&(pDest[k]), &(pSource[j]), (i - j) * sizeof(WCHAR));
  398. k += (i-j);
  399. j = i;
  400. }
  401. pDest[k] = PERCENTCHAR;
  402. pDest[k+1] = PERCENTCHAR;
  403. k += 2;
  404. j++;
  405. }
  406. }
  407. if (i > j)
  408. {
  409. memcpy(&(pDest[k]), &(pSource[j]), (i - j) * sizeof(WCHAR));
  410. }
  411. pDest[SourceLength + n] = L'\0';
  412. }
  413. }
  414. else // OK pSource is fine; no need of a new string.
  415. {
  416. *ppDest = NULL;
  417. }
  418. return (TRUE);
  419. }
  420. /*******************************************************************************
  421. *
  422. * Message
  423. * Display a message to stdout with variable arguments. Message
  424. * format string comes from the application resources.
  425. *
  426. * ENTRY:
  427. * nResourceID (input)
  428. * Resource ID of the format string to use in the message.
  429. * ... (input)
  430. * Optional additional arguments to be used with format string.
  431. *
  432. * EXIT:
  433. *
  434. ******************************************************************************/
  435. VOID WINAPI
  436. Message( int nResourceID, ...)
  437. {
  438. WCHAR sz1[256], sz2[512];
  439. va_list args;
  440. va_start( args, nResourceID );
  441. if ( LoadString( NULL, nResourceID, sz1, 256 ) ) {
  442. vswprintf( sz2, sz1, args );
  443. My_wprintf( sz2 );
  444. } else {
  445. fwprintf( stderr, L"{Message(): LoadString failed, Error %ld, (0x%08X)}\n",
  446. GetLastError(), GetLastError() );
  447. }
  448. va_end(args);
  449. } /* Message() */
  450. /************************************************************************************
  451. * StringMessage
  452. * used as a pre-routine for Message in case the argument is a single string
  453. * (fix for bug #334374)
  454. *
  455. ************************************************************************************/
  456. VOID WINAPI
  457. StringMessage(int nErrorResourceID, PWCHAR pString)
  458. {
  459. PWCHAR pFixedString = NULL;
  460. if (ScanPrintfString(pString, &pFixedString) )
  461. {
  462. if (pFixedString != NULL)
  463. {
  464. Message(nErrorResourceID, pFixedString);
  465. free(pFixedString);
  466. }
  467. else
  468. {
  469. Message(nErrorResourceID, pString);
  470. }
  471. }
  472. else
  473. {
  474. Message(nErrorResourceID, L" ");
  475. }
  476. }
  477. /************************************************************************************
  478. * StringErrorPrintf
  479. * used as a pre-routine for ErrorPrintf in case the argument is a single string
  480. * (fix for bug #334374)
  481. *
  482. ************************************************************************************/
  483. VOID WINAPI
  484. StringErrorPrintf(int nErrorResourceID, PWCHAR pString)
  485. {
  486. PWCHAR pFixedString = NULL;
  487. if (ScanPrintfString(pString, &pFixedString) )
  488. {
  489. if (pFixedString != NULL)
  490. {
  491. ErrorPrintf(nErrorResourceID, pFixedString);
  492. free(pFixedString);
  493. }
  494. else
  495. {
  496. ErrorPrintf(nErrorResourceID, pString);
  497. }
  498. }
  499. else
  500. {
  501. ErrorPrintf(nErrorResourceID, L" ");
  502. }
  503. }
  504. /************************************************************************************
  505. * StringDwordMessage
  506. * used as a pre-routine for Message in case the argument are:
  507. * a single string + a ulong
  508. * (fix for bug #334374)
  509. *
  510. ************************************************************************************/
  511. VOID WINAPI
  512. StringDwordMessage(int nErrorResourceID, PWCHAR pString, DWORD Num)
  513. {
  514. PWCHAR pFixedString = NULL;
  515. if (ScanPrintfString(pString, &pFixedString) )
  516. {
  517. if (pFixedString != NULL)
  518. {
  519. Message(nErrorResourceID, pFixedString, Num);
  520. free(pFixedString);
  521. }
  522. else
  523. {
  524. Message(nErrorResourceID, pString, Num);
  525. }
  526. }
  527. else
  528. {
  529. Message(nErrorResourceID, L" ", Num);
  530. }
  531. }
  532. /************************************************************************************
  533. * DwordStringMessage
  534. * used as a pre-routine for Message in case the argument are:
  535. * a single string + a ulong
  536. * (fix for bug #334374)
  537. *
  538. ************************************************************************************/
  539. VOID WINAPI
  540. DwordStringMessage(int nErrorResourceID, DWORD Num, PWCHAR pString)
  541. {
  542. PWCHAR pFixedString = NULL;
  543. if (ScanPrintfString(pString, &pFixedString) )
  544. {
  545. if (pFixedString != NULL)
  546. {
  547. Message(nErrorResourceID, Num, pFixedString);
  548. free(pFixedString);
  549. }
  550. else
  551. {
  552. Message(nErrorResourceID, Num, pString);
  553. }
  554. }
  555. else
  556. {
  557. Message(nErrorResourceID, Num, L" ");
  558. }
  559. }
  560. /************************************************************************************
  561. * StringDwordErrorPrintf
  562. * used as a pre-routine for ErrorPrintf in case the argument are:
  563. * a single string + a ulong
  564. * (fix for bug #334374)
  565. *
  566. ************************************************************************************/
  567. VOID WINAPI
  568. StringDwordErrorPrintf(int nErrorResourceID, PWCHAR pString, DWORD Num)
  569. {
  570. PWCHAR pFixedString = NULL;
  571. if (ScanPrintfString(pString, &pFixedString) )
  572. {
  573. if (pFixedString != NULL)
  574. {
  575. ErrorPrintf(nErrorResourceID, pFixedString, Num);
  576. free(pFixedString);
  577. }
  578. else
  579. {
  580. ErrorPrintf(nErrorResourceID, pString, Num);
  581. }
  582. }
  583. else
  584. {
  585. ErrorPrintf(nErrorResourceID, L" ", Num);
  586. }
  587. }
  588. /*******************************************************************************
  589. *
  590. * ErrorPrintf
  591. * Output an error message to stderr with variable arguments. Message
  592. * format string comes from the application resources.
  593. *
  594. * ENTRY:
  595. * nErrorResourceID (input)
  596. * Resource ID of the format string to use in the error message.
  597. * ... (input)
  598. * Optional additional arguments to be used with format string.
  599. *
  600. * EXIT:
  601. *
  602. ******************************************************************************/
  603. VOID WINAPI
  604. ErrorPrintf( int nErrorResourceID, ...)
  605. {
  606. WCHAR sz1[256], sz2[512];
  607. va_list args;
  608. va_start( args, nErrorResourceID );
  609. if ( LoadString( NULL, nErrorResourceID, sz1, 256 ) ) {
  610. vswprintf( sz2, sz1, args );
  611. My_fwprintf( stderr, sz2 );
  612. } else {
  613. fwprintf( stderr, L"{ErrorPrintf(): LoadString failed, Error %ld, (0x%08X)}\n",
  614. GetLastError(), GetLastError() );
  615. PutStdErr( GetLastError(), 0 );
  616. }
  617. va_end(args);
  618. } /* ErrorPrintf() */
  619. /*******************************************************************************
  620. *
  621. * TruncateString
  622. *
  623. * This routine truncates given string with elipsis '...' suffix, if needed.
  624. *
  625. *
  626. * ENTRY:
  627. * pString (input/output)
  628. * pointer to string to truncate
  629. * MaxLength (input)
  630. * maximum length of string
  631. *
  632. * EXIT:
  633. * nothing
  634. *
  635. ******************************************************************************/
  636. VOID WINAPI
  637. TruncateString( PWCHAR pString, int MaxLength )
  638. {
  639. /*
  640. * if string is too long, trucate it
  641. */
  642. if ( (int)wcslen(pString) > MaxLength && MaxLength > 2 ) {
  643. wcscpy( pString + MaxLength - 3, L"..." );
  644. }
  645. } /* TruncateString() */
  646. /*******************************************************************************
  647. *
  648. * EnumerateDevices
  649. *
  650. * Perform PD device enumeration for the specified PD DLL.
  651. *
  652. * ENTRY:
  653. * pDllName (input)
  654. * Pointer to DLLNAME string specifying the PD DLL to enumerate.
  655. * pEntries (output)
  656. * Points to variable to return number of devices that were enumerated.
  657. *
  658. * EXIT:
  659. * (PPDPARAMS) Points to a malloc()'ed PDPARAMS array containing the
  660. * enumeration results if sucessful. The caller must perform
  661. * free of this array when done. NULL if error.
  662. *
  663. ******************************************************************************/
  664. /*
  665. * Typedefs for PdEnumerate function (from ...WINDOWS\INC\CITRIX\PDAPI.H)
  666. */
  667. typedef NTSTATUS (APIENTRY * PPDENUMERATE)(PULONG, PPDPARAMS, PULONG);
  668. #define INITIAL_ENUMERATION_COUNT 30
  669. PPDPARAMS WINAPI
  670. EnumerateDevices( PDLLNAME pDllName,
  671. PULONG pEntries )
  672. {
  673. PPDENUMERATE pPdEnumerate;
  674. HANDLE Handle;
  675. ULONG ByteCount;
  676. NTSTATUS Status;
  677. int i;
  678. PPDPARAMSW pPdParams = NULL;
  679. /*
  680. * Load the specified PD DLL.
  681. */
  682. if ( (Handle = LoadLibrary(pDllName)) == NULL ) {
  683. ErrorOutFromResource(IDS_DEVICE_ENUM_CANT_LOAD, pDllName);
  684. // fwprintf(
  685. // stderr,
  686. // L"Device enumeration failure:\n\tCan't load the %s DLL for device enumeration\n",
  687. // pDllName );
  688. goto CantLoad;
  689. }
  690. /*
  691. * Get the PD enumeration function's load entry pointer.
  692. */
  693. if ( (pPdEnumerate =
  694. (PPDENUMERATE)GetProcAddress((HMODULE)Handle, "PdEnumerate"))
  695. == NULL ) {
  696. ErrorOutFromResource(IDS_DEVENUM_NO_ENTRY_POINT, pDllName);
  697. // fwprintf(
  698. // stderr,
  699. // L"Device enumeration failure:\n\tDLL %s has no enumeration entry point\n",
  700. // pDllName );
  701. goto EnumerateMissing;
  702. }
  703. /*
  704. * Call enumerate in loop till we hit enough buffer entries to handle
  705. * a complete enumeration.
  706. */
  707. for ( i = INITIAL_ENUMERATION_COUNT; ; i *= 2 ) {
  708. if ( pPdParams == NULL ) {
  709. pPdParams =
  710. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  711. } else {
  712. free(pPdParams);
  713. pPdParams =
  714. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  715. }
  716. if ( pPdParams == NULL ) {
  717. ErrorOutFromResource(IDS_ERROR_MEMORY);
  718. // fwprintf(stderr, L"Error allocating memory\n");
  719. goto OutOfMemory;
  720. }
  721. /*
  722. * Perform enumeration and break loop if successful.
  723. */
  724. if ( (Status = (*pPdEnumerate)(pEntries, pPdParams, &ByteCount))
  725. == STATUS_SUCCESS )
  726. break;
  727. /*
  728. * If we received any other error other than 'buffer too small',
  729. * complain and quit.
  730. */
  731. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  732. ErrorOutFromResource(IDS_DEVICE_ENUM_FAILED, pDllName, Status);
  733. // fwprintf(
  734. // stderr,
  735. // L"Device enumeration failure\n\tDLL %s, Error 0x%08lX\n",
  736. // pDllName, Status );
  737. goto BadEnumerate;
  738. }
  739. }
  740. /*
  741. * Close the DLL handle and return the PDPARAMS pointer.
  742. */
  743. CloseHandle(Handle);
  744. return(pPdParams);
  745. /*-------------------------------------
  746. * Error cleanup and return
  747. */
  748. BadEnumerate:
  749. free(pPdParams);
  750. OutOfMemory:
  751. EnumerateMissing:
  752. CloseHandle( Handle );
  753. CantLoad:
  754. return(NULL);
  755. } /* EnumerateDevices() */
  756. /******************************************************************************
  757. *
  758. * wfopen
  759. *
  760. * UNICODE version of fopen
  761. *
  762. * ENTRY:
  763. * filename (input)
  764. * UNICODE filename to open.
  765. * mode (input)
  766. * UNICODE file open mode string.
  767. *
  768. * EXIT:
  769. * Pointer to FILE or NULL if open error.
  770. *
  771. *****************************************************************************/
  772. FILE * WINAPI
  773. wfopen( LPCWSTR filename, LPCWSTR mode )
  774. {
  775. PCHAR FileBuf, ModeBuf;
  776. FILE *pFile;
  777. if ( !(FileBuf = (PCHAR)malloc((wcslen(filename)+1) * sizeof(CHAR))) )
  778. goto BadFileBufAlloc;
  779. if ( !(ModeBuf = (PCHAR)malloc((wcslen(mode)+1) * sizeof(CHAR))) )
  780. goto BadModeBufAlloc;
  781. /*
  782. * Convert UNICODE strings to ANSI and call ANSI fopen.
  783. */
  784. wcstombs(FileBuf, filename, wcslen(filename)+1);
  785. wcstombs(ModeBuf, mode, wcslen(mode)+1);
  786. pFile = fopen(FileBuf, ModeBuf);
  787. /*
  788. * Clean up and return
  789. */
  790. free(FileBuf);
  791. free(ModeBuf);
  792. return(pFile);
  793. /*-------------------------------------
  794. * Error cleanup and return
  795. */
  796. BadModeBufAlloc:
  797. free(FileBuf);
  798. BadFileBufAlloc:
  799. return(NULL);
  800. } /* wfopen() */
  801. /******************************************************************************
  802. *
  803. * wfgets
  804. *
  805. * UNICODE version of fgets
  806. *
  807. * ENTRY:
  808. * Buffer (output)
  809. * Buffer to place string retreived from stream
  810. * Len (input)
  811. * Maximum number of WCHARs in buffer.
  812. * Stream (input)
  813. * STDIO file stream for input
  814. *
  815. * EXIT:
  816. * Pointer to Buffer or NULL.
  817. *
  818. *****************************************************************************/
  819. PWCHAR WINAPI
  820. wfgets( PWCHAR Buffer, int Len, FILE *Stream )
  821. {
  822. PCHAR AnsiBuf, pRet;
  823. int count;
  824. if ( !(AnsiBuf = (PCHAR)malloc(Len * sizeof(CHAR))) )
  825. goto BadAnsiBufAlloc;
  826. /*
  827. * Get the ANSI version of the string from the stream
  828. */
  829. if ( !(pRet = fgets(AnsiBuf, Len, Stream)) )
  830. goto NullFgets;
  831. /*
  832. * Convert to UNICODE string in user's buffer.
  833. */
  834. count = mbstowcs(Buffer, AnsiBuf, strlen(AnsiBuf)+1);
  835. /*
  836. * Clean up and return
  837. */
  838. free(AnsiBuf);
  839. return(Buffer);
  840. /*-------------------------------------
  841. * Error cleanup and return
  842. */
  843. NullFgets:
  844. free(AnsiBuf);
  845. BadAnsiBufAlloc:
  846. return(NULL);
  847. } /* wfgets() */
  848. /*** PutStdErr - Print a message to STDERR
  849. *
  850. * Purpose:
  851. * Calls PutMsg sending STDERR as the handle to which the message
  852. * will be written.
  853. *
  854. * int PutStdErr(unsigned MsgNum, unsigned NumOfArgs, ...)
  855. *
  856. * Args:
  857. * MsgNum - the number of the message to print
  858. * NumOfArgs - the number of total arguments
  859. * ... - the additonal arguments for the message
  860. *
  861. * Returns:
  862. * Return value from PutMsg() M026
  863. *
  864. */
  865. int WINAPI
  866. PutStdErr(unsigned int MsgNum, unsigned int NumOfArgs, ...)
  867. {
  868. int Result;
  869. va_list arglist;
  870. va_start(arglist, NumOfArgs);
  871. Result = PutMsg(MsgNum, NumOfArgs, &arglist);
  872. va_end(arglist);
  873. return Result;
  874. }
  875. int
  876. FindMsg(unsigned MsgNum, PTCHAR NullArg, unsigned NumOfArgs, va_list *arglist)
  877. {
  878. unsigned msglen;
  879. DWORD msgsource;
  880. TCHAR *Inserts[ 2 ];
  881. CHAR numbuf[ 32 ];
  882. TCHAR wnumbuf[ 32 ];
  883. //
  884. // find message without doing argument substitution
  885. //
  886. if (MsgNum == ERROR_MR_MID_NOT_FOUND) {
  887. msglen = 0;
  888. }
  889. else {
  890. #ifdef LATER
  891. msgsource = MsgNum >= IDS_ERROR_MALLOC ?
  892. FORMAT_MESSAGE_FROM_HMODULE :
  893. FORMAT_MESSAGE_FROM_SYSTEM;
  894. #endif
  895. msgsource = FORMAT_MESSAGE_FROM_SYSTEM;
  896. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  897. NULL,
  898. MsgNum,
  899. 0,
  900. MsgBuf,
  901. MAXCBMSGBUFFER,
  902. NULL
  903. );
  904. if (msglen == 0) {
  905. if (NtDllHandle == NULL) {
  906. NtDllHandle = GetModuleHandle( TEXT("NTDLL") );
  907. }
  908. msgsource = FORMAT_MESSAGE_FROM_HMODULE;
  909. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  910. (LPVOID)NtDllHandle,
  911. MsgNum,
  912. 0,
  913. MsgBuf,
  914. MAXCBMSGBUFFER,
  915. NULL
  916. );
  917. }
  918. }
  919. if (msglen == 0) {
  920. //
  921. // didn't find message
  922. //
  923. msgsource = FORMAT_MESSAGE_FROM_SYSTEM |
  924. FORMAT_MESSAGE_ARGUMENT_ARRAY;
  925. _ultoa( MsgNum, numbuf, 16 );
  926. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
  927. Inserts[ 0 ]= wnumbuf;
  928. #ifdef LATER
  929. Inserts[ 1 ]= (MsgNum >= IDS_ERROR_MALLOC ? TEXT("Application") : TEXT("System"));
  930. #endif
  931. Inserts[ 1 ]= TEXT("System");
  932. MsgNum = ERROR_MR_MID_NOT_FOUND;
  933. msglen = FormatMessage(msgsource,
  934. NULL,
  935. MsgNum,
  936. 0,
  937. MsgBuf,
  938. MAXCBMSGBUFFER,
  939. (va_list *)Inserts
  940. );
  941. }
  942. else {
  943. // see how many arguments are expected and make sure we have enough
  944. PTCHAR tmp;
  945. ULONG count;
  946. tmp=MsgBuf;
  947. count = 0;
  948. while (tmp = mystrchr(tmp, PERCENT)) {
  949. tmp++;
  950. if (*tmp >= TEXT('1') && *tmp <= TEXT('9')) {
  951. count += 1;
  952. }
  953. else if (*tmp == PERCENT) {
  954. tmp++;
  955. }
  956. }
  957. if (count > NumOfArgs) {
  958. PTCHAR *LocalArgList;
  959. ULONG i;
  960. LocalArgList = (PTCHAR*)malloc(sizeof(PTCHAR) * count);
  961. if( LocalArgList == NULL )
  962. {
  963. msglen = 0;
  964. }
  965. else
  966. {
  967. for (i=0; i<count; i++)
  968. {
  969. if (i < NumOfArgs)
  970. {
  971. LocalArgList[i] = (PTCHAR)(ULONG_PTR)va_arg( *arglist, ULONG );
  972. }
  973. else
  974. {
  975. LocalArgList[i] = NullArg;
  976. }
  977. }
  978. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  979. NULL,
  980. MsgNum,
  981. 0,
  982. MsgBuf,
  983. MAXCBMSGBUFFER,
  984. (va_list *)LocalArgList
  985. );
  986. free(LocalArgList);
  987. }
  988. }
  989. else {
  990. msglen = FormatMessage(msgsource,
  991. NULL,
  992. MsgNum,
  993. 0,
  994. MsgBuf,
  995. MAXCBMSGBUFFER,
  996. arglist
  997. );
  998. }
  999. }
  1000. return msglen;
  1001. }
  1002. /*** PutMsg - Print a message to a handle
  1003. *
  1004. * Purpose:
  1005. * PutMsg is the work routine which interfaces command.com with the
  1006. * DOS message retriever. This routine is called by PutStdOut and
  1007. * PutStdErr.
  1008. *
  1009. * int PutMsg(unsigned MsgNum, unsigned Handle, unsigned NumOfArgs, ...)
  1010. *
  1011. * Args:
  1012. * MsgNum - the number of the message to print
  1013. * NumOfArgs - the number of total arguments
  1014. * Handle - the handle to print to
  1015. * Arg1 [Arg2...] - the additonal arguments for the message
  1016. *
  1017. * Returns:
  1018. * Return value from DOSPUTMESSAGE M026
  1019. *
  1020. * Notes:
  1021. * - PutMsg builds an argument table which is passed to DOSGETMESSAGE;
  1022. * this table contains the variable information which the DOS routine
  1023. * inserts into the message.
  1024. * - If more than one Arg is sent into PutMsg, it (or they) are taken
  1025. * from the stack in the first for loop.
  1026. * - M020 MsgBuf is a static array of 2K length. It is temporary and
  1027. * will be replaced by a more efficient method when decided upon.
  1028. *
  1029. */
  1030. int
  1031. PutMsg(unsigned int MsgNum, unsigned int NumOfArgs, va_list *arglist)
  1032. {
  1033. unsigned msglen;
  1034. PTCHAR NullArg = TEXT(" ");
  1035. WCHAR szErrorNo[256];
  1036. if (GetResourceStringFromUtilDll(IDS_ERROR_NUMBER, szErrorNo, 256))
  1037. {
  1038. fwprintf( stderr, szErrorNo, MsgNum );
  1039. }
  1040. msglen = FindMsg(MsgNum,NullArg,NumOfArgs,arglist);
  1041. My_fwprintf( stderr, MsgBuf );
  1042. return NO_ERROR;
  1043. }
  1044. /***
  1045. * mystrchr(string, c) - search a string for a character
  1046. *
  1047. * mystrchr will search through string and return a pointer to the first
  1048. * occurance of the character c. This version of mystrchr knows about
  1049. * double byte characters. Note that c must be a single byte character.
  1050. *
  1051. */
  1052. TCHAR *
  1053. mystrchr(TCHAR const *string, int c)
  1054. {
  1055. /* handle null seperatly to make main loop easier to code */
  1056. if (string == NULL)
  1057. return(NULL);
  1058. if (c == NULLC)
  1059. return((TCHAR *)(string + wcslen(string)));
  1060. return wcschr( string, (TCHAR)c );
  1061. }
  1062. /***
  1063. * My_wprintf(format) - print formatted data
  1064. *
  1065. * Prints Unicode formatted string to console window using WriteConsoleW.
  1066. * Note: This My_wprintf() is used to workaround the problem in c-runtime
  1067. * which looks up LC_CTYPE even for Unicode string.
  1068. *
  1069. */
  1070. int __cdecl
  1071. My_wprintf(
  1072. const wchar_t *format,
  1073. ...
  1074. )
  1075. {
  1076. DWORD cchWChar;
  1077. va_list args;
  1078. va_start( args, format );
  1079. cchWChar = My_vfwprintf(stdout, format, args);
  1080. va_end(args);
  1081. return cchWChar;
  1082. }
  1083. /***
  1084. * My_fwprintf(stream, format) - print formatted data
  1085. *
  1086. * Prints Unicode formatted string to console window using WriteConsoleW.
  1087. * Note: This My_fwprintf() is used to workaround the problem in c-runtime
  1088. * which looks up LC_CTYPE even for Unicode string.
  1089. *
  1090. */
  1091. int __cdecl
  1092. My_fwprintf(
  1093. FILE *str,
  1094. const wchar_t *format,
  1095. ...
  1096. )
  1097. {
  1098. DWORD cchWChar;
  1099. va_list args;
  1100. va_start( args, format );
  1101. cchWChar = My_vfwprintf(str, format, args);
  1102. va_end(args);
  1103. return cchWChar;
  1104. }
  1105. int __cdecl
  1106. My_vfwprintf(
  1107. FILE *str,
  1108. const wchar_t *format,
  1109. va_list argptr
  1110. )
  1111. {
  1112. HANDLE hOut;
  1113. if (str == stderr) {
  1114. hOut = GetStdHandle(STD_ERROR_HANDLE);
  1115. }
  1116. else {
  1117. hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1118. }
  1119. if ((GetFileType(hOut) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR) {
  1120. DWORD cchWChar;
  1121. WCHAR szBufferMessage[1024];
  1122. vswprintf( szBufferMessage, format, argptr );
  1123. cchWChar = wcslen(szBufferMessage);
  1124. WriteConsoleW(hOut, szBufferMessage, cchWChar, &cchWChar, NULL);
  1125. return cchWChar;
  1126. }
  1127. return vfwprintf(str, format, argptr);
  1128. }