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.

616 lines
18 KiB

  1. /***************************************************************************\
  2. *
  3. * File: MsgClass.h
  4. *
  5. * Description:
  6. * MsgClass.h implements the "Message Class" object that is created for each
  7. * different message object type. Each object has a corresponding MsgClass
  8. * that provides information about that object type.
  9. *
  10. *
  11. * History:
  12. * 8/05/2000: JStall: Created
  13. *
  14. * Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
  15. *
  16. \***************************************************************************/
  17. #include "stdafx.h"
  18. #include "Msg.h"
  19. #include "MsgClass.h"
  20. #include "MsgTable.h"
  21. #include "MsgObject.h"
  22. #include "ClassLibrary.h"
  23. /***************************************************************************\
  24. *****************************************************************************
  25. *
  26. * class MsgClass
  27. *
  28. *****************************************************************************
  29. \***************************************************************************/
  30. /***************************************************************************\
  31. *
  32. * MsgClass::~MsgClass
  33. *
  34. * ~MsgClass() cleans up resources associated with a specific message class.
  35. *
  36. \***************************************************************************/
  37. MsgClass::~MsgClass()
  38. {
  39. //
  40. // Clean up internal resources
  41. //
  42. if (m_pmt != NULL) {
  43. m_pmt->Destroy();
  44. }
  45. DeleteAtom(m_atomName);
  46. }
  47. /***************************************************************************\
  48. *
  49. * MsgClass::Build
  50. *
  51. * Build() creates a placeholder MsgClass so that we can register Stubs to be
  52. * setup after the implementation is registered.
  53. *
  54. * NOTE: We can NOT instantiate MsgObject's until the implementation has also
  55. * been registered.
  56. *
  57. \***************************************************************************/
  58. HRESULT
  59. MsgClass::Build(
  60. IN LPCWSTR pszClassName, // Class information
  61. OUT MsgClass ** ppmcNew) // New MsgClass
  62. {
  63. //
  64. // Allocate the new MsgClass
  65. //
  66. ATOM atomName = AddAtomW(pszClassName);
  67. if (atomName == 0) {
  68. return E_OUTOFMEMORY;
  69. }
  70. MsgClass * pmcNew = ProcessNew(MsgClass);
  71. if (pmcNew == NULL) {
  72. return E_OUTOFMEMORY;
  73. }
  74. pmcNew->m_pszName = pszClassName;
  75. pmcNew->m_atomName = atomName;
  76. *ppmcNew = pmcNew;
  77. return S_OK;
  78. }
  79. /***************************************************************************\
  80. *
  81. * MsgClass::xwDeleteHandle
  82. *
  83. * xwDeleteHandle() is called when the application calls ::DeleteHandle() on
  84. * an object.
  85. *
  86. \***************************************************************************/
  87. BOOL
  88. MsgClass::xwDeleteHandle()
  89. {
  90. //
  91. // MsgClass's can not be deleted externally. Once registered, they exist
  92. // for the lifetime of the process. The reason is that we don't keep track
  93. // of how many already created objects may be using the MsgTable owned by
  94. // the MsgClass. We also would need to ensure that no classes derive from
  95. // this class.
  96. //
  97. return TRUE;
  98. }
  99. /***************************************************************************\
  100. *
  101. * MsgClass::RegisterGuts
  102. *
  103. * RegisterGuts() is called by the implementation class to provide the "guts"
  104. * of a MsgClass. This fills in the outstanding information required to be
  105. * able to actually instantiate the MsgClass.
  106. *
  107. \***************************************************************************/
  108. HRESULT
  109. MsgClass::RegisterGuts(
  110. IN OUT DUser::MessageClassGuts * pmcInfo)
  111. // Class information
  112. {
  113. AssertWritePtr(pmcInfo);
  114. if (IsGutsRegistered()) {
  115. PromptInvalid("The implementation has already been registered");
  116. return DU_E_CLASSALREADYREGISTERED;
  117. }
  118. //
  119. // Find the super
  120. //
  121. const MsgClass * pmcSuper = NULL;
  122. if ((pmcInfo->pszSuperName != NULL) && (pmcInfo->pszSuperName[0] != '\0')) {
  123. pmcSuper = GetClassLibrary()->FindClass(FindAtomW(pmcInfo->pszSuperName));
  124. if (pmcSuper == NULL) {
  125. PromptInvalid("The specified super class was not found");
  126. return DU_E_NOTFOUND;
  127. }
  128. // TODO: Remove this requirement that the Super's guts must be
  129. // registered before this class's guts can be registered.
  130. if (!pmcSuper->IsGutsRegistered()) {
  131. PromptInvalid("The super class's implementation to be registered first");
  132. return DU_E_CLASSNOTIMPLEMENTED;
  133. }
  134. }
  135. m_pmcSuper = pmcSuper;
  136. m_nVersion = pmcInfo->nClassVersion;
  137. m_pfnPromote = pmcInfo->pfnPromote;
  138. m_pfnDemote = pmcInfo->pfnDemote;
  139. //
  140. // Build the MsgTable for the new MsgClass
  141. //
  142. MsgTable * pmtNew;
  143. HRESULT hr = MsgTable::Build(pmcInfo, this, &pmtNew);
  144. if (FAILED(hr)) {
  145. return hr;
  146. }
  147. m_pmt = pmtNew;
  148. //
  149. // Return out the new MsgClass and the Super. These are used by the
  150. // caller to create instances of the object.
  151. //
  152. pmcInfo->hclNew = GetHandle();
  153. pmcInfo->hclSuper = pmcSuper != NULL ? pmcSuper->GetHandle() : NULL;
  154. //
  155. // Now that the Guts are registered, we can backfill all of the Stubs
  156. // and Supers. After this, we no longer need to store them.
  157. //
  158. int idx;
  159. int cStubs = m_arStubs.GetSize();
  160. for (idx = 0; idx < cStubs; idx++) {
  161. FillStub(m_arStubs[idx]);
  162. }
  163. m_arStubs.RemoveAll();
  164. int cSupers = m_arSupers.GetSize();
  165. for (idx = 0; idx < cSupers; idx++) {
  166. FillSuper(m_arSupers[idx]);
  167. }
  168. m_arSupers.RemoveAll();
  169. return S_OK;
  170. }
  171. /***************************************************************************\
  172. *
  173. * MsgClass::RegisterStub
  174. *
  175. * RegisterStub() starts the lookup process for a Stub. If the class is
  176. * already setup, we can fill in immediately. If the class isn't already
  177. * setup, we need to wait until it is setup and then we call post-fill-in.
  178. *
  179. \***************************************************************************/
  180. HRESULT
  181. MsgClass::RegisterStub(
  182. IN OUT DUser::MessageClassStub * pmcInfo) // Stub information to be filled in
  183. {
  184. //
  185. // NOTE: ONLY fill in the Stub if the caller is requesting the messages to
  186. // be filled in. If cMsgs == 0, they are probably just preregistering the
  187. // class (for a Super) and have allocated pmcInfo on the stack. In this
  188. // case, it is very important not to backfill it since we will trash the
  189. // memory.
  190. //
  191. if (pmcInfo->cMsgs > 0) {
  192. if (IsGutsRegistered()) {
  193. return FillStub(pmcInfo);
  194. } else {
  195. return m_arStubs.Add(pmcInfo) >= 0 ? S_OK : E_OUTOFMEMORY;
  196. }
  197. }
  198. return S_OK;
  199. }
  200. /***************************************************************************\
  201. *
  202. * MsgClass::RegisterSuper
  203. *
  204. * RegisterSuper() starts the lookup process for a Super. If the class is
  205. * already setup, we can fill in immediately. If the class isn't already
  206. * setup, we need to wait until it is setup and then we call post-fill-in.
  207. *
  208. \***************************************************************************/
  209. HRESULT
  210. MsgClass::RegisterSuper(
  211. IN OUT DUser::MessageClassSuper * pmcInfo) // Stub information to be filled in
  212. {
  213. if (IsGutsRegistered()) {
  214. FillSuper(pmcInfo);
  215. return S_OK;
  216. } else {
  217. return m_arSupers.Add(pmcInfo) >= 0 ? S_OK : E_OUTOFMEMORY;
  218. }
  219. }
  220. /***************************************************************************\
  221. *
  222. * MsgClass::xwConstructCB
  223. *
  224. * xwConstructCB() is called back by a pfnPromoteClass function to
  225. * initialize a super class's portion of a MsgObject. This allows the
  226. * specific pfnPromoteClass to decide what implementation classes to actually
  227. * implement and which to delegate.
  228. *
  229. * The caller passes in the super-class to actually construct.
  230. *
  231. \***************************************************************************/
  232. HRESULT CALLBACK
  233. MsgClass::xwConstructCB(
  234. IN DUser::Gadget::ConstructCommand cmd, // Construction code
  235. IN HCLASS hclCur, // Class being initialized
  236. IN DUser::Gadget * pgad, // Object being initialized
  237. IN void * pvData) // Construction information
  238. {
  239. //
  240. // Validate parameters.
  241. // NOTE: We NEED to check if hclSuper == NULL when passed in since this is
  242. // LEGAL (if we don't need a super-class generated).
  243. // ValidateMsgClass() will set pmcSuper == NULL if there is a
  244. // validation error.
  245. //
  246. if (hclCur == NULL) {
  247. return S_OK;
  248. }
  249. const MsgClass * pmcCur = ValidateMsgClass(hclCur);
  250. if (pmcCur == NULL) {
  251. PromptInvalid("Given invalid HCLASS during xwConstructSuperCB()");
  252. return E_INVALIDARG;
  253. }
  254. MsgObject * pmoNew = MsgObject::CastMsgObject(pgad);
  255. if (pmoNew == NULL) {
  256. return E_INVALIDARG;
  257. }
  258. HRESULT hr;
  259. switch (cmd)
  260. {
  261. case DUser::Gadget::ccSuper:
  262. //
  263. // pmcCur specifies the super-class that is being asked to build its
  264. // object.
  265. //
  266. hr = pmcCur->xwBuildUpObject(pmoNew, reinterpret_cast<DUser::Gadget::ConstructInfo *>(pvData));
  267. break;
  268. case DUser::Gadget::ccSetThis:
  269. //
  270. // pmcCur specifies the class to start filling the this pointers.
  271. //
  272. {
  273. int idxStartDepth = pmoNew->GetBuildDepth();
  274. int idxEndDepth = pmcCur->m_pmt->GetDepth();
  275. pmoNew->FillThis(idxStartDepth, idxEndDepth, pvData, pmcCur->m_pmt);
  276. hr = S_OK;
  277. }
  278. break;
  279. default:
  280. PromptInvalid("Unknown dwCode to ConstructProc()");
  281. hr = E_INVALIDARG;
  282. }
  283. return hr;
  284. }
  285. /***************************************************************************\
  286. *
  287. * MsgClass::xwBuildUpObject
  288. *
  289. * xwBuildUpObject() builds up an newly constructed MsgObject by calling
  290. * the most-derived Promotion function to initialize the MsgObject. This
  291. * Promotion function will usually callback to xwConstructCB() to
  292. * initialize base classes that are not provided in that implementation.
  293. *
  294. * As each Promotion function is called, xwBuildUpObject() will be called
  295. * from xwConstructCB() to construct the super-classes. As each Super
  296. * finishes construction, the "this array" on the MsgObject is updated.
  297. *
  298. \***************************************************************************/
  299. HRESULT
  300. MsgClass::xwBuildUpObject(
  301. IN MsgObject * pmoNew, // Object being constructed / promoted
  302. IN DUser::Gadget::ConstructInfo * pciData // Construction information
  303. ) const
  304. {
  305. //
  306. // For non-internally implemented classes, we need to callback to get the
  307. // "this" pointer to use. The callback is responsible for calling
  308. // ConstructProc(CONSTRUCT_SETTHIS) to Promote the object and set the
  309. // "this" pointers. For internally implemented classes, we use the
  310. // MsgObject to directly Promote the object.
  311. //
  312. //
  313. HRESULT hr;
  314. if (IsInternal()) {
  315. hr = S_OK;
  316. } else {
  317. //
  318. // Callback to this Super to give a chance to construct. This is done
  319. // from the most derived class and relies on callbacks to initialize
  320. // super-classes.
  321. //
  322. DUser::Gadget * pgad
  323. = pmoNew->GetGadget();
  324. HCLASS hcl = GetHandle();
  325. hr = (m_pfnPromote)(xwConstructCB, hcl, pgad, pciData);
  326. }
  327. #if DBG
  328. if (SUCCEEDED(hr)) {
  329. //
  330. // Check that the Promotion function properly set the this pointer.
  331. //
  332. int idxObjectDepth = pmoNew->GetDepth();
  333. int idxSuperDepth = m_pmt->GetDepth();
  334. if (idxObjectDepth <= idxSuperDepth) {
  335. PromptInvalid("The PromoteProc() function did not call ConstructProc(CONSTRUCT_SETTHIS).");
  336. }
  337. if (pmoNew->GetThis(idxSuperDepth) == ULongToPtr(0xA0E20000 + idxSuperDepth)) {
  338. PromptInvalid("The PromoteProc() function did not call ConstructProc(CONSTRUCT_SETTHIS).");
  339. }
  340. }
  341. #endif // DBG
  342. return hr;
  343. }
  344. /***************************************************************************\
  345. *
  346. * MsgClass::xwBuildObject
  347. *
  348. * xwBuildObject() builds and initializes a new MsgObject.
  349. *
  350. \***************************************************************************/
  351. HRESULT
  352. MsgClass::xwBuildObject(
  353. OUT MsgObject ** ppmoNew, // New MsgObject
  354. IN DUser::Gadget::ConstructInfo * pciData // Construction information
  355. ) const
  356. {
  357. //
  358. // Allocate a new object:
  359. // 1. Walk up the inheritance chain to determine the DUser object to build
  360. // that will provide MsgObject functionality.
  361. // 2. While walking up, Verify that the guts of all classes have been
  362. // properly registered.
  363. // 3. Kick off the build-up process.
  364. //
  365. HRESULT hr;
  366. MsgObject * pmoNew = NULL;
  367. const MsgClass * pmcInternal = this;
  368. while (pmcInternal != NULL) {
  369. if (!pmcInternal->IsGutsRegistered()) {
  370. PromptInvalid("The implementation of the specified class has not been provided");
  371. return DU_E_CLASSNOTIMPLEMENTED;
  372. }
  373. if (pmcInternal->IsInternal()) {
  374. AssertMsg(pmoNew == NULL, "Must be NULL for internal Promote() functions");
  375. hr = (pmcInternal->m_pfnPromote)(NULL, pmcInternal->GetHandle(), (DUser::Gadget *) &pmoNew, pciData);
  376. if (FAILED(hr)) {
  377. return E_OUTOFMEMORY;
  378. }
  379. AssertMsg(pmoNew != NULL, "Internal objects must fill in the MsgObject");
  380. AssertMsg(pmoNew->GetHandleType() != htNone, "Must have a valid handle type");
  381. break;
  382. }
  383. pmcInternal = pmcInternal->GetSuper();
  384. }
  385. if (pmoNew == NULL) {
  386. AssertMsg(pmcInternal == NULL, "Internal classes must have already allocated the MsgObject");
  387. pmoNew = ClientNew(MsgObject);
  388. if (pmoNew == NULL) {
  389. return E_OUTOFMEMORY;
  390. }
  391. }
  392. hr = pmoNew->PreAllocThis(m_pmt->GetDepth() + 1);
  393. if (FAILED(hr)) {
  394. goto Error;
  395. }
  396. if (pmcInternal != NULL) {
  397. int cObjectDepth = pmcInternal->m_pmt->GetDepth();
  398. pmoNew->FillThis(0, cObjectDepth, pmoNew, pmcInternal->m_pmt);
  399. }
  400. hr = xwBuildUpObject(pmoNew, pciData);
  401. if (FAILED(hr)) {
  402. goto Error;
  403. }
  404. *ppmoNew = pmoNew;
  405. return S_OK;
  406. Error:
  407. if (pmoNew != NULL) {
  408. xwTearDownObject(pmoNew);
  409. }
  410. return hr;
  411. }
  412. /***************************************************************************\
  413. *
  414. * MsgClass::xwTearDownObject
  415. *
  416. * xwTearDownObject() tears down a MsgObject as part of the destruction
  417. * process. This gives each of the implentation classes an opportunity to
  418. * cleanup resources, similar to having a destructor in C++.
  419. *
  420. \***************************************************************************/
  421. void
  422. MsgClass::xwTearDownObject(
  423. IN MsgObject * pmoNew // Object being destroyed.
  424. ) const
  425. {
  426. DUser::Gadget * pgad
  427. = pmoNew->GetGadget();
  428. int idxThis = m_pmt->GetDepth();
  429. const MsgClass * pmcCur = this;
  430. const MsgClass * pmcNext, * pmcTest;
  431. while (pmcCur != NULL) {
  432. HCLASS hcl = pmcCur->GetHandle();
  433. void * pvThis = pmoNew->GetThis(idxThis);
  434. hcl = (pmcCur->m_pfnDemote)(hcl, pgad, pvThis);
  435. //
  436. // Determine how many class to remove by how far up the chain this
  437. // MsgClass is.
  438. // - TODO: Need to check that returned class is actually in the chain.
  439. //
  440. pmcNext = ValidateMsgClass(hcl);
  441. if ((hcl != NULL) && (pmcNext == NULL)) {
  442. PromptInvalid("Incorrect HCLASS returned from Demote function. Object will not be properly destroyed.");
  443. }
  444. pmcTest = pmcCur;
  445. int cDepth = 0;
  446. while ((pmcTest != NULL) && (pmcTest != pmcNext)) {
  447. cDepth++;
  448. pmcTest = pmcTest->m_pmcSuper;
  449. }
  450. pmoNew->Demote(cDepth);
  451. idxThis -= cDepth;
  452. pmcCur = pmcNext;
  453. }
  454. }
  455. /***************************************************************************\
  456. *
  457. * MsgClass::FillStub
  458. *
  459. * FillStub() provides the calling stub with information about a previously
  460. * registered MsgClass.
  461. *
  462. \***************************************************************************/
  463. HRESULT
  464. MsgClass::FillStub(
  465. IN OUT DUser::MessageClassStub * pmcInfo // Stub information to be filled in
  466. ) const
  467. {
  468. HRESULT hr = S_OK;
  469. ATOM atomMsg;
  470. int idxSlot;
  471. int cbBeginOffset = sizeof(MsgTable);
  472. DUser::MessageInfoStub * rgMsgInfo = pmcInfo->rgMsgInfo;
  473. int cMsgs = pmcInfo->cMsgs;
  474. for (int idx = 0; idx < cMsgs; idx++) {
  475. if (((atomMsg = FindAtomW(rgMsgInfo[idx].pszMsgName)) == 0) ||
  476. ((idxSlot = m_pmt->FindIndex(atomMsg)) < 0)) {
  477. //
  478. // Could not find the function, so store a -1 to signal that this
  479. // slot with the error.
  480. //
  481. PromptInvalid("Unable to find message during lookup");
  482. hr = DU_E_MESSAGENOTFOUND;
  483. rgMsgInfo[idx].cbSlotOffset = -1;
  484. } else {
  485. //
  486. // Successfully found the function. We need to store the offset
  487. // to the slot so that it can be directly accessed without any math
  488. // or special knowledge of our internals.
  489. //
  490. int cbSlotOffset = idxSlot * sizeof(MsgSlot) + cbBeginOffset;
  491. rgMsgInfo[idx].cbSlotOffset = cbSlotOffset;
  492. }
  493. }
  494. return hr;
  495. }
  496. /***************************************************************************\
  497. *
  498. * MsgClass::FillSuper
  499. *
  500. * FillStub() provides the calling super with information about a previously
  501. * registered MsgClass.
  502. *
  503. \***************************************************************************/
  504. void
  505. MsgClass::FillSuper(
  506. IN OUT DUser::MessageClassSuper * pmcInfo // Super information to be filled in
  507. ) const
  508. {
  509. pmcInfo->pmt = m_pmt;
  510. }