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.

554 lines
11 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. InstDev.cpp
  5. Abstract:
  6. Routines for installing a device by programatically playing with
  7. the add driver wizard
  8. Author:
  9. Hakki T. Bostanci (hakkib) 17-Dec-1999
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #include "Wrappers.h"
  14. #include "WindowSearch.h"
  15. #include "StolenIds.h"
  16. //////////////////////////////////////////////////////////////////////////
  17. //
  18. // structs for manipulating resources in NE (Win 3.1 style exe) files
  19. //
  20. #include <pshpack1.h> // Assume byte packing throughout
  21. typedef struct
  22. {
  23. WORD Type;
  24. WORD NumEntries;
  25. DWORD Reserved;
  26. } RES_TYPE_INFO, *PRES_TYPE_INFO;
  27. typedef struct
  28. {
  29. WORD Offset;
  30. WORD Length;
  31. WORD Flags;
  32. WORD Id;
  33. WORD Handle;
  34. WORD Usage;
  35. } RES_NAME_INFO, *PRES_NAME_INFO;
  36. typedef struct
  37. {
  38. WORD Align;
  39. RES_TYPE_INFO TypeInfo[ANYSIZE_ARRAY];
  40. } RES_TABLE, *PRES_TABLE;
  41. #include <poppack.h>
  42. //////////////////////////////////////////////////////////////////////////
  43. //
  44. // IsEqualId
  45. //
  46. // Routine Description:
  47. // compares two resource id's
  48. //
  49. // Arguments:
  50. //
  51. // Return Value:
  52. //
  53. BOOL
  54. IsEqualId(
  55. PCTSTR pResName,
  56. WORD wResId,
  57. PRES_TABLE pResTable
  58. )
  59. {
  60. if (HIWORD(pResName) == 0)
  61. {
  62. // pResName is numerical
  63. return wResId == ((WORD) pResName | 0x8000);
  64. }
  65. if (pResName[0] == _T('#'))
  66. {
  67. // pResName is a string numerical
  68. return wResId == (_ttoi(pResName + 1) | 0x8000);
  69. }
  70. if (wResId & 0x8000)
  71. {
  72. // pResName is a string but wResId is numerical
  73. return FALSE;
  74. }
  75. // compare the pascal-style string in the resource table
  76. // with the C-style string we have
  77. PSTR pStr = (PSTR) ((PBYTE) pResTable + wResId);
  78. int nStrLen = *pStr++;
  79. if (pResName[nStrLen] != 0)
  80. {
  81. // string lengths do not match
  82. return FALSE;
  83. }
  84. int i = 0;
  85. while (i < nStrLen && tolower(pStr[i]) == tolower(pResName[i]))
  86. {
  87. ++i;
  88. }
  89. return i == nStrLen;
  90. }
  91. //////////////////////////////////////////////////////////////////////////
  92. //
  93. // FindResource16
  94. //
  95. // Routine Description:
  96. // finds a resource in a 16-bit NE format file
  97. //
  98. // Arguments:
  99. //
  100. // Return Value:
  101. //
  102. PVOID
  103. FindResource16(
  104. PVOID pImageBase,
  105. PCTSTR pName,
  106. PCTSTR pType
  107. )
  108. {
  109. // locate the dos header
  110. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) pImageBase;
  111. if (pDosHeader == 0 || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  112. {
  113. SetLastError(ERROR_BAD_FORMAT);
  114. return 0;
  115. }
  116. // locate the NE header
  117. PIMAGE_OS2_HEADER pOs2Header =
  118. (PIMAGE_OS2_HEADER) ((PBYTE)pDosHeader + pDosHeader->e_lfanew);
  119. if (pOs2Header->ne_magic != IMAGE_OS2_SIGNATURE)
  120. {
  121. SetLastError(ERROR_BAD_FORMAT);
  122. return 0;
  123. }
  124. // locate the resources table
  125. PRES_TABLE pResTable =
  126. (PRES_TABLE) ((PBYTE)pOs2Header + pOs2Header->ne_rsrctab);
  127. // go through the resources until we reach to the string table
  128. PRES_TYPE_INFO pTypeInfo = pResTable->TypeInfo;
  129. while (
  130. pTypeInfo->Type != 0 &&
  131. !IsEqualId(pType, pTypeInfo->Type, pResTable)
  132. )
  133. {
  134. pTypeInfo = (PRES_TYPE_INFO)
  135. ((PRES_NAME_INFO) (pTypeInfo + 1) + pTypeInfo->NumEntries);
  136. }
  137. if (pTypeInfo->Type == 0)
  138. {
  139. SetLastError(ERROR_NOT_FOUND);
  140. return 0;
  141. }
  142. // go through the resource table searching for our resource id
  143. PRES_NAME_INFO pNameInfo = (PRES_NAME_INFO) (pTypeInfo + 1);
  144. WORD nResource = 0;
  145. while (
  146. nResource < pTypeInfo->NumEntries &&
  147. !IsEqualId(pName, pNameInfo->Id, pResTable)
  148. )
  149. {
  150. ++nResource;
  151. ++pNameInfo;
  152. }
  153. if (nResource == pTypeInfo->NumEntries)
  154. {
  155. SetLastError(ERROR_NOT_FOUND);
  156. return 0;
  157. }
  158. // return the offset of the resource
  159. return (PBYTE) pDosHeader + (pNameInfo->Offset << pResTable->Align);
  160. }
  161. //////////////////////////////////////////////////////////////////////////
  162. //
  163. // LoadString16
  164. //
  165. // Routine Description:
  166. // loads a string resource from a 16-bit NE format file
  167. //
  168. // Arguments:
  169. //
  170. // Return Value:
  171. //
  172. int
  173. LoadString16(
  174. PVOID pImageBase,
  175. UINT uID,
  176. PTSTR pBuffer,
  177. int nBufferMax
  178. )
  179. {
  180. ASSERT(pBuffer != 0);
  181. // get the resource id and the index of the string
  182. WORD nBlockId = uID / 16 + 1;
  183. int nStrIndex = uID % 16;
  184. PSTR pszStr = (PSTR) FindResource16(
  185. pImageBase,
  186. MAKEINTRESOURCE(nBlockId),
  187. RT_STRING
  188. );
  189. if (pszStr == 0)
  190. {
  191. return 0;
  192. }
  193. // go through the string resource until we find our string index
  194. for (int nStr = 0; nStr < 16; ++nStr)
  195. {
  196. int nStrLen = *pszStr++;
  197. if (nStr == nStrIndex)
  198. {
  199. int nCopied = min(nBufferMax - 1, nStrLen);
  200. #ifdef UNICODE
  201. MultiByteToWideChar(CP_ACP, 0, pszStr, nCopied, pBuffer, nBufferMax);
  202. #else //UNICODE
  203. strncpy(pBuffer, pszStr, nCopied);
  204. #endif //UNICODE
  205. pBuffer[nCopied] = _T('\0');
  206. return nCopied;
  207. }
  208. pszStr += nStrLen;
  209. }
  210. // we cannot reach here but still...
  211. SetLastError(ERROR_NOT_FOUND);
  212. return 0;
  213. }
  214. //////////////////////////////////////////////////////////////////////////
  215. //
  216. //
  217. //
  218. BOOL CALLBACK EnumProcCancel(HWND hWnd, LPARAM /*lParam*/)
  219. {
  220. SendMessage(hWnd, WM_COMMAND, IDCANCEL, 0);
  221. return TRUE;
  222. }
  223. //////////////////////////////////////////////////////////////////////////
  224. //
  225. // InstallImageDeviceFromInf
  226. //
  227. // Routine Description:
  228. // installs an imaging device from an inf file
  229. //
  230. // Arguments:
  231. //
  232. // Return Value:
  233. //
  234. BOOL
  235. InstallImageDeviceFromInf(
  236. PCTSTR pInfFileName,
  237. PCTSTR pDeviceName /*= 0*/
  238. )
  239. {
  240. static TCHAR szWizardTitle[256];
  241. static TCHAR szOemDiskTitle[256];
  242. static LONG bInitStrings = TRUE;
  243. // read localizable strings
  244. if (bInitStrings)
  245. {
  246. CSystemDirectory SystemDirectory;
  247. SystemDirectory.SetFileName(_T("sti_ci.dll"));
  248. CMapFile<VOID, FILE_MAP_READ> sti_ci_dll(SystemDirectory);
  249. LoadString16(
  250. sti_ci_dll,
  251. MessageTitle,
  252. szWizardTitle,
  253. COUNTOF(szWizardTitle)
  254. );
  255. SystemDirectory.SetFileName(_T("setupx.dll"));
  256. CMapFile<VOID, FILE_MAP_READ> setupx_dll(SystemDirectory);
  257. LoadString16(
  258. setupx_dll,
  259. IDS_OEMTITLE,
  260. szOemDiskTitle,
  261. COUNTOF(szOemDiskTitle)
  262. );
  263. InterlockedExchange(&bInitStrings, FALSE);
  264. }
  265. #if 0
  266. // for the general case, read class name from the inf
  267. // (but the UI steps in this procedure are specific to image class
  268. // installs anyway, so don't bother...)
  269. GUID ClassGuid;
  270. TCHAR ClassName[MAX_CLASS_NAME_LEN];
  271. CHECK(SetupDiGetINFClass(
  272. pInfFileName,
  273. &ClassGuid,
  274. ClassName,
  275. MAX_CLASS_NAME_LEN,
  276. 0
  277. ));
  278. TCHAR szRunDevManager[256];
  279. _stprintf(
  280. szRunDevManager,
  281. _T("rundll sysdm.cpl,InstallDevice_RunDLL %s,,"),
  282. ClassName
  283. );
  284. #endif
  285. // enter a system wide "playing with device manager" critical section
  286. // (for the unlikely case that two or more WIAStress'es are running)
  287. Mutex DevManagerMutex(FALSE, _T("5AFD932E-AC4B-11d3-97B6-00C04F797DBB"));
  288. DevManagerMutex.WaitForSingleObject();
  289. // give the installation 2 minutes to be complete. If it is not complete
  290. // within this period, then probably there is some error dialog (that
  291. // we are not expecting) waiting for us. bugbug: this is a terrible
  292. // way for error handling...
  293. CWaitableTimer TimeOut(TRUE);
  294. TimeOut.Set(-1i64 * 2 * 60 * 1000 * 1000 * 10);
  295. // launch the add driver wizard
  296. CProcess DevManager(_T("rundll sysdm.cpl,InstallDevice_RunDLL Image,,"));
  297. DWORD dwThreadId = ((PROCESS_INFORMATION &)DevManager).dwThreadId;
  298. // find the wizard window
  299. HWND hWizardWnd = WaitForThreadWindow(
  300. dwThreadId,
  301. CWindowSearchByText(szWizardTitle),
  302. TimeOut
  303. );
  304. // find the "next" button
  305. HWND hNext = WaitForChildWindow(
  306. hWizardWnd,
  307. CWindowSearchById(IDD_NEXT),
  308. TimeOut
  309. );
  310. PushButton(hNext);
  311. // find the "have disk" button
  312. HWND hHaveDisk = WaitForChildWindow(
  313. hWizardWnd,
  314. CWindowSearchById(IDC_NDW_PICKDEV_HAVEDISK),
  315. TimeOut
  316. );
  317. PushButton(hHaveDisk);
  318. // wait for the oem disk selection dialog
  319. HWND hOemDiskWnd = WaitForThreadWindow(
  320. dwThreadId,
  321. CWindowSearchByText(szOemDiskTitle),
  322. TimeOut
  323. );
  324. // enter the directory name for the inf
  325. HWND hDirName = WaitForChildWindow(
  326. hOemDiskWnd,
  327. CWindowSearchByClass(_T("Edit")),
  328. TimeOut
  329. );
  330. CFullPathName InfPathName(pInfFileName);
  331. InfPathName.StripFileName();
  332. SetText(hDirName, InfPathName);
  333. // press ok's and next's and finish'es until the device is installed
  334. HWND hOk = WaitForChildWindow(
  335. hOemDiskWnd,
  336. CWindowSearchById(IDOK),
  337. TimeOut
  338. );
  339. PushButton(hOk);
  340. PushButton(hNext);
  341. PushButton(hNext);
  342. // if we have a name, rename the device
  343. if (pDeviceName)
  344. {
  345. HWND hDeviceName = WaitForChildWindow(
  346. hWizardWnd,
  347. CWindowSearchById(DeviceFriendlyName),
  348. TimeOut
  349. );
  350. SetText(hDeviceName, pDeviceName);
  351. }
  352. PushButton(hNext);
  353. HWND hFinish = WaitForChildWindow(
  354. hWizardWnd,
  355. CWindowSearchById(IDD_FINISH),
  356. TimeOut
  357. );
  358. PushButton(hFinish);
  359. while (DevManager.WaitForSingleObject(250) == WAIT_TIMEOUT)
  360. {
  361. // if time is up, destroy all windows
  362. if (TimeOut.IsSignaled())
  363. {
  364. EnumThreadWindows(dwThreadId, EnumProcCancel, 0);
  365. }
  366. }
  367. DevManagerMutex.Release();
  368. if (TimeOut.IsSignaled())
  369. {
  370. SetLastError(ERROR_INSTALL_FAILURE);
  371. return FALSE;
  372. }
  373. return TRUE;
  374. }
  375. //////////////////////////////////////////////////////////////////////////
  376. //
  377. // InstallDeviceFromInf
  378. //
  379. // Routine Description:
  380. //
  381. // Arguments:
  382. //
  383. // Return Value:
  384. //
  385. BOOL
  386. InstallDeviceFromInf(
  387. PCTSTR pInfFileName,
  388. PCTSTR pDeviceName,
  389. PCTSTR pSourceRootPath = 0
  390. )
  391. {
  392. BOOL bResult = FALSE;
  393. GUID ClassGuid;
  394. TCHAR ClassName[MAX_CLASS_NAME_LEN];
  395. bResult = SetupDiGetINFClass(
  396. pInfFileName,
  397. &ClassGuid,
  398. ClassName,
  399. MAX_CLASS_NAME_LEN,
  400. 0
  401. );
  402. HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&ClassGuid, 0);
  403. SP_DEVINFO_DATA DeviceInfoData;
  404. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  405. bResult = SetupDiCreateDeviceInfo(
  406. hDevInfo,
  407. pDeviceName,
  408. &ClassGuid,
  409. 0,
  410. 0,
  411. DICD_GENERATE_ID,
  412. &DeviceInfoData
  413. );
  414. bResult = SetupDiCallClassInstaller(
  415. DIF_INSTALLDEVICE,
  416. hDevInfo,
  417. &DeviceInfoData
  418. );
  419. return bResult;
  420. }