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.

490 lines
15 KiB

  1. //----------------------------------------------
  2. //
  3. // program to use setupapi.dll to install the DefaultInstall section of a install.inf file
  4. //
  5. //----------------------------------------------
  6. #include <tchar.h>
  7. #include <windows.h>
  8. #include <winbase.h>
  9. #include <shlobj.h>
  10. #include <io.h>
  11. #include <stdio.h>
  12. #include <setupapi.h>
  13. #include "resource.h"
  14. #include "advpub.h"
  15. #define MAX_BUFFER 1024
  16. typedef struct _QUEUECONTEXT {
  17. HWND OwnerWindow;
  18. DWORD MainThreadId;
  19. HWND ProgressDialog;
  20. HWND ProgressBar;
  21. BOOL Cancelled;
  22. PTSTR CurrentSourceName;
  23. BOOL ScreenReader;
  24. BOOL MessageBoxUp;
  25. WPARAM PendingUiType;
  26. PVOID PendingUiParameters;
  27. UINT CancelReturnCode;
  28. BOOL DialogKilled;
  29. //
  30. // If the SetupInitDefaultQueueCallbackEx is used, the caller can
  31. // specify an alternate handler for progress. This is useful to
  32. // get the default behavior for disk prompting, error handling, etc,
  33. // but to provide a gas gauge embedded, say, in a wizard page.
  34. //
  35. // The alternate window is sent ProgressMsg once when the copy queue
  36. // is started (wParam = 0. lParam = number of files to copy).
  37. // It is then also sent once per file copied (wParam = 1. lParam = 0).
  38. //
  39. // NOTE: a silent installation (i.e., no progress UI) can be accomplished
  40. // by specifying an AlternateProgressWindow handle of INVALID_HANDLE_VALUE.
  41. //
  42. HWND AlternateProgressWindow;
  43. UINT ProgressMsg;
  44. UINT NoToAllMask;
  45. HANDLE UiThreadHandle;
  46. #ifdef NOCANCEL_SUPPORT
  47. BOOL AllowCancel;
  48. #endif
  49. } QUEUECONTEXT, *PQUEUECONTEXT;
  50. /* ************************ prototypes ***************************** */
  51. LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
  52. void MakePath(LPSTR lpPath);
  53. void AddPath(LPSTR szPath, LPCSTR szName );
  54. void MyMessageBox(int WhichString_ID, char g_szFilepath[] = '\0');
  55. BOOL GetThisModulePath( LPSTR lpPath, int size );
  56. int InstallDefaultInfSection(void);
  57. int InstallDefaultInfSection2(void);
  58. HRESULT MyRunSetupCommand(HWND hwnd, LPCSTR lpszInfFile, LPCSTR lpszSection);
  59. /* ************************* globals ******************************* */
  60. HINSTANCE g_hInstance = NULL;
  61. HINSTANCE g_hPrevInstance = NULL;
  62. LPSTR g_lpCmdLine = NULL;
  63. int g_nCmdShow = 0;
  64. /* **************************************************************** */
  65. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  66. {
  67. HWND hwnd;
  68. MSG msg;
  69. WNDCLASS wcl;
  70. char szWinName[255];
  71. g_hInstance = hInstance;
  72. g_hPrevInstance = hPrevInstance;
  73. g_lpCmdLine = lpCmdLine;
  74. g_nCmdShow = nCmdShow;
  75. LoadString( g_hInstance, IDS_TITLE, szWinName, _MAX_PATH );
  76. // define windows class
  77. wcl.hInstance = hInstance;
  78. wcl.lpszClassName = szWinName;
  79. wcl.lpfnWndProc = WindowFunc;
  80. wcl.style = 0;
  81. wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  82. wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
  83. wcl.lpszMenuName = NULL;
  84. wcl.cbClsExtra = 0;
  85. wcl.cbWndExtra = 0;
  86. wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  87. // register the window class.
  88. if (!RegisterClass (&wcl)) return 0;
  89. hwnd = CreateWindow(szWinName, NULL, WS_DISABLED | WS_CHILD, CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, HWND_DESKTOP, NULL, hInstance , NULL);
  90. if (NULL != hwnd)
  91. {
  92. // display the window
  93. ShowWindow(hwnd, nCmdShow);
  94. // Install the inf section
  95. InstallDefaultInfSection();
  96. // Call PostQuit Message
  97. PostQuitMessage(0);
  98. while(GetMessage(&msg, NULL, 0, 0))
  99. {
  100. TranslateMessage(&msg);
  101. DispatchMessage(&msg);
  102. }
  103. }
  104. return (int)msg.wParam;
  105. }
  106. //***************************************************************************
  107. //*
  108. //* purpose: you know what
  109. //*
  110. //***************************************************************************
  111. LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  112. {
  113. switch(message)
  114. {
  115. case WM_CREATE:
  116. break;
  117. case WM_PAINT:
  118. break;
  119. case WM_DESTROY:
  120. PostQuitMessage(0);
  121. break;
  122. default:
  123. return DefWindowProc(hwnd,message,wParam, lParam);
  124. }
  125. return 0;
  126. }
  127. //***************************************************************************
  128. //*
  129. //* purpose: TRUE if the file is opened, FALSE if the file does not exists.
  130. //*
  131. //***************************************************************************
  132. int CheckIfFileExists(char * szFileName)
  133. {
  134. char svTemp1[_MAX_PATH];
  135. char *pdest;
  136. strcpy(svTemp1, szFileName);
  137. // cut off the trailing \ if need to
  138. pdest = svTemp1;
  139. if (*(pdest + (strlen(pdest) - 1)) == '\\')
  140. {*(strrchr(svTemp1, '\\')) = '\0';}
  141. if ((_access(svTemp1,0)) != -1)
  142. {return TRUE;}
  143. else
  144. {return FALSE;}
  145. }
  146. //***************************************************************************
  147. //*
  148. //* purpose: display message that we were unable to runthe exe
  149. //*
  150. //***************************************************************************
  151. void MyMessageBox(int WhichString_ID, char g_szFilepath[])
  152. {
  153. TCHAR TempString[_MAX_PATH];
  154. TCHAR TempString1[_MAX_PATH];
  155. TCHAR TempString2[_MAX_PATH];
  156. if(!LoadString(g_hInstance,IDS_ERROR,TempString1,sizeof(TempString1))) {*TempString1 = TEXT('\0');}
  157. if(!LoadString(g_hInstance,WhichString_ID,TempString2,sizeof(TempString2))) {*TempString2 = TEXT('\0');}
  158. strcpy(TempString, "Error");
  159. sprintf(TempString, TempString2, g_szFilepath);
  160. MessageBox(NULL, TempString, TempString1, MB_OK | MB_ICONSTOP);
  161. return;
  162. }
  163. int InstallDefaultInfSection2(void)
  164. {
  165. HWND Window = NULL;
  166. BOOL bError = TRUE; // assume failure.
  167. char szPath[_MAX_PATH];
  168. char szINFFilename_Full[_MAX_PATH];
  169. char szSectionName[_MAX_PATH];
  170. char szINFFilename[_MAX_PATH];
  171. if(!LoadString(NULL,IDS_SECTION_NAME,szSectionName,sizeof(szSectionName)))
  172. {strcpy(szSectionName, "DefaultInstall");}
  173. if(!LoadString(NULL,IDS_INF_FILENAME,szINFFilename,sizeof(szINFFilename)))
  174. {strcpy(szINFFilename, "install.inf");}
  175. // Get the path to setup.exe and strip off filename so we only have the path
  176. GetModuleFileName((HINSTANCE) Window, szPath, _MAX_PATH);
  177. *(strrchr(szPath, '\\') + 1) = '\0';
  178. strcpy(szINFFilename_Full, szPath);
  179. strcat(szINFFilename_Full, szINFFilename);
  180. // Check if the file exists
  181. if (CheckIfFileExists(szINFFilename_Full) == FALSE)
  182. {
  183. MyMessageBox(IDS_UNABLE_TO_FIND, szINFFilename_Full);
  184. }
  185. else
  186. {
  187. MyRunSetupCommand(NULL, szINFFilename_Full, szSectionName);
  188. }
  189. return TRUE;
  190. }
  191. //-------------------------------------------------------------------
  192. // purpose: install default inf section from install.inf file
  193. //-------------------------------------------------------------------
  194. int InstallDefaultInfSection(void)
  195. {
  196. HWND Window = NULL;
  197. PTSTR SourcePath = NULL;
  198. HINF InfHandle = INVALID_HANDLE_VALUE;
  199. HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
  200. PQUEUECONTEXT QueueContext = NULL;
  201. BOOL bReturn = FALSE;
  202. BOOL bError = TRUE; // assume failure.
  203. TCHAR ActualSection[1000];
  204. DWORD ActualSectionLength;
  205. char szSectionName[_MAX_PATH];
  206. char szINFFilename[_MAX_PATH];
  207. if(!LoadString(NULL,IDS_SECTION_NAME,szSectionName,sizeof(szSectionName)))
  208. {strcpy(szSectionName, "DefaultInstall");}
  209. if(!LoadString(NULL,IDS_INF_FILENAME,szINFFilename,sizeof(szINFFilename)))
  210. {strcpy(szINFFilename, "install.inf");}
  211. __try {
  212. // Get the path to setup.exe and strip off filename so we only have the path
  213. char szPath[_MAX_PATH];
  214. char szINFFilename_Full[_MAX_PATH];
  215. GetModuleFileName((HINSTANCE) Window, szPath, _MAX_PATH);
  216. *(strrchr(szPath, '\\') + 1) = '\0';
  217. strcpy(szINFFilename_Full, szPath);
  218. strcat(szINFFilename_Full, szINFFilename);
  219. SourcePath = szPath;
  220. *(strrchr(SourcePath, '\\') ) = '\0';
  221. // Check if the file exists
  222. if (CheckIfFileExists(szINFFilename_Full) == FALSE)
  223. {
  224. MyMessageBox(IDS_UNABLE_TO_FIND, szINFFilename_Full);
  225. goto c0;
  226. }
  227. //
  228. // Load the inf file and get the handle
  229. //
  230. InfHandle = SetupOpenInfFile(szINFFilename_Full, NULL, INF_STYLE_WIN4, NULL);
  231. if(InfHandle == INVALID_HANDLE_VALUE) {goto c1;}
  232. //
  233. // See if there is an nt-specific section
  234. //
  235. SetupDiGetActualSectionToInstall(InfHandle,szSectionName,ActualSection,sizeof(ActualSection),&ActualSectionLength,NULL);
  236. //
  237. // Create a setup file queue and initialize the default queue callback.
  238. //
  239. FileQueue = SetupOpenFileQueue();
  240. if(FileQueue == INVALID_HANDLE_VALUE) {goto c1;}
  241. //QueueContext = SetupInitDefaultQueueCallback(Window);
  242. //if(!QueueContext) {goto c1;}
  243. QueueContext = (PQUEUECONTEXT) SetupInitDefaultQueueCallbackEx(Window,NULL,0,0,0);
  244. if(!QueueContext) {goto c1;}
  245. QueueContext->PendingUiType = IDF_CHECKFIRST;
  246. //
  247. // Enqueue file operations for the section passed on the cmd line.
  248. //
  249. //SourcePath = NULL;
  250. bReturn = SetupInstallFilesFromInfSection(InfHandle,NULL,FileQueue,ActualSection,SourcePath,SP_COPY_NEWER);
  251. if(!bReturn) {goto c1;}
  252. //
  253. // Commit file queue.
  254. //
  255. if(!SetupCommitFileQueue(Window, FileQueue, SetupDefaultQueueCallback, QueueContext)) {goto c1;}
  256. //
  257. // Perform non-file operations for the section passed on the cmd line.
  258. //
  259. bReturn = SetupInstallFromInfSection(Window,InfHandle,ActualSection,SPINST_ALL & ~SPINST_FILES,NULL,NULL,0,NULL,NULL,NULL,NULL);
  260. if(!bReturn) {goto c1;}
  261. //
  262. // Refresh the desktop.
  263. //
  264. SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_FLUSHNOWAIT,0,0);
  265. //
  266. // If we get to here, then this routine has been successful.
  267. //
  268. bError = FALSE;
  269. c1:
  270. //
  271. // If the bError was because the user cancelled, then we don't want to consider
  272. // that as an bError (i.e., we don't want to give an bError popup later).
  273. //
  274. if(bError && (GetLastError() == ERROR_CANCELLED)) {bError = FALSE;}
  275. if(QueueContext) {SetupTermDefaultQueueCallback(QueueContext);QueueContext = NULL;}
  276. if(FileQueue != INVALID_HANDLE_VALUE) {SetupCloseFileQueue(FileQueue);FileQueue = INVALID_HANDLE_VALUE;}
  277. if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);InfHandle = INVALID_HANDLE_VALUE;}
  278. c0: ;
  279. } __except(EXCEPTION_EXECUTE_HANDLER)
  280. {
  281. if(QueueContext) {SetupTermDefaultQueueCallback(QueueContext);}
  282. if(FileQueue != INVALID_HANDLE_VALUE) {SetupCloseFileQueue(FileQueue);}
  283. if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);}
  284. }
  285. //
  286. // If the bError was because the user cancelled, then we don't want to consider
  287. // that as an bError (i.e., we don't want to give an bError popup later).
  288. //
  289. if(bError && (GetLastError() == ERROR_CANCELLED)) {bError = FALSE;}
  290. // Display installation failed message
  291. if(bError) {MyMessageBox(IDS_INF_FAILED);}
  292. return bError;
  293. }
  294. //***************************************************************************
  295. //*
  296. //* purpose: pass a particular section (from the .inf file) to the "RunSetupCommand" function
  297. //* in advpack.dll. depends upon if user wants to download another cpu/os
  298. //* than is own.
  299. //*
  300. //***************************************************************************
  301. HRESULT MyRunSetupCommand(HWND hwnd, LPCSTR lpszInfFile, LPCSTR lpszSection)
  302. {
  303. DWORD dwFlags;
  304. RUNSETUPCOMMAND fpRunSetupCommand;
  305. HRESULT hr = E_FAIL;
  306. char szTemp[MAX_BUFFER];
  307. HINSTANCE g_hAdvpack = NULL;
  308. char g_szSourceDir[MAX_PATH] = "";
  309. char szTmp[MAX_PATH];
  310. HRESULT g_hr = E_FAIL;
  311. BOOL bOleInited = FALSE ;
  312. if (SUCCEEDED(g_hr = CoInitialize(NULL)))
  313. {
  314. bOleInited = TRUE ;
  315. GetThisModulePath(g_szSourceDir, sizeof(g_szSourceDir));
  316. lstrcpy(szTmp, g_szSourceDir);
  317. AddPath(szTmp, "advpack.dll");
  318. lstrcpy(szTmp, "advpack.dll");
  319. g_hAdvpack = LoadLibrary( szTmp );
  320. if ( g_hAdvpack != NULL )
  321. {
  322. lstrcpy(szTemp, lpszSection);
  323. //dwFlags |= (RSC_FLAG_INF | RSC_FLAG_NGCONV);
  324. dwFlags = (RSC_FLAG_INF | RSC_FLAG_NGCONV);
  325. if (fpRunSetupCommand = (RUNSETUPCOMMAND)GetProcAddress(g_hAdvpack, achRUNSETUPCOMMANDFUNCTION))
  326. {
  327. hr = fpRunSetupCommand(hwnd, lpszInfFile, szTemp, g_szSourceDir, NULL, NULL, dwFlags, NULL);
  328. if (hr == S_OK){MessageBox(NULL, "", "Everything OK, no reboot needed.", MB_OK | MB_ICONSTOP);}
  329. if (hr == S_ASYNCHRONOUS){MessageBox(NULL, "", "Please wait on phEXE.", MB_OK | MB_ICONSTOP);}
  330. if (hr == ERROR_SUCCESS_REBOOT_REQUIRED){MessageBox(NULL, "", "Reboot required.", MB_OK | MB_ICONSTOP);}
  331. if (hr == E_INVALIDARG){MessageBox(NULL, "", "E_INVALIDARG", MB_OK | MB_ICONSTOP);}
  332. if (hr == E_UNEXPECTED){MessageBox(NULL, "", "E_UNEXPECTED", MB_OK | MB_ICONSTOP);}
  333. }
  334. }
  335. else
  336. {
  337. MyMessageBox(IDS_UNABLE_TO_FIND, szTmp);
  338. }
  339. }
  340. if (bOleInited) CoUninitialize();
  341. return hr;
  342. }
  343. //***************************************************************************
  344. //*
  345. //* purpose: getmodulefilename and return only the path
  346. //*
  347. //***************************************************************************
  348. BOOL GetThisModulePath( LPSTR lpPath, int size )
  349. {
  350. *lpPath = '\0';
  351. if ( GetModuleFileName( g_hInstance, lpPath, size ) )
  352. {
  353. MakePath(lpPath);
  354. return TRUE;
  355. }
  356. return FALSE;
  357. }
  358. //***************************************************************************
  359. //*
  360. //* purpose:
  361. //*
  362. //***************************************************************************
  363. void AddPath(LPSTR szPath, LPCSTR szName )
  364. {
  365. LPSTR szTmp;
  366. // Find end of the string
  367. szTmp = szPath + lstrlen(szPath);
  368. // If no trailing backslash then add one
  369. if ( szTmp > szPath && *(CharPrev( szPath, szTmp )) != '\\' )
  370. *(szTmp++) = '\\';
  371. // Add new name to existing path string
  372. while ( *szName == ' ' ) szName++;
  373. lstrcpy( szTmp, szName );
  374. }
  375. //***************************************************************************
  376. //*
  377. //* purpose:
  378. //*
  379. //***************************************************************************
  380. void MakePath(LPSTR lpPath)
  381. {
  382. LPSTR lpTmp;
  383. lpTmp = CharPrev( lpPath, lpPath+lstrlen(lpPath));
  384. // chop filename off
  385. while ( (lpTmp > lpPath) && *lpTmp && (*lpTmp != '\\') )
  386. lpTmp = CharPrev( lpPath, lpTmp );
  387. if ( *CharPrev( lpPath, lpTmp ) != ':' )
  388. *lpTmp = '\0';
  389. else
  390. *CharNext( lpTmp ) = '\0';
  391. return;
  392. }