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.

632 lines
18 KiB

  1. //Copyright (c) 1998 - 1999 Microsoft Corporation
  2. /*++
  3. Module Name:
  4. rdpdrstp
  5. Abstract:
  6. This module implements Terminal Server RDPDR device redirector
  7. setup functions in C for user-mode NT.
  8. Environment:
  9. User mode
  10. Author:
  11. Tadb
  12. --*/
  13. // Toggle stand-alone testing.
  14. //#define UNITTEST 1
  15. #include "stdafx.h"
  16. #ifdef UNITTEST
  17. #include <windows.h>
  18. #include <tchar.h>
  19. #include <time.h>
  20. #include <stdio.h>
  21. #include <setupapi.h>
  22. #include <prsht.h>
  23. #include "objbase.h" // for CoInitialize()
  24. #endif
  25. #include <devguid.h>
  26. #include <cfgmgr32.h>
  27. #include <winspool.h>
  28. #include <rdpdrstp.h>
  29. #include "newdev.h"
  30. #define SIZECHARS(x) (sizeof((x))/sizeof(*x))
  31. //#define USBMON_DLL TEXT("USBMON.DLL")
  32. //#define USB_MON_NAME TEXT("USB Monitor")
  33. #ifndef UNITTEST
  34. #include "logmsg.h"
  35. #endif
  36. #ifdef UNITTEST
  37. #define LOGMESSAGE1(arg1, arg2) ;
  38. #define LOGMESSAGE0(arg1) ;
  39. #endif
  40. ////////////////////////////////////////////////////////////
  41. //
  42. // Internal Types
  43. //
  44. typedef BOOL (InstallDevInstFuncType)(
  45. HWND hwndParent, LPCWSTR DeviceInstanceId,
  46. BOOL UpdateDriver,
  47. PDWORD pReboot,
  48. BOOL silentInstall
  49. );
  50. BOOL RDPDRINST_GUIModeSetupInstall(
  51. IN HWND hwndParent,
  52. IN WCHAR *pPNPID,
  53. IN TCHAR *pDeviceID
  54. )
  55. /*++
  56. Routine Description:
  57. This is the single entry point for RDPDR (Terminal Server Device Redirector)
  58. GUI-mode setup install routine.
  59. It currently simply creates and installs a dev node for RDPDR to interact with
  60. PnP.
  61. Arguments:
  62. hwndParent Handle to parent window for GUI required by this function.
  63. Return Value:
  64. TRUE on success. FALSE, otherwise.
  65. --*/
  66. {
  67. HDEVINFO devInfoSet;
  68. SP_DEVINFO_DATA deviceInfoData;
  69. WCHAR pnpID[256];
  70. DWORD len;
  71. WCHAR devInstanceID[MAX_PATH];
  72. InstallDevInstFuncType *pInstallDevInst;
  73. HINSTANCE hndl = NULL;
  74. //MONITOR_INFO_2 mi;
  75. //mi.pDLLName = USBMON_DLL;
  76. //mi.pEnvironment = NULL;
  77. //mi.pName = USB_MON_NAME;
  78. // Add the USB port monitor
  79. //if (!AddMonitor(NULL, 2, (PBYTE)&mi)) {
  80. // if (GetLastError() != ERROR_PRINT_MONITOR_ALREADY_INSTALLED) {
  81. // LOGMESSAGE1(_T("AddMonitor failed. Error code: %ld."), GetLastError());
  82. // return FALSE;
  83. // }
  84. //}
  85. //
  86. // Create the device info list.
  87. //
  88. devInfoSet = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_SYSTEM, hwndParent);
  89. if (devInfoSet == INVALID_HANDLE_VALUE) {
  90. LOGMESSAGE1(_T("Error creating device info list. Error code: %ld."),
  91. GetLastError());
  92. return FALSE;
  93. }
  94. //
  95. // Create the dev node.
  96. //
  97. ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
  98. deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  99. if (!SetupDiCreateDeviceInfo(devInfoSet,
  100. pDeviceID,
  101. &GUID_DEVCLASS_SYSTEM,
  102. NULL,
  103. hwndParent,
  104. 0L, // No flags.
  105. &deviceInfoData
  106. ))
  107. {
  108. // If it already exists, then we are done ... because this was an
  109. // upgrade.
  110. if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS)
  111. {
  112. SetupDiDestroyDeviceInfoList(devInfoSet);
  113. return TRUE;
  114. }
  115. else {
  116. LOGMESSAGE1(_T("Error creating device node. Error code: %ld."),
  117. GetLastError());
  118. SetupDiDestroyDeviceInfoList(devInfoSet);
  119. return FALSE;
  120. }
  121. }
  122. else if (!SetupDiSetSelectedDevice(devInfoSet, &deviceInfoData)) {
  123. LOGMESSAGE1(_T("Error selecting device node. Error code: %ld."),
  124. GetLastError());
  125. goto WhackTheDevNodeAndReturnError;
  126. }
  127. //
  128. // Add the RDPDR PnP ID.
  129. //
  130. // Create the PnP ID string.
  131. wcscpy(pnpID, pPNPID);
  132. len = wcslen(pnpID);
  133. // This is a multi_sz string, so we need to terminate with an extra null.
  134. pnpID[len+1] = 0;
  135. // Add it to the registry entry for the dev node.
  136. if (!SetupDiSetDeviceRegistryProperty(
  137. devInfoSet, &deviceInfoData,
  138. SPDRP_HARDWAREID, (CONST BYTE *)pnpID,
  139. (len + 2) * sizeof(WCHAR))) {
  140. LOGMESSAGE1(_T("Error setting device registry property. Error code: %ld."),
  141. GetLastError());
  142. goto WhackTheDevNodeAndReturnError;
  143. }
  144. //
  145. // Register the, as of yet, phantom dev node with PnP to turn it into a real
  146. // dev node.
  147. //
  148. if (!SetupDiRegisterDeviceInfo(devInfoSet, &deviceInfoData, 0, NULL,
  149. NULL, NULL)) {
  150. LOGMESSAGE1(_T("Error registering device node with PnP. Error code: %ld."),
  151. GetLastError());
  152. goto WhackTheDevNodeAndReturnError;
  153. }
  154. //
  155. // Get the device instance ID.
  156. //
  157. if (!SetupDiGetDeviceInstanceIdW(devInfoSet, &deviceInfoData, devInstanceID,
  158. SIZECHARS(devInstanceID), NULL)) {
  159. LOGMESSAGE1(_T("Error getting the device instance id. Error code: %ld."),
  160. GetLastError());
  161. goto WhackTheDevNodeAndReturnError;
  162. }
  163. //
  164. // Use newdev.dll to install RDPDR as the driver for this new dev node.
  165. //
  166. hndl = LoadLibrary(TEXT("newdev.dll"));
  167. if (hndl == NULL) {
  168. LOGMESSAGE1(_T("Error loading newdev.dll. Error code: %ld."),
  169. GetLastError());
  170. goto WhackTheDevNodeAndReturnError;
  171. }
  172. pInstallDevInst = (InstallDevInstFuncType *)GetProcAddress(hndl, "InstallDevInstEx");
  173. if (pInstallDevInst == NULL) {
  174. LOGMESSAGE1(_T("Error fetching InstallDevInst func. Error code: %ld."),
  175. GetLastError());
  176. goto WhackTheDevNodeAndReturnError;
  177. }
  178. DWORD dwReboot;
  179. if ((*pInstallDevInst)(hwndParent, devInstanceID, FALSE, &dwReboot, TRUE)) {
  180. // Clean up and return success!
  181. SetupDiDestroyDeviceInfoList(devInfoSet);
  182. FreeLibrary(hndl);
  183. return TRUE;
  184. }
  185. else {
  186. LOGMESSAGE1(_T("Error in newdev install. Error code: %ld."),
  187. GetLastError());
  188. }
  189. //
  190. // Whack the dev node and return failure.
  191. //
  192. WhackTheDevNodeAndReturnError:
  193. SetupDiCallClassInstaller(DIF_REMOVE, devInfoSet, &deviceInfoData);
  194. SetupDiDestroyDeviceInfoList(devInfoSet);
  195. if (hndl != NULL) {
  196. FreeLibrary(hndl);
  197. }
  198. return FALSE;
  199. }
  200. BOOL RDPDRINST_GUIModeSetupUninstall(HWND hwndParent, WCHAR *pPNPID, GUID *pGuid)
  201. /*++
  202. Routine Description:
  203. This is the single entry point for RDPDR (Terminal Server Device Redirector)
  204. GUI-mode setup uninstall routine.
  205. It currently simply remove the dev node created so that RDPDR can interact
  206. with PnP.
  207. Arguments:
  208. hwndParent Handle to parent window for GUI required by this function.
  209. Return Value:
  210. TRUE on success. FALSE, otherwise.
  211. --*/
  212. {
  213. HDEVINFO devInfoSet;
  214. SP_DEVINFO_DATA deviceInfoData;
  215. DWORD iLoop;
  216. BOOL bMoreDevices;
  217. WCHAR pnpID[256];
  218. BOOL result;
  219. //
  220. // Get the set of all devices with the RDPDR PnP ID.
  221. //
  222. devInfoSet = SetupDiGetClassDevs(pGuid, NULL, hwndParent,
  223. DIGCF_PRESENT);
  224. if (devInfoSet == INVALID_HANDLE_VALUE) {
  225. LOGMESSAGE1(_T("Error getting RDPDR devices from PnP. Error code: %ld."),
  226. GetLastError());
  227. return FALSE;
  228. }
  229. // Assume that we will be successful.
  230. result = TRUE;
  231. // Get the first device.
  232. iLoop=0;
  233. deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  234. bMoreDevices=SetupDiEnumDeviceInfo(devInfoSet, iLoop, &deviceInfoData);
  235. // Get the details for all matching device interfaces.
  236. while (bMoreDevices)
  237. {
  238. // Get the PnP ID for the device.
  239. if (!SetupDiGetDeviceRegistryProperty(devInfoSet, &deviceInfoData,
  240. SPDRP_HARDWAREID, NULL, (BYTE *)pnpID,
  241. sizeof(pnpID), NULL)) {
  242. LOGMESSAGE1(_T("Error fetching PnP ID in RDPDR device node remove. Error code: %ld."),
  243. GetLastError());
  244. }
  245. // If the current device matches RDPDR, then remove it.
  246. else if (!wcscmp(pnpID, pPNPID))
  247. {
  248. if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfoSet, &deviceInfoData)) {
  249. // If we failed here, set the return status to indicate failure, but
  250. // don't give up on any other RDPDR dev nodes.
  251. LOGMESSAGE1(_T("Error removing RDPDR device node. Error code: %ld."),
  252. GetLastError());
  253. result = FALSE;
  254. }
  255. }
  256. // Get the next one device interface.
  257. bMoreDevices=SetupDiEnumDeviceInfo(devInfoSet, ++iLoop, &deviceInfoData);
  258. }
  259. // Release the device info list.
  260. SetupDiDestroyDeviceInfoList(devInfoSet);
  261. return result;
  262. }
  263. ULONG RDPDRINST_DetectInstall()
  264. /*++
  265. Routine Description:
  266. Return the number of RDPDR.SYS devices found.
  267. Arguments:
  268. NA
  269. Return Value:
  270. TRUE on success. FALSE, otherwise.
  271. --*/
  272. {
  273. HDEVINFO devInfoSet;
  274. SP_DEVINFO_DATA deviceInfoData;
  275. DWORD iLoop;
  276. BOOL bMoreDevices;
  277. ULONG count;
  278. TCHAR pnpID[256];
  279. GUID *pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
  280. //
  281. // Get the set of all devices with the RDPDR PnP ID.
  282. //
  283. devInfoSet = SetupDiGetClassDevs(pGuid, NULL, NULL,
  284. DIGCF_PRESENT);
  285. if (devInfoSet == INVALID_HANDLE_VALUE) {
  286. LOGMESSAGE1(_T("ERRORgetting RDPDRINST_DetectInstall:RDPDR devices from PnP. Error code: %ld."),
  287. GetLastError());
  288. return 0;
  289. }
  290. // Get the first device.
  291. iLoop=0;
  292. deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  293. bMoreDevices=SetupDiEnumDeviceInfo(devInfoSet, iLoop, &deviceInfoData);
  294. // Get the details for all matching device interfaces.
  295. count = 0;
  296. while (bMoreDevices)
  297. {
  298. // Get the PnP ID for the device.
  299. if (!SetupDiGetDeviceRegistryProperty(devInfoSet, &deviceInfoData,
  300. SPDRP_HARDWAREID, NULL, (BYTE *)pnpID,
  301. sizeof(pnpID), NULL)) {
  302. LOGMESSAGE1(_T("ERROR:fetching PnP ID in RDPDR device node remove. Error code: %ld."),
  303. GetLastError());
  304. }
  305. // If the current device matches the RDPDR PNP ID
  306. if (!_tcscmp(pnpID, TRDPDRPNPID)) {
  307. count++;
  308. }
  309. // Get the next one device interface.
  310. bMoreDevices=SetupDiEnumDeviceInfo(devInfoSet, ++iLoop, &deviceInfoData);
  311. }
  312. // Release the device info list.
  313. SetupDiDestroyDeviceInfoList(devInfoSet);
  314. return count;
  315. }
  316. BOOL IsRDPDrInstalled ()
  317. {
  318. ULONG ulReturn;
  319. LOGMESSAGE0(_T("Entered IsRDPDrInstalled"));
  320. ulReturn = RDPDRINST_DetectInstall();
  321. LOGMESSAGE1(_T("Returning IsRDPDrInstalled (ulReturn = %d)"), ulReturn);
  322. return 0 != ulReturn;
  323. }
  324. //
  325. // Unit-Test
  326. //
  327. #ifdef UNITTEST
  328. void __cdecl main()
  329. {
  330. RDPDRINST_GUIModeSetupInstall(NULL);
  331. RDPDRINST_GUIModeSetupUninstall(NULL);
  332. }
  333. #endif
  334. #ifdef TSOC_CONSOLE_SHADOWING
  335. //
  336. // Need to instantiate the device class GUIDs so we can use the "Net" class
  337. // GUID below...
  338. //
  339. /*
  340. DWORD
  341. InstallRootEnumeratedDevice(
  342. IN HWND hwndParent,
  343. IN PCTSTR DeviceName,
  344. IN PCTSTR HardwareIdList,
  345. IN PCTSTR FullInfPath,
  346. OUT PBOOL RebootRequired OPTIONAL
  347. )
  348. */
  349. /*++
  350. Routine Description:
  351. This routine creates and installs a new, root-enumerated devnode
  352. representing a network adapter.
  353. Arguments:
  354. hwndParent - Supplies the window handle to be used as the parent of any
  355. UI that is generated as a result of this device's installation.
  356. DeviceName - Supplies the full name of the devnode to be created (e.g.,
  357. "Root\VMWARE\0000"). Note that if this devnode already exists, the API
  358. will fail.
  359. HardwareIdList - Supplies a multi-sz list containing one or more hardware
  360. IDs to be associated with the device. These are necessary in order to
  361. match up with an INF driver node when we go to do the device
  362. installation.
  363. FullInfPath - Supplies the full path to the INF to be used when installing
  364. this device.
  365. RebootRequired - Optionally, supplies the address of a boolean that is set,
  366. upon successful return, to indicate whether or not a reboot is required
  367. to bring the newly-installed device on-line.
  368. Return Value:
  369. If the function succeeds, the return value is NO_ERROR.
  370. If the function fails, the return value is a Win32 error code indicating
  371. the cause of the failure.
  372. --*/
  373. /*
  374. {
  375. HDEVINFO DeviceInfoSet;
  376. SP_DEVINFO_DATA DeviceInfoData;
  377. DWORD HardwareIdListSize, CurIdSize;
  378. PCTSTR p;
  379. DWORD Err;
  380. //
  381. // Create the container for the to-be-created device information element.
  382. //
  383. DeviceInfoSet = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, hwndParent);
  384. if (DeviceInfoSet == INVALID_HANDLE_VALUE)
  385. {
  386. LOGMESSAGE1(_T("SetupDiCreateDeviceInfoList failed. LastError = %ld"), GetLastError());
  387. return GetLastError();
  388. }
  389. //
  390. // Now create the element.
  391. //
  392. // ** Note that if the desire is to always have a unique devnode be created
  393. // (i.e., have an auto-generated name), then the caller would need to pass
  394. // in just the device part of the name (i.e., just the middle part of
  395. // "Root\<DeviceId>\<UniqueInstanceId>"). In that case, we'd need to pass
  396. // the DICD_GENERATE_ID flag in the next-to-last argument of the call below.
  397. //
  398. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  399. if (!SetupDiCreateDeviceInfo(DeviceInfoSet,
  400. DeviceName,
  401. &GUID_DEVCLASS_DISPLAY,
  402. NULL,
  403. hwndParent,
  404. 0,
  405. &DeviceInfoData))
  406. {
  407. LOGMESSAGE1(_T("SetupDiCreateDeviceInfo failed. LastError = %ld"), GetLastError());
  408. Err = GetLastError();
  409. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  410. return Err;
  411. }
  412. //
  413. // Now compute the size of the hardware ID list we're going to associate
  414. // with the device.
  415. //
  416. HardwareIdListSize = 1; // initialize to 1 for extra null terminating char
  417. for(p = HardwareIdList; *p; p += CurIdSize)
  418. {
  419. CurIdSize = lstrlen(p) + 1;
  420. HardwareIdListSize += CurIdSize;
  421. }
  422. //
  423. // (Need size in bytes, not characters, for call below.)
  424. //
  425. HardwareIdListSize *= sizeof(TCHAR);
  426. //
  427. // Store the hardware ID list to the device's HardwareID property.
  428. //
  429. if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  430. &DeviceInfoData,
  431. SPDRP_HARDWAREID,
  432. (LPBYTE)HardwareIdList,
  433. HardwareIdListSize))
  434. {
  435. LOGMESSAGE1(_T("SetupDiSetDeviceRegistryProperty failed. LastError = %ld"), GetLastError());
  436. Err = GetLastError();
  437. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  438. return Err;
  439. }
  440. //
  441. // OK, now we can register our device information element. This transforms
  442. // the element from a mere registry presence into an actual devnode in the
  443. // PnP hardware tree.
  444. //
  445. if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
  446. DeviceInfoSet,
  447. &DeviceInfoData))
  448. {
  449. LOGMESSAGE1(_T("SetupDiCallClassInstaller failed. LastError = %ld"), GetLastError());
  450. Err = GetLastError();
  451. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  452. return Err;
  453. }
  454. //
  455. // OK, the device information element has now been registered. From here
  456. // on, if we encounter any failure we'll also need to explicitly remove
  457. // this device from the system before bailing.
  458. //
  459. //
  460. // Now we're ready to install the device. (We need to initialize the
  461. // caller-supplied "RebootRequired" buffer to zero, because the call below
  462. // simply ORs in reboot-needed flags, as it performs device installations
  463. // that require reboot.)
  464. //
  465. if(RebootRequired)
  466. {
  467. *RebootRequired = FALSE;
  468. }
  469. if (!UpdateDriverForPlugAndPlayDevices(hwndParent,
  470. HardwareIdList, // use the first ID
  471. FullInfPath,
  472. INSTALLFLAG_FORCE,
  473. RebootRequired))
  474. {
  475. Err = GetLastError();
  476. LOGMESSAGE1(_T("UpdateDriverForPlugAndPlayDevices failed. LastError = %ld"), GetLastError());
  477. if(Err == NO_ERROR)
  478. {
  479. //
  480. // The only time we should get NO_ERROR here is when
  481. // UpdateDriverForPlugAndPlayDevices didn't find anything to do.
  482. // That should never be the case here. However, since something
  483. // obviously went awry, go ahead and force some error, so the
  484. // caller knows things didn't work out.
  485. //
  486. Err = ERROR_NO_SUCH_DEVINST;
  487. }
  488. SetupDiCallClassInstaller(DIF_REMOVE,
  489. DeviceInfoSet,
  490. &DeviceInfoData
  491. );
  492. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  493. return Err;
  494. }
  495. //
  496. // We're done! We successfully installed the device.
  497. //
  498. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  499. return NO_ERROR;
  500. }
  501. */
  502. #endif// TSOC_CONSOLE_SHADOWING