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.

1324 lines
38 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) / sizeof(WCHAR) ) {
  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) / sizeof(WCHAR) ) {
  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. size_t i;
  326. size_t namelen = wcslen(pProgramName);
  327. i = wsprintf(szUsage, L"%s {", pProgramName);
  328. for ( pProg = pProgramCommands->pFirst, bFirst = TRUE;
  329. pProg != NULL;
  330. pProg = pProg->pNext ) {
  331. if ( !pProg->fAlias ) {
  332. if ( (i + wcslen(pProg->Command) + (bFirst ? 1 : 3)) >= 80 ) {
  333. wcscat(szUsage, L"\n");
  334. if ( fError )
  335. My_fwprintf(stderr, szUsage);
  336. else
  337. My_wprintf(szUsage);
  338. bFirst = TRUE;
  339. for ( i=0; i < namelen; i++)
  340. szUsage[i] = L' ';
  341. }
  342. i += wsprintf( &(szUsage[i]),
  343. bFirst ? L" %s" : L" | %s",
  344. pProg->Command );
  345. bFirst = FALSE;
  346. }
  347. }
  348. wcscat(szUsage, L" }\n");
  349. if ( fError )
  350. My_fwprintf(stderr, szUsage);
  351. else
  352. My_wprintf(szUsage);
  353. }
  354. /*******************************************************************************
  355. * ScanPrintfString
  356. * Scans a string, detects any % and double it
  357. * (Use it for any string argument before calling ErrorPrintf)
  358. *
  359. *******************************************************************************/
  360. #define PERCENTCHAR L'%'
  361. BOOLEAN ScanPrintfString(PWCHAR pSource, PWCHAR *ppDest)
  362. {
  363. size_t i, j = 0, k = 0, n = 0;
  364. size_t SourceLength;
  365. PWCHAR pDest = NULL;
  366. if ( (pSource == 0) || (ppDest == 0))
  367. {
  368. SetLastError(ERROR_INVALID_PARAMETER);
  369. return (FALSE);
  370. }
  371. SourceLength = wcslen(pSource);
  372. for (i = 0; i < SourceLength; i++)
  373. {
  374. if (pSource[i] == PERCENTCHAR)
  375. {
  376. n++;
  377. }
  378. }
  379. if (n != 0) // at least one %, we need to build a new string.
  380. {
  381. pDest = (PWCHAR)malloc((SourceLength + n + 1) * sizeof(WCHAR));
  382. *ppDest = pDest;
  383. if (pDest == NULL)
  384. {
  385. return FALSE;
  386. }
  387. else
  388. {
  389. //
  390. // rescan and copy
  391. //
  392. for (i = 0; i < SourceLength; i++)
  393. {
  394. if (pSource[i] == PERCENTCHAR)
  395. {
  396. if ( i > j )
  397. {
  398. memcpy(&(pDest[k]), &(pSource[j]), (i - j) * sizeof(WCHAR));
  399. k += (i-j);
  400. j = i;
  401. }
  402. pDest[k] = PERCENTCHAR;
  403. pDest[k+1] = PERCENTCHAR;
  404. k += 2;
  405. j++;
  406. }
  407. }
  408. if (i > j)
  409. {
  410. memcpy(&(pDest[k]), &(pSource[j]), (i - j) * sizeof(WCHAR));
  411. }
  412. pDest[SourceLength + n] = L'\0';
  413. }
  414. }
  415. else // OK pSource is fine; no need of a new string.
  416. {
  417. *ppDest = NULL;
  418. }
  419. return (TRUE);
  420. }
  421. /*******************************************************************************
  422. *
  423. * Message
  424. * Display a message to stdout with variable arguments. Message
  425. * format string comes from the application resources.
  426. *
  427. * ENTRY:
  428. * nResourceID (input)
  429. * Resource ID of the format string to use in the message.
  430. * ... (input)
  431. * Optional additional arguments to be used with format string.
  432. *
  433. * EXIT:
  434. *
  435. ******************************************************************************/
  436. VOID WINAPI
  437. Message( int nResourceID, ...)
  438. {
  439. WCHAR sz1[256], sz2[512];
  440. va_list args;
  441. va_start( args, nResourceID );
  442. if ( LoadString( NULL, nResourceID, sz1, 256 ) ) {
  443. vswprintf( sz2, sz1, args );
  444. My_wprintf( sz2 );
  445. } else {
  446. fwprintf( stderr, L"{Message(): LoadString failed, Error %ld, (0x%08X)}\n",
  447. GetLastError(), GetLastError() );
  448. }
  449. va_end(args);
  450. } /* Message() */
  451. /************************************************************************************
  452. * StringMessage
  453. * used as a pre-routine for Message in case the argument is a single string
  454. * (fix for bug #334374)
  455. *
  456. ************************************************************************************/
  457. VOID WINAPI
  458. StringMessage(int nErrorResourceID, PWCHAR pString)
  459. {
  460. PWCHAR pFixedString = NULL;
  461. if (ScanPrintfString(pString, &pFixedString) )
  462. {
  463. if (pFixedString != NULL)
  464. {
  465. Message(nErrorResourceID, pFixedString);
  466. free(pFixedString);
  467. }
  468. else
  469. {
  470. Message(nErrorResourceID, pString);
  471. }
  472. }
  473. else
  474. {
  475. Message(nErrorResourceID, L" ");
  476. }
  477. }
  478. /************************************************************************************
  479. * StringErrorPrintf
  480. * used as a pre-routine for ErrorPrintf in case the argument is a single string
  481. * (fix for bug #334374)
  482. *
  483. ************************************************************************************/
  484. VOID WINAPI
  485. StringErrorPrintf(int nErrorResourceID, PWCHAR pString)
  486. {
  487. PWCHAR pFixedString = NULL;
  488. if (ScanPrintfString(pString, &pFixedString) )
  489. {
  490. if (pFixedString != NULL)
  491. {
  492. ErrorPrintf(nErrorResourceID, pFixedString);
  493. free(pFixedString);
  494. }
  495. else
  496. {
  497. ErrorPrintf(nErrorResourceID, pString);
  498. }
  499. }
  500. else
  501. {
  502. ErrorPrintf(nErrorResourceID, L" ");
  503. }
  504. }
  505. /************************************************************************************
  506. * StringDwordMessage
  507. * used as a pre-routine for Message in case the argument are:
  508. * a single string + a ulong
  509. * (fix for bug #334374)
  510. *
  511. ************************************************************************************/
  512. VOID WINAPI
  513. StringDwordMessage(int nErrorResourceID, PWCHAR pString, DWORD Num)
  514. {
  515. PWCHAR pFixedString = NULL;
  516. if (ScanPrintfString(pString, &pFixedString) )
  517. {
  518. if (pFixedString != NULL)
  519. {
  520. Message(nErrorResourceID, pFixedString, Num);
  521. free(pFixedString);
  522. }
  523. else
  524. {
  525. Message(nErrorResourceID, pString, Num);
  526. }
  527. }
  528. else
  529. {
  530. Message(nErrorResourceID, L" ", Num);
  531. }
  532. }
  533. /************************************************************************************
  534. * DwordStringMessage
  535. * used as a pre-routine for Message in case the argument are:
  536. * a single string + a ulong
  537. * (fix for bug #334374)
  538. *
  539. ************************************************************************************/
  540. VOID WINAPI
  541. DwordStringMessage(int nErrorResourceID, DWORD Num, PWCHAR pString)
  542. {
  543. PWCHAR pFixedString = NULL;
  544. if (ScanPrintfString(pString, &pFixedString) )
  545. {
  546. if (pFixedString != NULL)
  547. {
  548. Message(nErrorResourceID, Num, pFixedString);
  549. free(pFixedString);
  550. }
  551. else
  552. {
  553. Message(nErrorResourceID, Num, pString);
  554. }
  555. }
  556. else
  557. {
  558. Message(nErrorResourceID, Num, L" ");
  559. }
  560. }
  561. /************************************************************************************
  562. * StringDwordErrorPrintf
  563. * used as a pre-routine for ErrorPrintf in case the argument are:
  564. * a single string + a ulong
  565. * (fix for bug #334374)
  566. *
  567. ************************************************************************************/
  568. VOID WINAPI
  569. StringDwordErrorPrintf(int nErrorResourceID, PWCHAR pString, DWORD Num)
  570. {
  571. PWCHAR pFixedString = NULL;
  572. if (ScanPrintfString(pString, &pFixedString) )
  573. {
  574. if (pFixedString != NULL)
  575. {
  576. ErrorPrintf(nErrorResourceID, pFixedString, Num);
  577. free(pFixedString);
  578. }
  579. else
  580. {
  581. ErrorPrintf(nErrorResourceID, pString, Num);
  582. }
  583. }
  584. else
  585. {
  586. ErrorPrintf(nErrorResourceID, L" ", Num);
  587. }
  588. }
  589. /*******************************************************************************
  590. *
  591. * ErrorPrintf
  592. * Output an error message to stderr with variable arguments. Message
  593. * format string comes from the application resources.
  594. *
  595. * ENTRY:
  596. * nErrorResourceID (input)
  597. * Resource ID of the format string to use in the error message.
  598. * ... (input)
  599. * Optional additional arguments to be used with format string.
  600. *
  601. * EXIT:
  602. *
  603. ******************************************************************************/
  604. VOID WINAPI
  605. ErrorPrintf( int nErrorResourceID, ...)
  606. {
  607. WCHAR sz1[256], sz2[512];
  608. va_list args;
  609. va_start( args, nErrorResourceID );
  610. if ( LoadString( NULL, nErrorResourceID, sz1, 256 ) ) {
  611. vswprintf( sz2, sz1, args );
  612. My_fwprintf( stderr, sz2 );
  613. } else {
  614. fwprintf( stderr, L"{ErrorPrintf(): LoadString failed, Error %ld, (0x%08X)}\n",
  615. GetLastError(), GetLastError() );
  616. PutStdErr( GetLastError(), 0 );
  617. }
  618. va_end(args);
  619. } /* ErrorPrintf() */
  620. /*******************************************************************************
  621. *
  622. * TruncateString
  623. *
  624. * This routine truncates given string with elipsis '...' suffix, if needed.
  625. *
  626. *
  627. * ENTRY:
  628. * pString (input/output)
  629. * pointer to string to truncate
  630. * MaxLength (input)
  631. * maximum length of string
  632. *
  633. * EXIT:
  634. * nothing
  635. *
  636. ******************************************************************************/
  637. VOID WINAPI
  638. TruncateString( PWCHAR pString, int MaxLength )
  639. {
  640. /*
  641. * if string is too long, trucate it
  642. */
  643. if ( (int)wcslen(pString) > MaxLength && MaxLength > 2 ) {
  644. wcscpy( pString + MaxLength - 3, L"..." );
  645. }
  646. } /* TruncateString() */
  647. /*******************************************************************************
  648. *
  649. * EnumerateDevices
  650. *
  651. * Perform PD device enumeration for the specified PD DLL.
  652. *
  653. * ENTRY:
  654. * pDllName (input)
  655. * Pointer to DLLNAME string specifying the PD DLL to enumerate.
  656. * pEntries (output)
  657. * Points to variable to return number of devices that were enumerated.
  658. *
  659. * EXIT:
  660. * (PPDPARAMS) Points to a malloc()'ed PDPARAMS array containing the
  661. * enumeration results if sucessful. The caller must perform
  662. * free of this array when done. NULL if error.
  663. *
  664. ******************************************************************************/
  665. /*
  666. * Typedefs for PdEnumerate function (from ...WINDOWS\INC\CITRIX\PDAPI.H)
  667. */
  668. typedef NTSTATUS (APIENTRY * PPDENUMERATE)(PULONG, PPDPARAMS, PULONG);
  669. #define INITIAL_ENUMERATION_COUNT 30
  670. PPDPARAMS WINAPI
  671. EnumerateDevices( PDLLNAME pDllName,
  672. PULONG pEntries )
  673. {
  674. PPDENUMERATE pPdEnumerate;
  675. HANDLE Handle;
  676. ULONG ByteCount;
  677. NTSTATUS Status;
  678. int i;
  679. PPDPARAMSW pPdParams = NULL;
  680. /*
  681. * Load the specified PD DLL.
  682. */
  683. if ( (Handle = LoadLibrary(pDllName)) == NULL ) {
  684. ErrorOutFromResource(IDS_DEVICE_ENUM_CANT_LOAD, pDllName);
  685. // fwprintf(
  686. // stderr,
  687. // L"Device enumeration failure:\n\tCan't load the %s DLL for device enumeration\n",
  688. // pDllName );
  689. goto CantLoad;
  690. }
  691. /*
  692. * Get the PD enumeration function's load entry pointer.
  693. */
  694. if ( (pPdEnumerate =
  695. (PPDENUMERATE)GetProcAddress((HMODULE)Handle, "PdEnumerate"))
  696. == NULL ) {
  697. ErrorOutFromResource(IDS_DEVENUM_NO_ENTRY_POINT, pDllName);
  698. // fwprintf(
  699. // stderr,
  700. // L"Device enumeration failure:\n\tDLL %s has no enumeration entry point\n",
  701. // pDllName );
  702. goto EnumerateMissing;
  703. }
  704. /*
  705. * Call enumerate in loop till we hit enough buffer entries to handle
  706. * a complete enumeration.
  707. */
  708. for ( i = INITIAL_ENUMERATION_COUNT; ; i *= 2 ) {
  709. if ( pPdParams == NULL ) {
  710. pPdParams =
  711. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  712. } else {
  713. free(pPdParams);
  714. pPdParams =
  715. (PPDPARAMS)malloc(ByteCount = (sizeof(PDPARAMS) * i));
  716. }
  717. if ( pPdParams == NULL ) {
  718. ErrorOutFromResource(IDS_ERROR_MEMORY);
  719. // fwprintf(stderr, L"Error allocating memory\n");
  720. goto OutOfMemory;
  721. }
  722. /*
  723. * Perform enumeration and break loop if successful.
  724. */
  725. if ( (Status = (*pPdEnumerate)(pEntries, pPdParams, &ByteCount))
  726. == STATUS_SUCCESS )
  727. break;
  728. /*
  729. * If we received any other error other than 'buffer too small',
  730. * complain and quit.
  731. */
  732. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  733. ErrorOutFromResource(IDS_DEVICE_ENUM_FAILED, pDllName, Status);
  734. // fwprintf(
  735. // stderr,
  736. // L"Device enumeration failure\n\tDLL %s, Error 0x%08lX\n",
  737. // pDllName, Status );
  738. goto BadEnumerate;
  739. }
  740. }
  741. /*
  742. * Close the DLL handle and return the PDPARAMS pointer.
  743. */
  744. CloseHandle(Handle);
  745. return(pPdParams);
  746. /*-------------------------------------
  747. * Error cleanup and return
  748. */
  749. BadEnumerate:
  750. free(pPdParams);
  751. OutOfMemory:
  752. EnumerateMissing:
  753. CloseHandle( Handle );
  754. CantLoad:
  755. return(NULL);
  756. } /* EnumerateDevices() */
  757. /******************************************************************************
  758. *
  759. * wfopen
  760. *
  761. * UNICODE version of fopen
  762. *
  763. * ENTRY:
  764. * filename (input)
  765. * UNICODE filename to open.
  766. * mode (input)
  767. * UNICODE file open mode string.
  768. *
  769. * EXIT:
  770. * Pointer to FILE or NULL if open error.
  771. *
  772. *****************************************************************************/
  773. FILE * WINAPI
  774. wfopen( LPCWSTR filename, LPCWSTR mode )
  775. {
  776. PCHAR FileBuf, ModeBuf;
  777. FILE *pFile;
  778. if ( !(FileBuf = (PCHAR)malloc((wcslen(filename)+1) * sizeof(CHAR))) )
  779. goto BadFileBufAlloc;
  780. if ( !(ModeBuf = (PCHAR)malloc((wcslen(mode)+1) * sizeof(CHAR))) )
  781. goto BadModeBufAlloc;
  782. /*
  783. * Convert UNICODE strings to ANSI and call ANSI fopen.
  784. */
  785. wcstombs(FileBuf, filename, wcslen(filename)+1);
  786. wcstombs(ModeBuf, mode, wcslen(mode)+1);
  787. pFile = fopen(FileBuf, ModeBuf);
  788. /*
  789. * Clean up and return
  790. */
  791. free(FileBuf);
  792. free(ModeBuf);
  793. return(pFile);
  794. /*-------------------------------------
  795. * Error cleanup and return
  796. */
  797. BadModeBufAlloc:
  798. free(FileBuf);
  799. BadFileBufAlloc:
  800. return(NULL);
  801. } /* wfopen() */
  802. /******************************************************************************
  803. *
  804. * wfgets
  805. *
  806. * UNICODE version of fgets
  807. *
  808. * ENTRY:
  809. * Buffer (output)
  810. * Buffer to place string retreived from stream
  811. * Len (input)
  812. * Maximum number of WCHARs in buffer.
  813. * Stream (input)
  814. * STDIO file stream for input
  815. *
  816. * EXIT:
  817. * Pointer to Buffer or NULL.
  818. *
  819. *****************************************************************************/
  820. PWCHAR WINAPI
  821. wfgets( PWCHAR Buffer, int Len, FILE *Stream )
  822. {
  823. PCHAR AnsiBuf, pRet;
  824. size_t count;
  825. if ( !(AnsiBuf = (PCHAR)malloc(Len * sizeof(CHAR))) )
  826. goto BadAnsiBufAlloc;
  827. /*
  828. * Get the ANSI version of the string from the stream
  829. */
  830. if ( !(pRet = fgets(AnsiBuf, Len, Stream)) )
  831. goto NullFgets;
  832. /*
  833. * Convert to UNICODE string in user's buffer.
  834. */
  835. count = mbstowcs(Buffer, AnsiBuf, strlen(AnsiBuf)+1);
  836. /*
  837. * Clean up and return
  838. */
  839. free(AnsiBuf);
  840. return(Buffer);
  841. /*-------------------------------------
  842. * Error cleanup and return
  843. */
  844. NullFgets:
  845. free(AnsiBuf);
  846. BadAnsiBufAlloc:
  847. return(NULL);
  848. } /* wfgets() */
  849. /*** PutStdErr - Print a message to STDERR
  850. *
  851. * Purpose:
  852. * Calls PutMsg sending STDERR as the handle to which the message
  853. * will be written.
  854. *
  855. * int PutStdErr(unsigned MsgNum, unsigned NumOfArgs, ...)
  856. *
  857. * Args:
  858. * MsgNum - the number of the message to print
  859. * NumOfArgs - the number of total arguments
  860. * ... - the additonal arguments for the message
  861. *
  862. * Returns:
  863. * Return value from PutMsg() M026
  864. *
  865. */
  866. int WINAPI
  867. PutStdErr(unsigned int MsgNum, unsigned int NumOfArgs, ...)
  868. {
  869. int Result;
  870. va_list arglist;
  871. va_start(arglist, NumOfArgs);
  872. Result = PutMsg(MsgNum, NumOfArgs, &arglist);
  873. va_end(arglist);
  874. return Result;
  875. }
  876. int
  877. FindMsg(unsigned MsgNum, PTCHAR NullArg, unsigned NumOfArgs, va_list *arglist)
  878. {
  879. unsigned msglen;
  880. DWORD msgsource;
  881. TCHAR *Inserts[ 2 ];
  882. CHAR numbuf[ 32 ];
  883. TCHAR wnumbuf[ 32 ];
  884. //
  885. // find message without doing argument substitution
  886. //
  887. if (MsgNum == ERROR_MR_MID_NOT_FOUND) {
  888. msglen = 0;
  889. }
  890. else {
  891. #ifdef LATER
  892. msgsource = MsgNum >= IDS_ERROR_MALLOC ?
  893. FORMAT_MESSAGE_FROM_HMODULE :
  894. FORMAT_MESSAGE_FROM_SYSTEM;
  895. #endif
  896. msgsource = FORMAT_MESSAGE_FROM_SYSTEM;
  897. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  898. NULL,
  899. MsgNum,
  900. 0,
  901. MsgBuf,
  902. MAXCBMSGBUFFER,
  903. NULL
  904. );
  905. if (msglen == 0) {
  906. if (NtDllHandle == NULL) {
  907. NtDllHandle = GetModuleHandle( TEXT("NTDLL") );
  908. }
  909. msgsource = FORMAT_MESSAGE_FROM_HMODULE;
  910. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_IGNORE_INSERTS,
  911. (LPVOID)NtDllHandle,
  912. MsgNum,
  913. 0,
  914. MsgBuf,
  915. MAXCBMSGBUFFER,
  916. NULL
  917. );
  918. }
  919. }
  920. if (msglen == 0) {
  921. //
  922. // didn't find message
  923. //
  924. msgsource = FORMAT_MESSAGE_FROM_SYSTEM |
  925. FORMAT_MESSAGE_ARGUMENT_ARRAY;
  926. _ultoa( MsgNum, numbuf, 16 );
  927. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
  928. Inserts[ 0 ]= wnumbuf;
  929. #ifdef LATER
  930. Inserts[ 1 ]= (MsgNum >= IDS_ERROR_MALLOC ? TEXT("Application") : TEXT("System"));
  931. #endif
  932. Inserts[ 1 ]= TEXT("System");
  933. MsgNum = ERROR_MR_MID_NOT_FOUND;
  934. msglen = FormatMessage(msgsource,
  935. NULL,
  936. MsgNum,
  937. 0,
  938. MsgBuf,
  939. MAXCBMSGBUFFER,
  940. (va_list *)Inserts
  941. );
  942. }
  943. else {
  944. // see how many arguments are expected and make sure we have enough
  945. PTCHAR tmp;
  946. ULONG count;
  947. tmp=MsgBuf;
  948. count = 0;
  949. while (tmp = mystrchr(tmp, PERCENT)) {
  950. tmp++;
  951. if (*tmp >= TEXT('1') && *tmp <= TEXT('9')) {
  952. count += 1;
  953. }
  954. else if (*tmp == PERCENT) {
  955. tmp++;
  956. }
  957. }
  958. if (count > NumOfArgs) {
  959. PTCHAR *LocalArgList;
  960. ULONG i;
  961. LocalArgList = (PTCHAR*)malloc(sizeof(PTCHAR) * count);
  962. if( LocalArgList == NULL )
  963. {
  964. msglen = 0;
  965. }
  966. else
  967. {
  968. for (i=0; i<count; i++)
  969. {
  970. if (i < NumOfArgs)
  971. {
  972. LocalArgList[i] = (PTCHAR)(ULONG_PTR)va_arg( *arglist, ULONG );
  973. }
  974. else
  975. {
  976. LocalArgList[i] = NullArg;
  977. }
  978. }
  979. msglen = FormatMessage(msgsource | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  980. NULL,
  981. MsgNum,
  982. 0,
  983. MsgBuf,
  984. MAXCBMSGBUFFER,
  985. (va_list *)LocalArgList
  986. );
  987. free(LocalArgList);
  988. }
  989. }
  990. else {
  991. msglen = FormatMessage(msgsource,
  992. NULL,
  993. MsgNum,
  994. 0,
  995. MsgBuf,
  996. MAXCBMSGBUFFER,
  997. arglist
  998. );
  999. }
  1000. }
  1001. return msglen;
  1002. }
  1003. /*** PutMsg - Print a message to a handle
  1004. *
  1005. * Purpose:
  1006. * PutMsg is the work routine which interfaces command.com with the
  1007. * DOS message retriever. This routine is called by PutStdOut and
  1008. * PutStdErr.
  1009. *
  1010. * int PutMsg(unsigned MsgNum, unsigned Handle, unsigned NumOfArgs, ...)
  1011. *
  1012. * Args:
  1013. * MsgNum - the number of the message to print
  1014. * NumOfArgs - the number of total arguments
  1015. * Handle - the handle to print to
  1016. * Arg1 [Arg2...] - the additonal arguments for the message
  1017. *
  1018. * Returns:
  1019. * Return value from DOSPUTMESSAGE M026
  1020. *
  1021. * Notes:
  1022. * - PutMsg builds an argument table which is passed to DOSGETMESSAGE;
  1023. * this table contains the variable information which the DOS routine
  1024. * inserts into the message.
  1025. * - If more than one Arg is sent into PutMsg, it (or they) are taken
  1026. * from the stack in the first for loop.
  1027. * - M020 MsgBuf is a static array of 2K length. It is temporary and
  1028. * will be replaced by a more efficient method when decided upon.
  1029. *
  1030. */
  1031. int
  1032. PutMsg(unsigned int MsgNum, unsigned int NumOfArgs, va_list *arglist)
  1033. {
  1034. unsigned msglen;
  1035. PTCHAR NullArg = TEXT(" ");
  1036. WCHAR szErrorNo[256];
  1037. if (GetResourceStringFromUtilDll(IDS_ERROR_NUMBER, szErrorNo, 256))
  1038. {
  1039. fwprintf( stderr, szErrorNo, MsgNum );
  1040. }
  1041. msglen = FindMsg(MsgNum,NullArg,NumOfArgs,arglist);
  1042. My_fwprintf( stderr, MsgBuf );
  1043. return NO_ERROR;
  1044. }
  1045. /***
  1046. * mystrchr(string, c) - search a string for a character
  1047. *
  1048. * mystrchr will search through string and return a pointer to the first
  1049. * occurance of the character c. This version of mystrchr knows about
  1050. * double byte characters. Note that c must be a single byte character.
  1051. *
  1052. */
  1053. TCHAR *
  1054. mystrchr(TCHAR const *string, int c)
  1055. {
  1056. /* handle null seperatly to make main loop easier to code */
  1057. if (string == NULL)
  1058. return(NULL);
  1059. if (c == NULLC)
  1060. return((TCHAR *)(string + wcslen(string)));
  1061. return wcschr( string, (TCHAR)c );
  1062. }
  1063. /***
  1064. * My_wprintf(format) - print formatted data
  1065. *
  1066. * Prints Unicode formatted string to console window using WriteConsoleW.
  1067. * Note: This My_wprintf() is used to workaround the problem in c-runtime
  1068. * which looks up LC_CTYPE even for Unicode string.
  1069. *
  1070. */
  1071. int __cdecl
  1072. My_wprintf(
  1073. const wchar_t *format,
  1074. ...
  1075. )
  1076. {
  1077. DWORD cchWChar;
  1078. va_list args;
  1079. va_start( args, format );
  1080. cchWChar = My_vfwprintf(stdout, format, args);
  1081. va_end(args);
  1082. return cchWChar;
  1083. }
  1084. /***
  1085. * My_fwprintf(stream, format) - print formatted data
  1086. *
  1087. * Prints Unicode formatted string to console window using WriteConsoleW.
  1088. * Note: This My_fwprintf() is used to workaround the problem in c-runtime
  1089. * which looks up LC_CTYPE even for Unicode string.
  1090. *
  1091. */
  1092. int __cdecl
  1093. My_fwprintf(
  1094. FILE *str,
  1095. const wchar_t *format,
  1096. ...
  1097. )
  1098. {
  1099. DWORD cchWChar;
  1100. va_list args;
  1101. va_start( args, format );
  1102. cchWChar = My_vfwprintf(str, format, args);
  1103. va_end(args);
  1104. return cchWChar;
  1105. }
  1106. int __cdecl
  1107. My_vfwprintf(
  1108. FILE *str,
  1109. const wchar_t *format,
  1110. va_list argptr
  1111. )
  1112. {
  1113. HANDLE hOut;
  1114. if (str == stderr) {
  1115. hOut = GetStdHandle(STD_ERROR_HANDLE);
  1116. }
  1117. else {
  1118. hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1119. }
  1120. if ((GetFileType(hOut) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR) {
  1121. DWORD cchWChar;
  1122. WCHAR szBufferMessage[1024];
  1123. vswprintf( szBufferMessage, format, argptr );
  1124. cchWChar = wcslen(szBufferMessage);
  1125. WriteConsoleW(hOut, szBufferMessage, cchWChar, &cchWChar, NULL);
  1126. return cchWChar;
  1127. }
  1128. return vfwprintf(str, format, argptr);
  1129. }