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.

414 lines
11 KiB

  1. //+----------------------------------------------------------------------------
  2. // File: array.cxx
  3. //
  4. // Synopsis:
  5. //
  6. //-----------------------------------------------------------------------------
  7. // Includes -------------------------------------------------------------------
  8. #include <mgr.hxx>
  9. #include <factory.hxx>
  10. //+----------------------------------------------------------------------------
  11. //
  12. // Member: AddClass
  13. //
  14. // Synopsis:
  15. //
  16. // Arguments:
  17. //
  18. // Returns:
  19. //
  20. //-----------------------------------------------------------------------------
  21. HRESULT
  22. CLicenseManager::AddClass(
  23. REFCLSID rclsid,
  24. int * piLic)
  25. {
  26. IClassFactory2 * pcf2 = NULL;
  27. LICINFO licinfo;
  28. BSTR bstrLic;
  29. int iLic;
  30. HRESULT hr;
  31. Assert(piLic);
  32. Assert(!FindClass(rclsid, &iLic));
  33. // Get the class factory for the CLSID
  34. hr = ::CoGetClassObject(rclsid,
  35. CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,
  36. NULL,
  37. IID_IClassFactory2, (void **)&pcf2);
  38. if (hr)
  39. goto Cleanup;
  40. Assert(pcf2);
  41. // Determine if the object supports the creation of runtime licenses
  42. licinfo.cbLicInfo = sizeof(LICINFO);
  43. hr = pcf2->GetLicInfo(&licinfo);
  44. if (hr)
  45. goto Cleanup;
  46. if (!licinfo.fRuntimeKeyAvail ||
  47. !licinfo.fLicVerified)
  48. {
  49. hr = CLASS_E_NOTLICENSED;
  50. goto Cleanup;
  51. }
  52. // Obtain the object's runtime license
  53. hr = pcf2->RequestLicKey(0, &bstrLic);
  54. if (hr)
  55. goto Cleanup;
  56. Assert(bstrLic);
  57. // Add the object and its runtime license to the array of CLSID-License pairs
  58. // (The class is added in ascending order based upon the first DWORD of the CLSID)
  59. hr = _aryLic.SetSize(_aryLic.Size()+1);
  60. if (hr)
  61. goto Cleanup;
  62. for (iLic = 0; iLic < (_aryLic.Size()-1); iLic++)
  63. {
  64. if (rclsid.Data1 < _aryLic[iLic].clsid.Data1)
  65. break;
  66. }
  67. if (iLic < (_aryLic.Size()-1))
  68. {
  69. ::memmove(&_aryLic[iLic+1], &_aryLic[iLic], sizeof(_aryLic[0])*(_aryLic.Size()-iLic-1));
  70. }
  71. _aryLic[iLic].clsid = rclsid;
  72. _aryLic[iLic].bstrLic = bstrLic;
  73. _aryLic[iLic].pcf2 = pcf2;
  74. pcf2 = NULL;
  75. *piLic = iLic;
  76. _fDirty = TRUE;
  77. Cleanup:
  78. ::SRelease(pcf2);
  79. return hr;
  80. }
  81. //+----------------------------------------------------------------------------
  82. //
  83. // Member: FindClass
  84. //
  85. // Synopsis:
  86. //
  87. // Arguments:
  88. //
  89. // Returns:
  90. //
  91. //-----------------------------------------------------------------------------
  92. BOOL
  93. CLicenseManager::FindClass(
  94. REFCLSID rclsid,
  95. int * piLic)
  96. {
  97. int iLic;
  98. Assert(piLic);
  99. // BUGBUG: Consider using a more efficient search if the number of classes is large
  100. for (iLic=0; iLic < _aryLic.Size(); iLic++)
  101. {
  102. if (_aryLic[iLic].clsid.Data1 == rclsid.Data1 &&
  103. _aryLic[iLic].clsid == rclsid)
  104. break;
  105. }
  106. if (iLic < _aryLic.Size())
  107. {
  108. *piLic = iLic;
  109. }
  110. return (iLic < _aryLic.Size());
  111. }
  112. //+----------------------------------------------------------------------------
  113. //
  114. // Member: OnChangeInRequiredClasses
  115. //
  116. // Synopsis:
  117. //
  118. // Arguments:
  119. //
  120. // Returns:
  121. //
  122. //-----------------------------------------------------------------------------
  123. STDMETHODIMP
  124. CLicenseManager::OnChangeInRequiredClasses(
  125. IRequireClasses * pRequireClasses)
  126. {
  127. ULONG cClasses;
  128. ULONG iClass;
  129. int cLic;
  130. int iLic;
  131. CLSID clsid;
  132. BOOL fClassUsed;
  133. BOOL fClassNotLicensed = FALSE;
  134. HRESULT hr;
  135. if (!pRequireClasses)
  136. return E_INVALIDARG;
  137. // Determine the number of required classes
  138. hr = pRequireClasses->CountRequiredClasses(&cClasses);
  139. if (hr)
  140. goto Cleanup;
  141. // Add new classes to the array of required classes
  142. // NOTE: During this pass, all required classes are also marked as "in use"
  143. // Because of this, the second loop must also alway run, even when errors occur,
  144. // to remove these marks; that is, this loop cannot "goto Cleanup"
  145. for (iClass = 0; iClass < cClasses; iClass++)
  146. {
  147. // Get the CLSID of the required class
  148. hr = pRequireClasses->GetRequiredClasses(iClass, &clsid);
  149. if (hr)
  150. break;
  151. // Check if the class is already known; if not, add it
  152. // (Ignore "false" errors which occur during adding the class and treat it as unlicensed)
  153. fClassUsed = TRUE; // Assume the class will be used
  154. if (!FindClass(clsid, &iLic))
  155. {
  156. hr = AddClass(clsid, &iLic);
  157. if (hr)
  158. {
  159. if (hr == E_OUTOFMEMORY)
  160. break;
  161. fClassUsed = FALSE; // Class was not found nor added
  162. fClassNotLicensed = TRUE;
  163. hr = S_OK;
  164. }
  165. }
  166. // Mark the class as "in use" by setting the high-order bit of the factory address
  167. if (fClassUsed)
  168. {
  169. Assert((ULONG)(_aryLic[iLic].pcf2) < (ULONG_PTR)ADDRESS_TAG_BIT);
  170. _aryLic[iLic].pcf2 = (IClassFactory2 *)((ULONG_PTR)(_aryLic[iLic].pcf2) | ADDRESS_TAG_BIT);
  171. }
  172. }
  173. // Remove from the array classes no longer required
  174. // NOTE: If hr is not S_OK, then this loop should still execute, but only to clear
  175. // the mark bits on the IClassFactory2 interface pointers, no other changes
  176. // should occur
  177. // Also, early exits from this loop (using "break" for example) must not occur
  178. for (cLic = iLic = 0; iLic < _aryLic.Size(); iLic++)
  179. {
  180. // If the class is "in use", clear the mark bit
  181. if ((ULONG_PTR)(_aryLic[iLic].pcf2) & ADDRESS_TAG_BIT)
  182. {
  183. _aryLic[iLic].pcf2 = (IClassFactory2 *)((ULONG_PTR)(_aryLic[iLic].pcf2) & (ADDRESS_TAG_BIT-1));
  184. // If classes have been removed, shift this class down to the first open slot
  185. if (!hr && iLic > cLic)
  186. {
  187. _aryLic[cLic] = _aryLic[iLic];
  188. ::memset(&(_aryLic[iLic]), 0, sizeof(_aryLic[iLic]));
  189. }
  190. }
  191. // Otherwise, free the class and remove it from the array
  192. else if (!hr)
  193. {
  194. ::SysFreeString(_aryLic[iLic].bstrLic);
  195. ::SRelease(_aryLic[iLic].pcf2);
  196. ::memset(&(_aryLic[iLic]), 0, sizeof(_aryLic[iLic]));
  197. _fDirty = TRUE;
  198. }
  199. // As long as it points at a valid class, increment the class counter
  200. if (_aryLic[cLic].clsid != CLSID_NULL)
  201. {
  202. cLic++;
  203. }
  204. }
  205. Implies(hr, cLic == _aryLic.Size());
  206. Implies(!hr, (ULONG)cLic <= cClasses);
  207. Verify(SUCCEEDED(_aryLic.SetSize(cLic)));
  208. Cleanup:
  209. // If a real error occurred, return it
  210. // Otherwise return CLASS_E_NOTLICENSED if any un-licensed objects were encountered
  211. return (hr
  212. ? hr
  213. : (fClassNotLicensed
  214. ? CLASS_E_NOTLICENSED
  215. : S_OK));
  216. }
  217. //+----------------------------------------------------------------------------
  218. //
  219. // Member: CreateInstance
  220. //
  221. // Synopsis:
  222. //
  223. // Arguments:
  224. //
  225. // Returns:
  226. //
  227. //-----------------------------------------------------------------------------
  228. STDMETHODIMP
  229. CLicenseManager::CreateInstance(
  230. CLSID clsid,
  231. IUnknown * pUnkOuter,
  232. REFIID riid,
  233. DWORD dwClsCtx,
  234. void ** ppvObj)
  235. {
  236. int iLic;
  237. HRESULT hr;
  238. // If there is a runtime license for the class, create it using IClassFactory2
  239. if (FindClass(clsid, &iLic))
  240. {
  241. if (!_aryLic[iLic].pcf2)
  242. {
  243. //
  244. // The following code calls CoGetClassObject for an IClassFactory
  245. // then QIs for an IClassFactory2. This is because of an apparent
  246. // bug in ole32.dll. On a win95 system if the call to
  247. // CoGetClassObject is remoted and you ask for IClassFactory2 the
  248. // process hangs.
  249. //
  250. IClassFactory *pIClassFactory;
  251. hr = ::CoGetClassObject(clsid, dwClsCtx, NULL,
  252. IID_IClassFactory, (void **)&(pIClassFactory));
  253. if (SUCCEEDED(hr)) {
  254. hr = pIClassFactory->QueryInterface(IID_IClassFactory2,
  255. (void **)&(_aryLic[iLic].pcf2));
  256. pIClassFactory->Release();
  257. }
  258. if (hr)
  259. goto Cleanup;
  260. }
  261. Assert(_aryLic[iLic].pcf2);
  262. Assert(_aryLic[iLic].bstrLic != NULL);
  263. hr = _aryLic[iLic].pcf2->CreateInstanceLic(pUnkOuter, NULL,
  264. riid, _aryLic[iLic].bstrLic, ppvObj);
  265. }
  266. // Otherwise, use the standard COM mechanisms
  267. else
  268. {
  269. hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsCtx, riid, ppvObj);
  270. }
  271. Cleanup:
  272. return hr;
  273. }
  274. //+----------------------------------------------------------------------------
  275. //
  276. // Member: GetTypeLibOfClsid
  277. //
  278. // Synopsis:
  279. //
  280. // Arguments:
  281. //
  282. // Returns:
  283. //
  284. //-----------------------------------------------------------------------------
  285. STDMETHODIMP
  286. CLicenseManager::GetTypeLibOfClsid(
  287. CLSID clsid,
  288. ITypeLib ** ptlib)
  289. {
  290. UNREF(clsid);
  291. UNREF(ptlib);
  292. return E_NOTIMPL;
  293. }
  294. //+----------------------------------------------------------------------------
  295. //
  296. // Member: GetClassObjectOfClsid
  297. //
  298. // Synopsis:
  299. //
  300. // Arguments:
  301. //
  302. // Returns:
  303. //
  304. //-----------------------------------------------------------------------------
  305. STDMETHODIMP
  306. CLicenseManager::GetClassObjectOfClsid(
  307. REFCLSID rclsid,
  308. DWORD dwClsCtx,
  309. LPVOID lpReserved,
  310. REFIID riid,
  311. void ** ppcClassObject)
  312. {
  313. // Load the class object
  314. return ::CoGetClassObject(rclsid, dwClsCtx, lpReserved, riid, ppcClassObject);
  315. }
  316. //+----------------------------------------------------------------------------
  317. //
  318. // Member: CountRequiredClasses
  319. //
  320. // Synopsis:
  321. //
  322. // Arguments:
  323. //
  324. // Returns:
  325. //
  326. //-----------------------------------------------------------------------------
  327. STDMETHODIMP
  328. CLicenseManager::CountRequiredClasses(
  329. ULONG * pcClasses)
  330. {
  331. if (!pcClasses)
  332. return E_INVALIDARG;
  333. // Return the current number of classes
  334. *pcClasses = _aryLic.Size();
  335. return S_OK;
  336. }
  337. //+----------------------------------------------------------------------------
  338. //
  339. // Member: GetRequiredClasses
  340. //
  341. // Synopsis:
  342. //
  343. // Arguments:
  344. //
  345. // Returns:
  346. //
  347. //-----------------------------------------------------------------------------
  348. STDMETHODIMP
  349. CLicenseManager::GetRequiredClasses(
  350. ULONG iClass,
  351. CLSID * pclsid)
  352. {
  353. if (!pclsid || iClass >= (ULONG)_aryLic.Size())
  354. return E_INVALIDARG;
  355. // Return the requested CLSID
  356. *pclsid = _aryLic[iClass].clsid;
  357. return S_OK;
  358. }