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.

539 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. w32drman
  5. Abstract:
  6. This module defines a special subclass of the Win32 client-side RDP
  7. printer redirection "device" class. The subclass, W32DrManualPrn
  8. manages a queue that is manually installed by a user by attaching
  9. a server-side queue to a client-side redirected printing port.
  10. Author:
  11. Tad Brockway 3/23/99
  12. Revision History:
  13. --*/
  14. #include <precom.h>
  15. #define TRC_FILE "W32DrMan"
  16. #include "w32drman.h"
  17. #include "w32proc.h"
  18. #include "w32utl.h"
  19. #include "w32drprt.h"
  20. #include "drdbg.h"
  21. #ifdef OS_WINCE
  22. #include "ceconfig.h"
  23. #endif
  24. ///////////////////////////////////////////////////////////////
  25. //
  26. // W32DrManualPrn Methods
  27. //
  28. //
  29. //
  30. // W32DrManualPrn
  31. //
  32. W32DrManualPrn::W32DrManualPrn(
  33. ProcObj *processObject,
  34. const DRSTRING printerName, const DRSTRING driverName,
  35. const DRSTRING portName, BOOL defaultPrinter, ULONG deviceID) :
  36. W32DrPRN(processObject, printerName, driverName, portName, NULL,
  37. defaultPrinter, deviceID, portName)
  38. {
  39. }
  40. //
  41. // ~W32DrManualPrn
  42. //
  43. W32DrManualPrn::~W32DrManualPrn()
  44. {
  45. }
  46. /*++
  47. Routine Description:
  48. For serial printers, we need to initialize the COM port.
  49. Arguments:
  50. fileHandle - Open file object for the COM port.
  51. Return Value:
  52. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  53. --*/
  54. DWORD
  55. W32DrManualPrn::InitializeDevice(
  56. DrFile* fileObj
  57. )
  58. {
  59. HANDLE FileHandle;
  60. LPTSTR portName;
  61. DC_BEGIN_FN("W32DrManualPrn::InitializeDevice");
  62. if (_isSerialPort) {
  63. //
  64. // Our devicePath is formulated as
  65. // sprintf(_devicePath, TEXT("\\\\.\\%s"), portName);
  66. //
  67. portName = _tcsrchr( _devicePath, _T('\\') );
  68. if( portName == NULL ) {
  69. // invalid device path
  70. goto CLEANUPANDEXIT;
  71. }
  72. portName++;
  73. if( !*portName ) {
  74. //
  75. // Invalid port name
  76. //
  77. goto CLEANUPANDEXIT;
  78. }
  79. //
  80. // Get the file handle.
  81. //
  82. FileHandle = fileObj->GetFileHandle();
  83. if (!FileHandle || FileHandle == INVALID_HANDLE_VALUE) {
  84. ASSERT(FALSE);
  85. TRC_ERR((TB, _T("File Object was not created successfully")));
  86. goto CLEANUPANDEXIT;
  87. }
  88. W32DrPRT::InitializeSerialPort(portName, FileHandle);
  89. }
  90. CLEANUPANDEXIT:
  91. DC_END_FN();
  92. //
  93. // This function always returns success. If the port cannot
  94. // be initialized, then subsequent port commands will fail
  95. // anyway.
  96. //
  97. return ERROR_SUCCESS;
  98. }
  99. DWORD
  100. W32DrManualPrn::Enumerate(
  101. IN ProcObj *procObj,
  102. IN DrDeviceMgr *deviceMgr
  103. )
  104. /*++
  105. Routine Description:
  106. Enumerate devices of this type by adding appropriate device
  107. instances to the device manager.
  108. Arguments:
  109. procObj - Corresponding process object.
  110. deviceMgr - Device manager to add devices to.
  111. Return Value:
  112. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  113. --*/
  114. {
  115. HKEY hKey = NULL;
  116. W32DrPRN *prnDevice;
  117. ULONG ulIndex;
  118. TCHAR achRegSubKey[REGISTRY_KEY_NAME_SIZE];
  119. ULONG ulRegSubKeySize;
  120. DWORD result;
  121. HKEY hTsClientKey = NULL;
  122. DWORD ulType;
  123. DC_BEGIN_FN("W32DrManualPrn::Enumerate");
  124. if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectPrinters)
  125. {
  126. TRC_DBG((TB,_T("Printer redirection disabled, bailing out")));
  127. return ERROR_SUCCESS;
  128. }
  129. //
  130. // Open cached printers key.
  131. //
  132. #ifdef OS_WINCE
  133. //Before opening, make sure the printer list is current.
  134. //This is to ensure that local printers deleted from within a TS session, show up
  135. //when you log on the next time
  136. CEUpdateCachedPrinters();
  137. #endif
  138. result =
  139. RegCreateKeyEx(HKEY_CURRENT_USER, REG_RDPDR_CACHED_PRINTERS,
  140. 0L, NULL, REG_OPTION_NON_VOLATILE,
  141. KEY_ALL_ACCESS, NULL, &hKey,
  142. NULL);
  143. if (result != ERROR_SUCCESS) {
  144. TRC_ERR((TB, _T("RegCreateKeyEx failed, %ld."), result));
  145. hKey = NULL;
  146. }
  147. //
  148. // Check for maximum config length specified in the registry
  149. // by an admin, if any
  150. //
  151. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  152. REG_TERMINALSERVERCLIENT, 0L,
  153. KEY_READ, &hTsClientKey)
  154. == ERROR_SUCCESS) {
  155. DWORD maxRegCacheData, sz;
  156. if (RegQueryValueEx(hTsClientKey, REG_RDPDR_PRINTER_MAXCACHELEN,
  157. NULL, &ulType, (LPBYTE)&maxRegCacheData, &sz) == ERROR_SUCCESS) {
  158. W32DrPRN::_maxCacheDataSize = maxRegCacheData;
  159. }
  160. RegCloseKey(hTsClientKey);
  161. }
  162. //
  163. // Enumerate cached printers.
  164. //
  165. for (ulIndex = 0; result == ERROR_SUCCESS; ulIndex++) {
  166. //
  167. // Try enumerating the ulIndex'th sub key.
  168. //
  169. ulRegSubKeySize = sizeof(achRegSubKey) / sizeof(TCHAR);
  170. result = RegEnumKeyEx(
  171. hKey, ulIndex,
  172. (LPTSTR)achRegSubKey,
  173. &ulRegSubKeySize, //size in TCHARS
  174. NULL,NULL,NULL,NULL
  175. );
  176. if (result == ERROR_SUCCESS) {
  177. //
  178. // Resolve the registry key into a printer object.
  179. //
  180. //
  181. // Don't like the fact that we are scanning for automatic
  182. // printer settings here. I don't know how much value there is
  183. // in cleaning this up, however.
  184. //
  185. prnDevice = ResolveCachedPrinter(procObj, deviceMgr,
  186. hKey, achRegSubKey);
  187. //
  188. // If we didn't get a printer device object then remove the registry key.
  189. //
  190. if (prnDevice == NULL) {
  191. TRC_ERR((TB, _T("Didn't get a printer for %s."), achRegSubKey)
  192. );
  193. RegDeleteKey(hKey, achRegSubKey);
  194. }
  195. }
  196. else {
  197. TRC_NRM((TB, _T("RegEnumKeyEx %ld."), result));
  198. }
  199. }
  200. //
  201. // Close the parent registry key.
  202. //
  203. if (hKey != NULL) {
  204. RegCloseKey(hKey);
  205. }
  206. DC_END_FN();
  207. return result;
  208. }
  209. VOID
  210. W32DrManualPrn::CachedDataRestored()
  211. /*++
  212. Routine Description:
  213. Called once the cached printer data has reached a "steady state."
  214. Arguments:
  215. NA
  216. Return Value:
  217. NA
  218. --*/
  219. {
  220. WCHAR *portName;
  221. DC_BEGIN_FN("W32DrManualPrn::CachedDataRestored");
  222. //
  223. // Parse the cached printer information for specific information
  224. // about this printer that is generic to all printers.
  225. //
  226. if (!ParsePrinterCacheInfo()) {
  227. if (_cachedData != NULL) {
  228. delete _cachedData;
  229. _cachedData = NULL;
  230. _cachedDataSize = 0;
  231. }
  232. //
  233. // If we fail here, then we are no longer valid.
  234. //
  235. W32DrDeviceAsync::SetValid(FALSE);
  236. }
  237. else {
  238. //
  239. // Our devicePath is formulated as
  240. // sprintf(_devicePath, TEXT("\\\\.\\%s"), portName);
  241. //
  242. #ifndef OS_WINCE
  243. portName = _tcsrchr(_devicePath, _T('\\'));
  244. if( portName == NULL ) {
  245. ASSERT(FALSE);
  246. _isSerialPort = FALSE;
  247. goto CLEANUPANDEXIT;
  248. }
  249. portName++;
  250. if( !*portName ) {
  251. ASSERT(FALSE);
  252. _isSerialPort = FALSE;
  253. goto CLEANUPANDEXIT;
  254. }
  255. #else
  256. portName = _devicePath;
  257. #endif
  258. //
  259. // Find out of the port is a serial port.
  260. //
  261. _isSerialPort = !_wcsnicmp(portName, L"COM", 3);
  262. }
  263. CLEANUPANDEXIT:
  264. DC_END_FN();
  265. }
  266. BOOL
  267. W32DrManualPrn::ParsePrinterCacheInfo()
  268. /*++
  269. Routine Description:
  270. Parse the cached printer information for specific information
  271. about this printer.
  272. Arguments:
  273. NA
  274. Return Value:
  275. TRUE - if valid cache data.
  276. FALSE - if not.
  277. --*/
  278. {
  279. PRDPDR_PRINTER_ADD_CACHEDATA pAddCacheData;
  280. ULONG ulSize;
  281. PBYTE pStringData;
  282. BOOL valid;
  283. ULONG len;
  284. LPSTR ansiPortName;
  285. LPTSTR portName;
  286. DC_BEGIN_FN("W32DrManualPrn::ParsePrinterCacheInfo");
  287. ASSERT(IsValid());
  288. //
  289. // Check to see the cache size is at least the structure size.
  290. //
  291. valid =_cachedDataSize >= sizeof(RDPDR_PRINTER_ADD_CACHEDATA);
  292. //
  293. // Make sure the internal sizes match the size of the catched data.
  294. //
  295. if (valid) {
  296. pAddCacheData = (PRDPDR_PRINTER_ADD_CACHEDATA)_cachedData;
  297. ulSize =
  298. sizeof(RDPDR_PRINTER_ADD_CACHEDATA) +
  299. pAddCacheData->PnPNameLen +
  300. pAddCacheData->DriverLen +
  301. pAddCacheData->PrinterNameLen +
  302. pAddCacheData->CachedFieldsLen;
  303. valid = _cachedDataSize >= ulSize;
  304. }
  305. //
  306. // Grab the port name out of the cached data. We don't yet know our
  307. // device path because it's embedded in the cached data.
  308. //
  309. if (valid) {
  310. pAddCacheData = (PRDPDR_PRINTER_ADD_CACHEDATA)_cachedData;
  311. ansiPortName = (LPSTR)pAddCacheData->PortDosName;
  312. len = strlen(ansiPortName);
  313. }
  314. if (valid) {
  315. #if UNICODE
  316. WCHAR unicodePortName[PREFERRED_DOS_NAME_SIZE];
  317. RDPConvertToUnicode(
  318. ansiPortName,
  319. (LPWSTR)unicodePortName,
  320. sizeof(unicodePortName)/sizeof(WCHAR) );
  321. portName = (LPWSTR)unicodePortName;
  322. #else
  323. portName = ansiPortName;
  324. #endif
  325. //
  326. // Our device path is the port name.
  327. //
  328. #ifndef OS_WINCE
  329. StringCchPrintf(_devicePath,
  330. SIZE_TCHARS(_devicePath),
  331. TEXT("\\\\.\\%s"), portName);
  332. #else
  333. _stprintf(_devicePath, TEXT("\\\\.\\%s"), portName);
  334. #endif
  335. }
  336. //
  337. // Get the PnP name.
  338. //
  339. if (valid) {
  340. pStringData = (PBYTE)(pAddCacheData + 1);
  341. valid = (!pAddCacheData->PnPNameLen) ||
  342. (pAddCacheData->PnPNameLen ==
  343. ((wcslen((LPWSTR)pStringData) + 1) * sizeof(WCHAR)));
  344. }
  345. //
  346. // If we got a valid PnP name, get the driver name.
  347. //
  348. if (valid && (pAddCacheData->PnPNameLen > 0)) {
  349. //
  350. // Need to convert the name to ANSI if we are non-unicode.
  351. //
  352. #ifdef UNICODE
  353. SetPnPName((DRSTRING)pStringData);
  354. #else
  355. SetPnPName(NULL);
  356. _pnpName = new char[pAddCacheData->PnPNameLen/sizeof(WCHAR)];
  357. if (_pnpName != NULL) {
  358. valid = (RDPConvertToAnsi(
  359. (WCHAR *)pStringData, _pnpName,
  360. pAddCacheData->PnPNameLen/sizeof(WCHAR)
  361. ) == ERROR_SUCCESS);
  362. }
  363. else {
  364. TRC_ERR((TB, _T("Alloc failed.")));
  365. valid = FALSE;
  366. }
  367. #endif
  368. pStringData += pAddCacheData->PnPNameLen;
  369. valid = (!pAddCacheData->DriverLen) ||
  370. (pAddCacheData->DriverLen ==
  371. ((wcslen((LPWSTR)pStringData) + 1) * sizeof(WCHAR)));
  372. }
  373. //
  374. // If we got a valid driver name
  375. //
  376. if (valid && (pAddCacheData->DriverLen > 0)) {
  377. #ifdef UNICODE
  378. SetDriverName((DRSTRING)pStringData);
  379. #else
  380. SetDriverName(NULL);
  381. _driverName = new char[pAddCacheData->DriverLen/sizeof(WCHAR)];
  382. if (_driverName != NULL) {
  383. valid = (RDPConvertToAnsi(
  384. (WCHAR *)pStringData, _driverName,
  385. pAddCacheData->DriverLen/sizeof(WCHAR)
  386. ) == ERROR_SUCCESS);
  387. }
  388. else {
  389. TRC_ERR((TB, _T("Alloc failed.")));
  390. valid = FALSE;
  391. }
  392. #endif
  393. pStringData += pAddCacheData->DriverLen;
  394. }
  395. //
  396. // Our cache contains printer after driver name
  397. //
  398. if (valid) {
  399. pStringData += pAddCacheData->PrinterNameLen;
  400. }
  401. //
  402. // Need to adjust the cached pointer to point to the actual cached
  403. // configuration data.
  404. //
  405. if (valid) {
  406. PVOID oldCachedData;
  407. oldCachedData = _cachedData;
  408. #ifdef OS_WINCE
  409. if (pAddCacheData->CachedFieldsLen > 0) {
  410. #endif
  411. _cachedData = new BYTE[pAddCacheData->CachedFieldsLen];
  412. if (_cachedData != NULL) {
  413. memcpy((PBYTE)_cachedData, pStringData, pAddCacheData->CachedFieldsLen);
  414. _cachedDataSize = pAddCacheData->CachedFieldsLen;
  415. }
  416. else {
  417. TRC_NRM((TB, _T("Can't allocate %ld bytes."), pAddCacheData->CachedFieldsLen));
  418. _cachedDataSize = 0;
  419. valid = FALSE;
  420. }
  421. #ifdef OS_WINCE
  422. }
  423. else {
  424. _cachedData = NULL;
  425. _cachedDataSize = 0;
  426. }
  427. if (oldCachedData)
  428. #endif
  429. delete oldCachedData;
  430. }
  431. DC_END_FN();
  432. return valid;
  433. }