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.

876 lines
28 KiB

  1. //
  2. // update.cpp - assembly update
  3. //
  4. #include <windows.h>
  5. #include <objbase.h>
  6. #include <fusenetincludes.h>
  7. //#include "Iface.h"
  8. #include "server.h"
  9. #include "CUnknown.h" // Base class for IUnknown
  10. #include "update.h"
  11. #include "cfactory.h"
  12. #include "list.h"
  13. #include "version.h"
  14. // used in OnProgress(), copied from guids.c
  15. DEFINE_GUID( IID_IAssemblyManifestImport,
  16. 0x696fb37f,0xda64,0x4175,0x94,0xe7,0xfd,0xc8,0x23,0x45,0x39,0xc4);
  17. #define WZ_URL L"Url"
  18. #define WZ_SYNC_INTERVAL L"SyncInterval"
  19. #define WZ_SYNC_EVENT L"SyncEvent"
  20. #define WZ_EVENT_DEMAND_CONNECTION L"EventDemandConnection"
  21. #define SUBSCRIPTION_REG_KEY L"1.0.0.0\\Subscription\\"
  22. #define UPDATE_REG_KEY L"CurrentService"
  23. extern HWND g_hwndUpdateServer;
  24. extern CRITICAL_SECTION g_csServer;
  25. List <CDownloadInstance*> g_ActiveDownloadList;
  26. HANDLE g_hAbortTimeout = INVALID_HANDLE_VALUE;
  27. BOOL g_fSignalUpdate = FALSE;
  28. // ---------------------------------------------------------------------------
  29. // Main timer callback for servicing subscriptions.
  30. // ---------------------------------------------------------------------------
  31. VOID CALLBACK SubscriptionTimerProc(
  32. HWND hwnd, // handle to window
  33. UINT uMsg, // WM_TIMER message
  34. UINT_PTR idEvent, // timer identifier
  35. DWORD dwTime // current system time
  36. )
  37. {
  38. HRESULT hr = S_OK;
  39. MAKE_ERROR_MACROS_STATIC(hr);
  40. DWORD dwHash = 0, nMilliseconds = 0, i= 0;
  41. BOOL bIsDuplicate = FALSE;
  42. CString sUrl;
  43. CRegImport *pRegImport = NULL;
  44. CRegImport *pSubRegImport = NULL;
  45. IAssemblyDownload *pAssemblyDownload = NULL;
  46. CAssemblyBindSink *pCBindSink = NULL;
  47. CDownloadInstance *pCDownloadInstance = NULL;
  48. // If update detected stop processing
  49. // subscriptions and kick off new server.
  50. hr = CAssemblyUpdate::CheckForUpdate();
  51. IF_FAILED_EXIT(hr);
  52. if (hr == S_OK)
  53. goto exit;
  54. IF_FAILED_EXIT(CRegImport::Create(&pRegImport, SUBSCRIPTION_REG_KEY));
  55. if (hr == S_FALSE)
  56. goto exit;
  57. // Enum over subscription keys.
  58. while ((hr = pRegImport->EnumKeys(i++, &pSubRegImport)) == S_OK)
  59. {
  60. // Get url and polling inteval.
  61. IF_FAILED_EXIT(pSubRegImport->ReadString(WZ_URL, sUrl));
  62. IF_FAILED_EXIT(pSubRegImport->ReadDword(WZ_SYNC_INTERVAL, &nMilliseconds));
  63. // Get url hash
  64. IF_FAILED_EXIT(sUrl.Get65599Hash(&dwHash, CString::CaseInsensitive));
  65. // Check the hash.
  66. if ((dwHash == idEvent))
  67. {
  68. // hash checks, now check for dupe and skip if found.
  69. IF_FAILED_EXIT(CAssemblyUpdate::IsDuplicate(sUrl._pwz, &bIsDuplicate));
  70. if (bIsDuplicate)
  71. {
  72. SAFEDELETE(pSubRegImport);
  73. continue;
  74. }
  75. // Create the download object.
  76. IF_FAILED_EXIT(CreateAssemblyDownload(&pAssemblyDownload, NULL, 0));
  77. // Create bind sink object with download pointer
  78. IF_ALLOC_FAILED_EXIT(pCBindSink = new CAssemblyBindSink(pAssemblyDownload));
  79. // Create the download instance object.
  80. IF_ALLOC_FAILED_EXIT(pCDownloadInstance = new CDownloadInstance);
  81. // Download instance references pAssemblyDownload.
  82. pCDownloadInstance->_pAssemblyDownload = pAssemblyDownload;
  83. IF_FAILED_EXIT(pCDownloadInstance->_sUrl.Assign(sUrl));
  84. // Push download object onto list and fire off download; bind sink will remove and release on completion.
  85. EnterCriticalSection(&g_csServer);
  86. g_ActiveDownloadList.AddHead(pCDownloadInstance);
  87. LeaveCriticalSection(&g_csServer);
  88. // Invoke the download.
  89. hr = pAssemblyDownload->DownloadManifestAndDependencies(sUrl._pwz,
  90. (IAssemblyBindSink*) pCBindSink, DOWNLOAD_FLAGS_NOTIFY_BINDSINK);
  91. if(hr == STG_E_TERMINATED)
  92. {
  93. hr = S_FALSE; // there was an error in download. Log it but don't break into debugger/assert.
  94. }
  95. IF_FAILED_EXIT(hr);
  96. }
  97. SAFEDELETE(pSubRegImport);
  98. }
  99. exit:
  100. // The active download list looks like:
  101. // (circ. refcount)
  102. // pCDownloadInstance ---> pAssemblyDownload <=========> pCBindSink
  103. // |
  104. // v
  105. // ...
  106. //
  107. // pAssemblyDownload, pCBindSink each have refcount of 1 and will be released
  108. // on successful completion.
  109. // DON'T RELEASE THEM HERE UNLESS A FAILURE OCCURED.
  110. if (FAILED(hr))
  111. {
  112. SAFERELEASE(pAssemblyDownload);
  113. SAFERELEASE(pCBindSink);
  114. SAFEDELETE(pCDownloadInstance);
  115. }
  116. SAFEDELETE(pRegImport);
  117. SAFEDELETE(pSubRegImport);
  118. return;
  119. }
  120. ///////////////////////////////////////////////////////////
  121. //
  122. // Interface IAssemblyBindSink
  123. //
  124. // ---------------------------------------------------------------------------
  125. // ctor
  126. // ---------------------------------------------------------------------------
  127. CAssemblyBindSink::CAssemblyBindSink(IAssemblyDownload *pAssemblyDownload)
  128. {
  129. _cRef = 1;
  130. _pAssemblyDownload = pAssemblyDownload;
  131. }
  132. // ---------------------------------------------------------------------------
  133. // dtor
  134. // ---------------------------------------------------------------------------
  135. CAssemblyBindSink::~CAssemblyBindSink()
  136. {}
  137. // ---------------------------------------------------------------------------
  138. // OnProgress
  139. // ---------------------------------------------------------------------------
  140. HRESULT CAssemblyBindSink::OnProgress(
  141. DWORD dwNotification,
  142. HRESULT hrNotification,
  143. LPCWSTR szNotification,
  144. DWORD dwProgress,
  145. DWORD dwProgressMax,
  146. IUnknown *pUnk)
  147. {
  148. HRESULT hr = S_OK;
  149. MAKE_ERROR_MACROS_STATIC(hr);
  150. LPASSEMBLY_MANIFEST_IMPORT pManifestImport = NULL;
  151. LPASSEMBLY_IDENTITY pAppId = NULL;
  152. CAssemblyUpdate *pAssemblyUpdate = NULL;
  153. LPMANIFEST_INFO pAppAssemblyInfo = NULL;
  154. LPMANIFEST_INFO pSubsInfo = NULL;
  155. if (dwNotification == ASM_NOTIFICATION_SUBSCRIPTION_MANIFEST)
  156. {
  157. LPWSTR pwz = NULL;
  158. DWORD cb = 0, cc = 0, dwFlag = 0;
  159. CString sAppName;
  160. // szNotification == URL to manifest
  161. IF_NULL_EXIT(szNotification, E_INVALIDARG);
  162. // pUnk == manifest import of manifest
  163. IF_FAILED_EXIT(pUnk->QueryInterface(IID_IAssemblyManifestImport, (LPVOID*) &pManifestImport));
  164. // Get the dependent (application) assembly info (0th index)
  165. IF_FAILED_EXIT(pManifestImport->GetNextAssembly(0, &pAppAssemblyInfo));
  166. IF_NULL_EXIT(pAppAssemblyInfo, E_INVALIDARG);
  167. // Get dependent (application) assembly identity
  168. IF_FAILED_EXIT(pAppAssemblyInfo->Get(MAN_INFO_DEPENDENT_ASM_ID, (LPVOID *)&pAppId, &cb, &dwFlag));
  169. IF_NULL_EXIT(pAppId, E_INVALIDARG);
  170. // Get application text name.
  171. IF_FAILED_EXIT(hr = pAppId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwz, &cc));
  172. IF_FAILED_EXIT(sAppName.TakeOwnership(pwz, cc));
  173. pAssemblyUpdate = new CAssemblyUpdate();
  174. IF_ALLOC_FAILED_EXIT(pAssemblyUpdate);
  175. // Get subscription info from manifest
  176. IF_FAILED_EXIT(pManifestImport->GetSubscriptionInfo(&pSubsInfo));
  177. // Register the subscription.
  178. IF_FAILED_EXIT(pAssemblyUpdate->RegisterAssemblySubscriptionFromInfo(sAppName._pwz,
  179. (LPWSTR) szNotification, pSubsInfo));
  180. }
  181. else if ((dwNotification == ASM_NOTIFICATION_DONE)
  182. || (dwNotification == ASM_NOTIFICATION_ABORT)
  183. || (dwNotification == ASM_NOTIFICATION_ERROR))
  184. {
  185. // Synchronize with SubscriptionTimerProc.
  186. EnterCriticalSection(&g_csServer);
  187. LISTNODE pos = NULL;
  188. LISTNODE posRemove = NULL;
  189. CDownloadInstance *pDownloadInstance = NULL;
  190. // Walk the global download instance list.
  191. pos = g_ActiveDownloadList.GetHeadPosition();
  192. while ((posRemove = pos) && (pDownloadInstance = g_ActiveDownloadList.GetNext(pos)))
  193. {
  194. // Check for match against callback's interface pointer value.
  195. if (pDownloadInstance->_pAssemblyDownload == _pAssemblyDownload)
  196. {
  197. // If match found, remove from list and release.
  198. g_ActiveDownloadList.RemoveAt(posRemove);
  199. // If an update has been signalled the client thread will wait until
  200. // the active download list has been drained via abort handling on
  201. // each download object. Signal this when the list is empty.
  202. if (g_fSignalUpdate && (g_ActiveDownloadList.GetCount() == 0))
  203. SetEvent(g_hAbortTimeout);
  204. _pAssemblyDownload->Release();
  205. SAFEDELETE(pDownloadInstance);
  206. break;
  207. }
  208. }
  209. LeaveCriticalSection(&g_csServer);
  210. // Because of the circular refcount between CAssemblyDownload and CAssemblyBindSink
  211. // we don't addreff this instance and it is responsible for deleting itself.
  212. delete this;
  213. }
  214. exit:
  215. SAFERELEASE(pManifestImport);
  216. SAFERELEASE(pAppId);
  217. SAFEDELETE(pAssemblyUpdate);
  218. SAFERELEASE(pAppAssemblyInfo);
  219. SAFERELEASE(pSubsInfo);
  220. return hr;
  221. }
  222. // ---------------------------------------------------------------------------
  223. // CAssemblyBindSink::QI
  224. // ---------------------------------------------------------------------------
  225. STDMETHODIMP
  226. CAssemblyBindSink::QueryInterface(REFIID riid, void** ppvObj)
  227. {
  228. if ( IsEqualIID(riid, IID_IUnknown)
  229. || IsEqualIID(riid, IID_IAssemblyBindSink)
  230. )
  231. {
  232. *ppvObj = static_cast<IAssemblyBindSink*> (this);
  233. AddRef();
  234. return S_OK;
  235. }
  236. else
  237. {
  238. *ppvObj = NULL;
  239. return E_NOINTERFACE;
  240. }
  241. }
  242. // ---------------------------------------------------------------------------
  243. // CAssemblyBindSink::AddRef
  244. // ---------------------------------------------------------------------------
  245. STDMETHODIMP_(ULONG)
  246. CAssemblyBindSink::AddRef()
  247. {
  248. return InterlockedIncrement ((LONG*) &_cRef);
  249. }
  250. // ---------------------------------------------------------------------------
  251. // CAssemblyBindSink::Release
  252. // ---------------------------------------------------------------------------
  253. STDMETHODIMP_(ULONG)
  254. CAssemblyBindSink::Release()
  255. {
  256. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  257. if (!lRet)
  258. delete this;
  259. return lRet;
  260. }
  261. ///////////////////////////////////////////////////////////
  262. //
  263. // Interface IAssemblyUpdate
  264. //
  265. HRESULT __stdcall CAssemblyUpdate::RegisterAssemblySubscription(LPWSTR pwzDisplayName,
  266. LPWSTR pwzUrl, DWORD dwInterval)
  267. {
  268. // ISSUE-2002/04/19-felixybc dummy method to keep interface unchanged.
  269. // This method should not be called.
  270. return E_NOTIMPL;
  271. }
  272. // ---------------------------------------------------------------------------
  273. // RegisterAssemblySubscriptionEx
  274. // ---------------------------------------------------------------------------
  275. HRESULT __stdcall CAssemblyUpdate::RegisterAssemblySubscriptionEx(LPWSTR pwzDisplayName,
  276. LPWSTR pwzUrl, DWORD dwInterval, DWORD dwIntervalUnit,
  277. DWORD dwEvent, BOOL bEventDemandConnection)
  278. {
  279. DWORD dwMilliseconds = 0, dwDemandConnection = 0,
  280. dwHash = 0, dwFactor = 1;
  281. CString sUrl;
  282. CString sSubscription;
  283. CRegEmit *pRegEmit = NULL;
  284. dwDemandConnection = bEventDemandConnection; // BOOL -> DWORD
  285. switch(dwIntervalUnit)
  286. {
  287. case SUBSCRIPTION_INTERVAL_UNIT_DAYS:
  288. dwFactor *= 24; // falls thru, 1 hr*24 = 1 day
  289. case SUBSCRIPTION_INTERVAL_UNIT_HOURS:
  290. default:
  291. dwFactor *= 60; // falls thru, 1 min*60 = 1 hr
  292. case SUBSCRIPTION_INTERVAL_UNIT_MINUTES:
  293. dwFactor *= 60000; // 1ms*60000 = 1 min
  294. break;
  295. }
  296. // BUGBUG: check overflow
  297. dwMilliseconds = dwInterval * dwFactor;
  298. #ifdef DBG
  299. #define REG_KEY_FUSION_SETTINGS TEXT("Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\Subscription")
  300. // BUGBUG: code to facilitate testing ONLY - shorten minutes to seconds
  301. {
  302. // read subkey, default is false
  303. if (SHRegGetBoolUSValue(REG_KEY_FUSION_SETTINGS, L"ShortenMinToSec", FALSE, FALSE))
  304. {
  305. dwMilliseconds /= 60; // at this point, dwMilliseconds >= 60000
  306. }
  307. }
  308. #endif
  309. // Get hash of url
  310. // BUGBUG - this could just be a global counter, right?
  311. IF_FAILED_EXIT(sUrl.Assign(pwzUrl));
  312. IF_FAILED_EXIT(sUrl.Get65599Hash(&dwHash, CString::CaseInsensitive));
  313. // Form subscription regstring.
  314. IF_FAILED_EXIT(sSubscription.Assign(SUBSCRIPTION_REG_KEY));
  315. IF_FAILED_EXIT(sSubscription.Append(pwzDisplayName));
  316. // Set the subscription regkeys.
  317. IF_FAILED_EXIT(CRegEmit::Create(&pRegEmit, sSubscription._pwz));
  318. IF_FAILED_EXIT(pRegEmit->WriteDword(WZ_SYNC_INTERVAL, dwMilliseconds));
  319. IF_FAILED_EXIT(pRegEmit->WriteDword(WZ_SYNC_EVENT, dwEvent));
  320. IF_FAILED_EXIT(pRegEmit->WriteDword(WZ_EVENT_DEMAND_CONNECTION, dwDemandConnection));
  321. IF_FAILED_EXIT(pRegEmit->WriteString(WZ_URL, sUrl));
  322. // Fire off the timer.
  323. IF_WIN32_FALSE_EXIT(SetTimer((HWND) g_hwndUpdateServer, dwHash, dwMilliseconds, SubscriptionTimerProc));
  324. IF_FAILED_EXIT(CheckForUpdate());
  325. _hr = S_OK;
  326. exit:
  327. SAFEDELETE(pRegEmit);
  328. return _hr;
  329. }
  330. // ---------------------------------------------------------------------------
  331. // UnRegisterAssemblySubscription
  332. // ---------------------------------------------------------------------------
  333. HRESULT __stdcall CAssemblyUpdate::UnRegisterAssemblySubscription(LPWSTR pwzDisplayName)
  334. {
  335. CRegEmit *pRegEmit = NULL;
  336. // Form full regkey path.
  337. IF_FAILED_EXIT(CRegEmit::Create(&pRegEmit, SUBSCRIPTION_REG_KEY));
  338. IF_FAILED_EXIT(pRegEmit->DeleteKey(pwzDisplayName));
  339. IF_FAILED_EXIT(CheckForUpdate());
  340. _hr = S_OK;
  341. exit:
  342. SAFEDELETE(pRegEmit);
  343. return _hr;
  344. }
  345. // ---------------------------------------------------------------------------
  346. // Initialize servicing subscriptions.
  347. // ---------------------------------------------------------------------------
  348. HRESULT CAssemblyUpdate::InitializeSubscriptions()
  349. {
  350. HRESULT hr = S_OK;
  351. MAKE_ERROR_MACROS_STATIC(hr);
  352. DWORD dwHash = 0, nMilliseconds = 0, i=0;
  353. CString sUrl;
  354. CRegImport *pRegImport = NULL;
  355. CRegImport *pSubRegImport = NULL;
  356. IF_FAILED_EXIT(CRegImport::Create(&pRegImport, SUBSCRIPTION_REG_KEY));
  357. if (hr == S_FALSE)
  358. goto exit;
  359. // Enum over subscription keys.
  360. while ((hr = pRegImport->EnumKeys(i++, &pSubRegImport)) == S_OK)
  361. {
  362. // Get url and polling inteval.
  363. IF_FAILED_EXIT(pSubRegImport->ReadString(WZ_URL, sUrl));
  364. IF_FAILED_EXIT(pSubRegImport->ReadDword(WZ_SYNC_INTERVAL, &nMilliseconds));
  365. // Get url hash
  366. IF_FAILED_EXIT(sUrl.Get65599Hash(&dwHash, CString::CaseInsensitive));
  367. // Set the subscription timer event.
  368. IF_WIN32_FALSE_EXIT(SetTimer((HWND) g_hwndUpdateServer, dwHash, nMilliseconds, SubscriptionTimerProc));
  369. SAFEDELETE(pSubRegImport);
  370. }
  371. g_hAbortTimeout = CreateEvent(NULL, TRUE, FALSE, NULL);
  372. IF_WIN32_FALSE_EXIT(g_hAbortTimeout != NULL);
  373. exit:
  374. SAFEDELETE(pRegImport);
  375. SAFEDELETE(pSubRegImport);
  376. return hr;
  377. }
  378. // ---------------------------------------------------------------------------
  379. // CheckForUpdate
  380. // ---------------------------------------------------------------------------
  381. HRESULT CAssemblyUpdate::CheckForUpdate()
  382. {
  383. HRESULT hr = S_OK;
  384. MAKE_ERROR_MACROS_STATIC(hr);
  385. ULONGLONG ullUpdateVersion = 0,
  386. ullCurrentVersion = 0;
  387. CString sUpdatePath;
  388. BOOL bUpdate = FALSE, bDoRelease = TRUE;
  389. DWORD dwWaitState = 0;
  390. STARTUPINFO si = {0};
  391. PROCESS_INFORMATION pi = {0};
  392. EnterCriticalSection(&g_csServer);
  393. if (g_fSignalUpdate == TRUE)
  394. goto exit;
  395. // Check the registry update location. The service will terminate
  396. // if no key is found (uninstall) or if update with higher version is found.
  397. // ISSUE-2002/03/19-adriaanc
  398. // A race condition exists when Darwin upgrades v1->v2 of ClickOnce -
  399. // Major upgrade first uninstalls v1, then installs v2 so the registry key
  400. // may not be present when checking and we will incorrectly shutdown.
  401. // Mitigating factor is that this requires a major upgrade - so reboot implicit?
  402. // One possible solution is to zomby the process for a time and reverify
  403. // the uninstall by rechecking the regkey.
  404. IF_FAILED_EXIT(ReadUpdateRegistryEntry(&ullUpdateVersion, sUpdatePath));
  405. if (hr == S_OK)
  406. {
  407. GetCurrentVersion(&ullCurrentVersion);
  408. if (ullUpdateVersion <= ullCurrentVersion)
  409. {
  410. hr = S_FALSE;
  411. goto exit;
  412. }
  413. bUpdate = TRUE;
  414. }
  415. else
  416. hr = S_OK;
  417. // Revoke the class factories.
  418. CFactory::StopFactories();
  419. // Nuke outstanding jobs.
  420. if (g_ActiveDownloadList.GetCount())
  421. {
  422. LISTNODE pos = NULL;
  423. CDownloadInstance *pDownloadInstance = NULL;
  424. // Walk the global download instance list and cancel
  425. // any outstanding jobs.
  426. pos = g_ActiveDownloadList.GetHeadPosition();
  427. // Walk the list and cancel the downloads.
  428. // DO NOT remove them from the list or release
  429. // them - this will be taken care of by the bindsink.
  430. while (pos && (pDownloadInstance = g_ActiveDownloadList.GetNext(pos)))
  431. IF_FAILED_EXIT(pDownloadInstance->_pAssemblyDownload->CancelDownload());
  432. }
  433. // CreateProcess on updated server.
  434. if (bUpdate)
  435. {
  436. si.cb = sizeof(si);
  437. IF_WIN32_FALSE_EXIT(CreateProcess(sUpdatePath._pwz, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi));
  438. }
  439. // Flag that an update has been signalled. We are now entering process termination phase.
  440. g_fSignalUpdate = TRUE;
  441. // The process must stay resident until any outstanding async callback threads have had a chance to
  442. // complete their aborts. An efficient check is to first check if the active download queue has any
  443. // entries. We can do this here because we are under the global crit sect and BITS callbacks can
  444. // only be extant when one or more downloads are in the queue and no additional downloads will
  445. // be submitted because g_fSignalUpdate before we leave the critsect.
  446. if (g_ActiveDownloadList.GetCount())
  447. {
  448. // Downloads are currently in progress. Wait for the aborts to complete.
  449. // We synchronize on the abort event with a 1 minute timeout in the
  450. // case that one or more aborts failed to complete. This is technically
  451. // an error condition but we still MUST exit the process.
  452. // It is necessary to release the global critsect so that the
  453. // downloaders may update the active download list.
  454. bDoRelease = FALSE;
  455. ::LeaveCriticalSection(&g_csServer);
  456. // Sync on the abort timeout.
  457. dwWaitState = WaitForSingleObject(g_hAbortTimeout, 60000);
  458. IF_WIN32_FALSE_EXIT((dwWaitState != WAIT_FAILED));
  459. // In retail builds we would ignore the timeout. In debug catch the assert.
  460. if (dwWaitState != WAIT_OBJECT_0)
  461. {
  462. ASSERT(FALSE);
  463. }
  464. }
  465. // decrement artificial ref count; ensures server
  466. // exits on last interface released.
  467. ::InterlockedDecrement(&CFactory::s_cServerLocks) ;
  468. // And attempt to terminate the process.
  469. CFactory::CloseExe();
  470. exit:
  471. if (bDoRelease)
  472. ::LeaveCriticalSection(&g_csServer);
  473. return hr;
  474. }
  475. // ---------------------------------------------------------------------------
  476. // RegisterAssemblySubscriptionFromInfo
  477. // NOTE - this is NOT a public method on IAssemblyUpdate
  478. // NOTE - what types of validation should be done here if any?
  479. // ---------------------------------------------------------------------------
  480. HRESULT CAssemblyUpdate::RegisterAssemblySubscriptionFromInfo(LPWSTR pwzDisplayName,
  481. LPWSTR pwzUrl, IManifestInfo *pSubscriptionInfo)
  482. {
  483. DWORD *pdw = NULL;
  484. BOOL *pb = NULL;
  485. DWORD dwInterval = 0, dwUnit = SUBSCRIPTION_INTERVAL_UNIT_MAX;
  486. DWORD dwEvent = 0;
  487. BOOL bDemandConnection = FALSE;
  488. DWORD dwCB = 0, dwFlag = 0;
  489. IF_FAILED_EXIT(pSubscriptionInfo->Get(MAN_INFO_SUBSCRIPTION_SYNCHRONIZE_INTERVAL, (LPVOID *)&pdw, &dwCB, &dwFlag));
  490. if (pdw != NULL)
  491. {
  492. dwInterval = *pdw;
  493. SAFEDELETEARRAY(pdw);
  494. }
  495. IF_FAILED_EXIT(pSubscriptionInfo->Get(MAN_INFO_SUBSCRIPTION_INTERVAL_UNIT, (LPVOID *)&pdw, &dwCB, &dwFlag));
  496. if (pdw != NULL)
  497. {
  498. dwUnit = *pdw;
  499. SAFEDELETEARRAY(pdw);
  500. }
  501. IF_FAILED_EXIT(pSubscriptionInfo->Get(MAN_INFO_SUBSCRIPTION_SYNCHRONIZE_EVENT, (LPVOID *)&pdw, &dwCB, &dwFlag));
  502. if (pdw != NULL)
  503. {
  504. dwEvent = *pdw;
  505. SAFEDELETEARRAY(pdw);
  506. }
  507. IF_FAILED_EXIT(pSubscriptionInfo->Get(MAN_INFO_SUBSCRIPTION_EVENT_DEMAND_CONNECTION, (LPVOID *)&pb, &dwCB, &dwFlag));
  508. if (pb != NULL)
  509. {
  510. bDemandConnection = *pb;
  511. SAFEDELETEARRAY(pb);
  512. }
  513. IF_FAILED_EXIT(RegisterAssemblySubscriptionEx(pwzDisplayName,
  514. pwzUrl, dwInterval, dwUnit, dwEvent, bDemandConnection));
  515. exit:
  516. return _hr;
  517. }
  518. // ---------------------------------------------------------------------------
  519. // ctor
  520. // ---------------------------------------------------------------------------
  521. CAssemblyUpdate::CAssemblyUpdate()
  522. : CUnknown(), _hr(S_OK)
  523. {
  524. // Empty
  525. }
  526. // ---------------------------------------------------------------------------
  527. // dtor
  528. // ---------------------------------------------------------------------------
  529. CAssemblyUpdate::~CAssemblyUpdate()
  530. {
  531. }
  532. // ---------------------------------------------------------------------------
  533. // QueryInterface
  534. // ---------------------------------------------------------------------------
  535. HRESULT __stdcall CAssemblyUpdate::QueryInterface(const IID& iid,
  536. void** ppv)
  537. {
  538. if ( IsEqualIID(iid, IID_IUnknown)
  539. || IsEqualIID(iid, IID_IAssemblyUpdate)
  540. )
  541. {
  542. return CUnknown::FinishQI((IAssemblyUpdate*)this, ppv) ;
  543. }
  544. else
  545. {
  546. *ppv = NULL;
  547. return E_NOINTERFACE;
  548. }
  549. }
  550. // ---------------------------------------------------------------------------
  551. // CAssemblyDownload::AddRef
  552. // ---------------------------------------------------------------------------
  553. STDMETHODIMP_(ULONG)
  554. CAssemblyUpdate::AddRef()
  555. {
  556. return CUnknown::AddRef();
  557. }
  558. // ---------------------------------------------------------------------------
  559. // CAssemblyDownload::Release
  560. // ---------------------------------------------------------------------------
  561. STDMETHODIMP_(ULONG)
  562. CAssemblyUpdate::Release()
  563. {
  564. return CUnknown::Release();
  565. }
  566. // ---------------------------------------------------------------------------
  567. // Creation function used by CFactory
  568. // ---------------------------------------------------------------------------
  569. HRESULT CAssemblyUpdate::CreateInstance(IUnknown* pUnknownOuter,
  570. CUnknown** ppNewComponent)
  571. {
  572. if (pUnknownOuter != NULL)
  573. {
  574. return CLASS_E_NOAGGREGATION ;
  575. }
  576. *ppNewComponent = new CAssemblyUpdate() ;
  577. return S_OK ;
  578. }
  579. // ---------------------------------------------------------------------------
  580. // Init function used by CFactory
  581. // ---------------------------------------------------------------------------
  582. HRESULT CAssemblyUpdate::Init()
  583. {
  584. return S_OK;
  585. }
  586. // ---------------------------------------------------------------------------
  587. // GetCurrentVersion
  588. // ---------------------------------------------------------------------------
  589. HRESULT CAssemblyUpdate::GetCurrentVersion(ULONGLONG *pullCurrentVersion)
  590. {
  591. ULONGLONG ullVer = 0;
  592. WORD wVer[4] = { FUS_VER_MAJORVERSION , FUS_VER_MINORVERSION,
  593. FUS_VER_PRODUCTBUILD, FUS_VER_PRODUCTBUILD_QFE };
  594. for (int i = 0; i < 4; i++)
  595. ullVer |= ((ULONGLONG) wVer[i]) << (sizeof(WORD) * 8 * (3-i));
  596. *pullCurrentVersion = ullVer;
  597. return S_OK;
  598. }
  599. // ---------------------------------------------------------------------------
  600. // RemoveUpdateRegEntry
  601. // ---------------------------------------------------------------------------
  602. HRESULT CAssemblyUpdate::RemoveUpdateRegistryEntry()
  603. {
  604. HRESULT hr = S_OK;
  605. MAKE_ERROR_MACROS_STATIC(hr);
  606. CRegEmit *pEmit = NULL;
  607. IF_FAILED_EXIT(CRegEmit::Create(&pEmit, NULL));
  608. IF_FAILED_EXIT(pEmit->DeleteKey(UPDATE_REG_KEY));
  609. exit:
  610. return hr;
  611. }
  612. // ---------------------------------------------------------------------------
  613. // ReadUpdateRegistryEntry
  614. // ---------------------------------------------------------------------------
  615. HRESULT CAssemblyUpdate::ReadUpdateRegistryEntry(ULONGLONG *pullUpdateVersion, CString &sUpdatePath)
  616. {
  617. HRESULT hr = S_OK;
  618. MAKE_ERROR_MACROS_STATIC(hr);
  619. LPWSTR pwz = NULL;
  620. WORD wVer[4] = {0,0,0,0};
  621. ULONGLONG ullVer = 0;
  622. INT i= 0, iVersion = 0;
  623. BOOL fDot = TRUE;
  624. CString sVersion;
  625. CRegImport *pRegImport = NULL;
  626. hr = CRegImport::Create(&pRegImport, UPDATE_REG_KEY);
  627. if (hr == S_FALSE)
  628. goto exit;
  629. IF_FAILED_EXIT(hr);
  630. IF_FAILED_EXIT(pRegImport->ReadString(L"Version", sVersion));
  631. IF_FAILED_EXIT(pRegImport->ReadString(L"Path", sUpdatePath));
  632. // Parse the version to ulonglong
  633. pwz = sVersion._pwz;
  634. while (*pwz)
  635. {
  636. if (fDot)
  637. {
  638. iVersion=StrToInt(pwz);
  639. wVer[i++] = (WORD) iVersion;
  640. fDot = FALSE;
  641. }
  642. if (*pwz == L'.')
  643. fDot = TRUE;
  644. pwz++;
  645. if (i > 3)
  646. break;
  647. }
  648. for (i = 0; i < 4; i++)
  649. ullVer |= ((ULONGLONG) wVer[i]) << (sizeof(WORD) * 8 * (3-i));
  650. *pullUpdateVersion = ullVer;
  651. exit:
  652. SAFEDELETE(pRegImport);
  653. return hr;
  654. }
  655. // ---------------------------------------------------------------------------
  656. // Helper function for determining dupes in active subscription list.
  657. // ---------------------------------------------------------------------------
  658. HRESULT CAssemblyUpdate::IsDuplicate(LPWSTR pwzURL, BOOL *pbIsDuplicate)
  659. {
  660. HRESULT hr = S_OK;
  661. MAKE_ERROR_MACROS_STATIC(hr);
  662. BOOL bDuplicate = FALSE;
  663. INT iCompare = 0;
  664. LISTNODE pos = NULL;
  665. CDownloadInstance *pDownloadInstance = NULL;
  666. EnterCriticalSection(&g_csServer);
  667. // Walk the global download instance list.
  668. pos = g_ActiveDownloadList.GetHeadPosition();
  669. while ( (pos) && (pDownloadInstance = g_ActiveDownloadList.GetNext(pos)))
  670. {
  671. iCompare = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  672. pDownloadInstance->_sUrl._pwz, -1, pwzURL, -1);
  673. IF_WIN32_FALSE_EXIT(iCompare);
  674. if (iCompare == CSTR_EQUAL)
  675. {
  676. bDuplicate = TRUE;
  677. break;
  678. }
  679. }
  680. *pbIsDuplicate = bDuplicate;
  681. exit:
  682. LeaveCriticalSection(&g_csServer);
  683. return hr;
  684. }