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.

1261 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: COMLOCAL.CXX (16 bit target)
  7. //
  8. // Contents: CompObj APIs
  9. //
  10. // Functions:
  11. //
  12. // History: 16-Dec-93 JohannP Created
  13. //
  14. //--------------------------------------------------------------------------
  15. #include <headers.cxx>
  16. #pragma hdrstop
  17. #include <ole2ver.h>
  18. #include <ole2sp.h>
  19. #include <olecoll.h>
  20. #include <map_kv.h>
  21. #include "comlocal.hxx"
  22. #include "map_htsk.h"
  23. #include "etask.hxx"
  24. #include "call32.hxx"
  25. #include "apilist.hxx"
  26. UINT v_pidHighWord = 1; // incremented each time used
  27. IMalloc FAR* v_pMallocShared = NULL; // is not addrefed
  28. // Note: bug 3698
  29. // MsPub is not calling CoInitialize befor calling OpenStorage to
  30. // preview templates. This pointer has an addref!
  31. // When this pointer is not NULL CoGetMalloc was called prior to CoInitialize
  32. // The pointer is transfered as soon as CoInitialize is called by any task.
  33. IMalloc FAR* v_pMallocPreShared = NULL;
  34. BOOL SetupSharedAllocator(Etask FAR& etask);
  35. //+---------------------------------------------------------------------------
  36. //
  37. // Function: TaskAlloc, private
  38. //
  39. // Synopsis: Allocates task memory
  40. //
  41. // Arguments: [cb] - Number of bytes to allocate
  42. //
  43. // Returns: Pointer to memory or NULL
  44. //
  45. // History: 03-Mar-94 DrewB Created
  46. //
  47. //----------------------------------------------------------------------------
  48. LPVOID __loadds FAR PASCAL TaskAlloc(ULONG cb)
  49. {
  50. HRESULT hr;
  51. LPMALLOC lpMalloc = NULL;
  52. LPVOID lpv;
  53. hr = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
  54. if (FAILED(GetScode(hr)) )
  55. {
  56. lpv = NULL;
  57. }
  58. else
  59. {
  60. thkAssert(lpMalloc != NULL && "CoGetMalloc pMalloce is NULL\n");
  61. lpv = lpMalloc->Alloc(cb);
  62. lpMalloc->Release();
  63. }
  64. return lpv;
  65. }
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Function: TaskFree, private
  69. //
  70. // Synopsis: Free task memory
  71. //
  72. // Arguments: [pv] - Memory
  73. //
  74. // History: 03-Mar-94 DrewB Created
  75. //
  76. //----------------------------------------------------------------------------
  77. void __loadds FAR PASCAL TaskFree(LPVOID pv)
  78. {
  79. HRESULT hr;
  80. LPMALLOC lpMalloc;
  81. hr = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
  82. if (SUCCEEDED(GetScode(hr)))
  83. {
  84. lpMalloc->Free(pv);
  85. lpMalloc->Release();
  86. }
  87. }
  88. #if defined(_CHICAGO_)
  89. //+---------------------------------------------------------------------------
  90. //
  91. // Function: IsProcessIn32Context, private
  92. //
  93. // Synopsis: Returns true if current process is 32-bits.
  94. //
  95. // Arguments: None.
  96. //
  97. // History: 03-Jan-95 KentCe Created
  98. //
  99. // Remarks: This function takes advantage of internal Chicago data
  100. // structures. No other method available.
  101. //
  102. //----------------------------------------------------------------------------
  103. BOOL IsProcessIn32Context(void)
  104. {
  105. LPBYTE pTaskFlag;
  106. //
  107. // Create a pointer to the 0x16 byte of the task structure.
  108. //
  109. pTaskFlag = (LPBYTE)MAKELONG(0x16, GetCurrentTask());
  110. //
  111. // Bit 4 (0x10) is only true when we are a 32-bit process.
  112. //
  113. if (*pTaskFlag & 0x10)
  114. return TRUE;
  115. return FALSE;
  116. }
  117. #endif
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Method: SetupSharedAllocator
  121. //
  122. // Synopsis: Allocats the shared allocator and
  123. // initializes the etask shared allocator
  124. //
  125. // Arguments: [etask] --
  126. //
  127. // Returns:
  128. //
  129. // History: 2-03-95 JohannP (Johann Posch) Created
  130. //
  131. // Notes: call by CoInitialize and DllEntryPoint
  132. //
  133. //----------------------------------------------------------------------------
  134. BOOL SetupSharedAllocator(Etask FAR& etask)
  135. {
  136. // we must ensure we have a shared allocator now since that is where the
  137. // etask map wiil be stored; if another process already created it, use it;
  138. // this is so we always use the same shared pool of memory for all
  139. // processes (so the DidAlloc method returns 1 for the same call from
  140. // different process); the pointer refers to shared memory within
  141. // the blocks managed by the IMalloc implementation and the
  142. // vtable is always valid on Windows; the global pointer carries
  143. // no ref count on its own; changes might be requires on
  144. // other platforms.
  145. if (v_pMallocPreShared != NULL)
  146. {
  147. // Note: fix for bug 3698;l MsPub not calling CoInitialize
  148. // transfer addref from preshared to task entry
  149. etask.m_pMallocShared = v_pMallocPreShared;
  150. v_pMallocShared = v_pMallocPreShared;
  151. v_pMallocPreShared = NULL;
  152. }
  153. else if (v_pMallocShared != NULL)
  154. {
  155. (etask.m_pMallocShared = v_pMallocShared)->AddRef();
  156. }
  157. else
  158. {
  159. // sets pMalloc to NULL on error
  160. CoCreateStandardMalloc(MEMCTX_SHARED, &etask.m_pMallocShared);
  161. v_pMallocShared = etask.m_pMallocShared;
  162. thkAssert(v_pMallocShared != NULL && "SetupSharedAllocator failed!");
  163. }
  164. return (v_pMallocShared != NULL) ? TRUE : FALSE;
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Function: CoInitialize, Split
  169. //
  170. // Synopsis:
  171. //
  172. // Effects:
  173. //
  174. // Arguments: [pMalloc] --
  175. //
  176. // Requires:
  177. //
  178. // Returns:
  179. //
  180. // Signals:
  181. //
  182. // Modifies:
  183. //
  184. // Algorithm:
  185. //
  186. // History: 2-28-94 kevinro Created
  187. // 3-08-94 BobDay Added code from \\ole\slm\...\compobj.cpp
  188. //
  189. // Notes:
  190. //
  191. //----------------------------------------------------------------------------
  192. // initialize compobj; errors: S_FALSE, E_OUTOFMEMORY
  193. STDAPI CoInitialize(IMalloc FAR* pMalloc)
  194. {
  195. LPMALLOC pmlNull = NULL;
  196. HRESULT hresult;
  197. HTASK htask;
  198. Etask etask;
  199. thkDebugOut((DEB_ITRACE, "CoInitialize\n"));
  200. thkDebugOut((DEB_APIS16, "CoInitilaize called on Process (%X) \n", GetCurrentProcess()));
  201. #if defined(_CHICAGO_)
  202. //
  203. // Prevent 32-bit MPLAYER from loading a 16-bit DLL's which in turns
  204. // uses 16-bit OLE2. We can't handle the condition of a 32-bit process
  205. // thunking up thru the 16:32 OLE2 interop layer. So return an error
  206. // and not fault out.
  207. //
  208. if (IsProcessIn32Context())
  209. return ResultFromScode(E_OUTOFMEMORY);
  210. etask.m_Dllinits = 0;
  211. #endif
  212. // if already init, bump count and return S_FALSE
  213. if ( IsEtaskInit(htask, etask)
  214. && IsValidInterface((etask.m_pMalloc)) )
  215. {
  216. if ( etask.m_inits != ETASK_FAKE_INIT )
  217. {
  218. etask.m_inits++;
  219. thkVerify(SetEtask(htask, etask));
  220. return ResultFromScode(S_FALSE);
  221. }
  222. //
  223. // CoInitialize has been called after we've done a fake call for them
  224. // we can just take over their allocator and get rid of our fake one.
  225. //
  226. if ( pMalloc != NULL )
  227. {
  228. etask.m_pMalloc->Release(); // Get rid of the old task allocator
  229. etask.m_pMalloc = pMalloc;
  230. etask.m_pMalloc->AddRef();
  231. }
  232. else
  233. {
  234. //
  235. // It would be nice if we could assert that the fake task
  236. // allocator was a default task allocator. i.e. no operation
  237. // were really needed!
  238. //
  239. }
  240. //
  241. // "We need to have a way to clean up any fake calls to
  242. // CoInitialize. Should the application go away after using one of
  243. // the apis that caused us to do a fake CoInitialize in the first
  244. // place, and should the application exit without really making a
  245. // call to CoInitialize eventually, then we wouldn't know enough to
  246. // clean up... I think this is ok for now. Most apps do call
  247. // CoInitialize eventually."
  248. //
  249. etask.m_inits = 1;
  250. thkAssert(etask.m_pMalloc != NULL); // now have task allocator in all cases
  251. thkVerify(SetEtask(htask, etask));
  252. return ResultFromScode(S_OK);
  253. }
  254. #ifdef _CHICAGO_
  255. else if (etask.m_Dllinits == 0)
  256. {
  257. // Note: we might end up here since some app call
  258. // CoInitialize in LibMain. The call to our DllEntryPoint
  259. // will follow.
  260. if (!Call32Initialize())
  261. {
  262. return ResultFromScode(E_OUTOFMEMORY);
  263. }
  264. etask.m_htask = GetCurrentProcess();
  265. }
  266. #endif
  267. // set/create task malloc
  268. if (pMalloc != NULL)
  269. {
  270. VDATEIFACE( pMalloc );
  271. (etask.m_pMalloc = pMalloc)->AddRef();
  272. }
  273. else
  274. {
  275. if ((hresult = CoCreateStandardMalloc(MEMCTX_TASK,
  276. &etask.m_pMalloc)) != NOERROR)
  277. return hresult;
  278. }
  279. thkAssert(etask.m_pMalloc != NULL); // now have task allocator in all cases
  280. // set up the shared allocator
  281. if ( etask.m_pMallocShared == NULL
  282. && SetupSharedAllocator(etask) == FALSE)
  283. {
  284. etask.m_pMalloc->Release(); // was created or AddRef'd above
  285. return ResultFromScode(E_OUTOFMEMORY);
  286. }
  287. // now have shared allocator in all cases
  288. thkAssert(etask.m_pMallocShared != NULL);
  289. // init remaining entries and add entry to table for this app/task pair;
  290. // leave maps null for now (they are allocated on demand)
  291. etask.m_pMallocSBlock = NULL;
  292. etask.m_pMallocPrivate = NULL;
  293. etask.m_pid = MAKELONG(GetCurrentProcess(),v_pidHighWord++);
  294. etask.m_inits = 1;
  295. etask.m_oleinits = 0;
  296. etask.m_reserved = 0;
  297. etask.m_pDlls = NULL;
  298. etask.m_pMapToServerCO = NULL;
  299. etask.m_pMapToHandlerCO = NULL;
  300. etask.m_pArraySH = NULL;
  301. etask.m_pCThrd = NULL;
  302. etask.m_hwndClip = NULL;
  303. etask.m_hwndDde = NULL;
  304. etask.m_punkState = NULL;
  305. if (!SetEtask(htask, etask))
  306. {
  307. ReleaseEtask(NULL, etask);
  308. thkAssert(0 && "CompObj: CoInitialize SetEtask failed.");
  309. return ResultFromScode(E_OUTOFMEMORY);
  310. }
  311. // Initialize the thunk manager for this apartment.
  312. if (SUCCEEDED(hresult = CallThkMgrInitialize()))
  313. {
  314. //
  315. // Now transition into 32-bit world to give it a chance for
  316. // initialization at this time.
  317. //
  318. // Never pass the 16-bit allocator on to 32-bits
  319. pMalloc = NULL;
  320. hresult = (HRESULT)CallObjectInWOW(THK_API_METHOD(THK_API_CoInitialize),
  321. PASCAL_STACK_PTR(pMalloc) );
  322. }
  323. if (FAILED(GetScode(hresult)))
  324. {
  325. ReleaseEtask(htask, etask);
  326. }
  327. return hresult;
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Function: CoUninitialize, Split
  332. //
  333. // Synopsis:
  334. //
  335. // Effects:
  336. //
  337. // Arguments: [void] --
  338. //
  339. // Requires:
  340. //
  341. // Returns:
  342. //
  343. // Signals:
  344. //
  345. // Modifies:
  346. //
  347. // Algorithm:
  348. //
  349. // History: 2-28-94 kevinro Created
  350. // 10-Mar-94 BobDay Copied & Merged with compobj.cpp 16-bit
  351. //
  352. // Notes:
  353. //
  354. //----------------------------------------------------------------------------
  355. STDAPI_(void) CoUninitialize(void)
  356. {
  357. HTASK htask;
  358. Etask etask;
  359. thkDebugOut((DEB_ITRACE, "CoUninitialize\n"));
  360. thkDebugOut((DEB_APIS16, "CoUninitilaize called on Process (%X) \n", GetCurrentProcess()));
  361. if (!IsEtaskInit(htask, etask))
  362. return;
  363. // if not last uninit, just decrement count and return.
  364. if (etask.m_inits != 1)
  365. {
  366. //
  367. // If a fake init, then just ignore as if we haven't ever init'd
  368. //
  369. if ( etask.m_inits == ETASK_FAKE_INIT )
  370. {
  371. //
  372. // Some slimy app doesn't call CoInitialize but does eventually
  373. // call CoUninitialize. Lets find them if they do!
  374. //
  375. thkAssert(FALSE &&
  376. "CoUninitialize called after fake CoInitialize\n");
  377. }
  378. else
  379. {
  380. etask.m_inits--;
  381. thkVerify(SetEtask(htask, etask));
  382. }
  383. return ;
  384. }
  385. // Some applications pass on module handle of loaded dlls.
  386. // As a result LibMain and WEP is not called in the same process.
  387. // To prevent premature unloading of OleThk32.dll call
  388. // SetReleaseDLL(FALSE)
  389. SetReleaseDLL(FALSE);
  390. //
  391. // Now transition into 32-bit world to give it a chance for
  392. // initialization at this time.
  393. //
  394. CallObjectInWOW(THK_API_METHOD(THK_API_CoUninitialize), NULL );
  395. // Reset dll unloading - see above
  396. SetReleaseDLL(TRUE);
  397. CoFreeAllLibraries();
  398. //
  399. // We do not uninitialize the thunk manager at this point. The app may attempt
  400. // to call additional API's after CoUninitialize. For example, Lotus 1-2-3
  401. // is known to do this, as is Publisher. The thunk manager will clean up
  402. // as part of its thread detach.
  403. //
  404. // the last thing is to remove the allocator and delete the etask for us;
  405. // must lookup again in case contents changed.
  406. if (LookupEtask(htask, etask))
  407. ReleaseEtask(htask, etask);
  408. thkDebugOut((DEB_APIS16, "CoUninitilaize on Process (%X) done.\n", GetCurrentProcess()));
  409. thkDebugOut((DEB_ITRACE, "CoUninitialize exit\n"));
  410. // Note: some apps check the return value if the void function CoUninitialize
  411. // and they fail if it is not NULL like WinOffice Setup 4.3
  412. // Please don't take it out.
  413. _asm mov ax,0;
  414. _asm mov dx,0;
  415. }
  416. //+---------------------------------------------------------------------------
  417. //
  418. // Function: CoGetMalloc, Local
  419. //
  420. // Synopsis:
  421. //
  422. // Effects:
  423. //
  424. // Arguments: [dwMemContext] --
  425. // [ppMalloc] --
  426. //
  427. // Requires:
  428. //
  429. // Returns:
  430. //
  431. // Signals:
  432. //
  433. // Modifies:
  434. //
  435. // Algorithm:
  436. //
  437. // History: 2-28-94 kevinro Created
  438. // 10-Mar-94 BobDay Copied & Merged with compobj.cpp 16-bit
  439. //
  440. // Notes:
  441. //
  442. //----------------------------------------------------------------------------
  443. // return pMalloc for the current task; errors: E_INVALIDARG,
  444. // CO_E_NOTINITIALIZED, E_OUTOFMEMORY (not for task or shared allocators)
  445. STDAPI CoGetMalloc(DWORD dwContext, IMalloc FAR* FAR* ppMalloc)
  446. {
  447. Etask etask;
  448. HTASK htask;
  449. thkDebugOut((DEB_ITRACE, " CoGetMalloc\n"));
  450. VDATEPTROUT( ppMalloc, IMalloc FAR* );
  451. // NOTE: we set *ppMalloc to NULL only in the error cases below
  452. // MOre work here!
  453. // need this for the bootstrap case
  454. if (dwContext == MEMCTX_SHARED)
  455. {
  456. if (v_pMallocShared != NULL)
  457. {
  458. *ppMalloc = v_pMallocShared;
  459. goto Exit;
  460. }
  461. // pMallocShared is NULL -- CoInitialize was not called yet.
  462. if (v_pMallocPreShared == NULL)
  463. {
  464. CoCreateStandardMalloc(MEMCTX_SHARED, &v_pMallocPreShared);
  465. if (v_pMallocPreShared != NULL)
  466. {
  467. *ppMalloc = v_pMallocPreShared;
  468. goto Exit;
  469. }
  470. else
  471. {
  472. *ppMalloc = NULL;
  473. return ResultFromScode(CO_E_NOTINITIALIZED);
  474. }
  475. }
  476. else
  477. {
  478. *ppMalloc = v_pMallocPreShared;
  479. goto Exit;
  480. }
  481. }
  482. //
  483. // Clip Art Gallery will call pStream->Stat before calling CoInitialize.
  484. // This causes the thunk logic to allocation 16bit memory which will
  485. // fail at this point. The below code to auto-initialize should this
  486. // happen. (Really just a hack for Clip Art Gallery).
  487. //
  488. if ( !IsEtaskInit(htask, etask)
  489. || !IsValidInterface((etask.m_pMalloc)) )
  490. {
  491. if (FAILED(CoInitialize(NULL)))
  492. {
  493. *ppMalloc = NULL;
  494. return ResultFromScode(CO_E_NOTINITIALIZED);
  495. }
  496. thkVerify(LookupEtask( htask, etask ));
  497. etask.m_inits = ETASK_FAKE_INIT;
  498. thkVerify(SetEtask(htask, etask));
  499. }
  500. // shared always available if initialized; no need to handle here
  501. thkAssert(dwContext != MEMCTX_SHARED);
  502. if (dwContext == MEMCTX_TASK)
  503. {
  504. thkAssert(etask.m_pMalloc != NULL);
  505. *ppMalloc = etask.m_pMalloc;
  506. }
  507. else
  508. {
  509. #ifdef NOTYET
  510. // contexts which are delay-created
  511. IMalloc FAR* FAR* ppMallocStore;
  512. if (dwContext == MEMCTX_SHAREDBLOCK)
  513. ppMallocStore = &etask.m_pMallocSBlock;
  514. else if (dwContext == MEMCTX_COPRIVATE)
  515. ppMallocStore = &etask.m_pMallocPrivate;
  516. else
  517. {
  518. // invalid context
  519. *ppMalloc = NULL;
  520. return ResultFromScode(E_INVALIDARG);
  521. }
  522. if (*ppMallocStore == NULL)
  523. {
  524. // sets pMalloc to NULL on error
  525. if (CoCreateStandardMalloc(dwContext, ppMallocStore) != NOERROR)
  526. {
  527. *ppMalloc = NULL;
  528. return ResultFromScode(E_OUTOFMEMORY);
  529. }
  530. thkVerify(SetEtask(htask, etask));
  531. }
  532. *ppMalloc = *ppMallocStore;
  533. #else
  534. // invalid context
  535. thkAssert(!"Unknown memctx in CoGetMalloc");
  536. *ppMalloc = NULL;
  537. return ResultFromScode(E_INVALIDARG);
  538. #endif // NOTYET
  539. }
  540. Exit: // have non-null *ppMalloc
  541. thkAssert(*ppMalloc != NULL);
  542. (*ppMalloc)->AddRef();
  543. return NOERROR;
  544. }
  545. //+---------------------------------------------------------------------------
  546. //
  547. // Function: CoGetState, Local
  548. //
  549. // Synopsis: Retrieves task-specific state
  550. //
  551. // Arguments: [ppunk] - IUnknown pointer to fill in
  552. //
  553. // Returns: Appropriate status code
  554. //
  555. // History: 26-Jul-94 DrewB Created
  556. //
  557. // Notes: Private API for OLE automation
  558. //
  559. //----------------------------------------------------------------------------
  560. STDAPI CoGetState(IUnknown FAR * FAR *ppunk)
  561. {
  562. Etask etask;
  563. HTASK htask;
  564. thkDebugOut((DEB_APIS16, "CoGetState called\n"));
  565. if (IsBadWritePtr(ppunk, sizeof(IUnknown *)))
  566. {
  567. thkDebugOut((DEB_APIS16, "CoGetState failed\n"));
  568. return ResultFromScode(E_INVALIDARG);
  569. }
  570. if (!LookupEtask(htask, etask) || etask.m_punkState == NULL )
  571. {
  572. *ppunk = NULL;
  573. thkDebugOut((DEB_APIS16, "CoGetState failed\n"));
  574. return ResultFromScode(S_FALSE);
  575. }
  576. if ( !IsValidInterface((etask.m_punkState)) )
  577. {
  578. *ppunk = NULL;
  579. etask.m_punkState = NULL;
  580. thkDebugOut((DEB_APIS16, "CoGetState failed (invalid interface)\n"));
  581. return ResultFromScode(S_FALSE);
  582. }
  583. *ppunk = etask.m_punkState;
  584. etask.m_punkState->AddRef();
  585. thkDebugOut((DEB_APIS16, "CoGetState done %p\n", *ppunk));
  586. return NOERROR;
  587. }
  588. //+---------------------------------------------------------------------------
  589. //
  590. // Function: CoSetState, Local
  591. //
  592. // Synopsis: Sets task-specific state
  593. //
  594. // Arguments: [punk] - State to set
  595. //
  596. // Returns: Appropriate status code
  597. //
  598. // History: 26-Jul-94 DrewB Created
  599. //
  600. // Notes: Private API for OLE automation
  601. //
  602. //----------------------------------------------------------------------------
  603. STDAPI CoSetState(IUnknown FAR *punk)
  604. {
  605. Etask etask;
  606. HTASK htask;
  607. IUnknown FAR *punkStateOld;
  608. thkDebugOut((DEB_APIS16, "CoSetState called %p\n", punk));
  609. if (punk != NULL && !IsValidInterface(punk))
  610. {
  611. thkDebugOut((DEB_APIS16, "CoSetState called %p failed\n", punk));
  612. return ResultFromScode(E_INVALIDARG);
  613. }
  614. if (!IsEtaskInit(htask, etask))
  615. {
  616. thkDebugOut((DEB_APIS16, "CoSetState called %p failed\n", punk));
  617. return ResultFromScode(S_FALSE);
  618. }
  619. if (punk != NULL)
  620. {
  621. punk->AddRef();
  622. }
  623. punkStateOld = etask.m_punkState;
  624. etask.m_punkState = punk;
  625. thkVerify(SetEtask(htask, etask));
  626. if (punkStateOld != NULL && IsValidInterface(punkStateOld))
  627. {
  628. punkStateOld->Release();
  629. }
  630. thkDebugOut((DEB_APIS16, "CoSetState called %p done\n", punk));
  631. return NOERROR;
  632. }
  633. //+---------------------------------------------------------------------------
  634. //
  635. // Function: CoGetCurrentProcess, Local
  636. //
  637. //----------------------------------------------------------------------------
  638. // returns a unique value for the current task; this routine is
  639. // necessary because htask values from Window get reused periodically.
  640. STDAPI_(DWORD) CoGetCurrentProcess(void)
  641. {
  642. HTASK htask;
  643. Etask etask;
  644. thkDebugOut((DEB_ITRACE, " CoGetCurrentProcess\n"));
  645. if (!IsEtaskInit(htask, etask))
  646. return 0;
  647. return etask.m_pid;
  648. }
  649. //+---------------------------------------------------------------------------
  650. //
  651. // Function: CoBuildVersion, Local
  652. //
  653. //----------------------------------------------------------------------------
  654. STDAPI_(DWORD) CoBuildVersion(VOID)
  655. {
  656. thkDebugOut((DEB_ITRACE, " CoBuildVersion\n"));
  657. // We must return 23 as our major version number to remain
  658. // compatible with shipped OLE 2.01
  659. // OLE 2.01 shipped with minor version 640
  660. // We return a number slightly higher to differentiate
  661. // our product while indicating compatibility
  662. return MAKELONG(700, 23);
  663. }
  664. //+---------------------------------------------------------------------------
  665. //
  666. // Function: CoMarshalHresult, Local
  667. //
  668. // History: Taken straight from OLE2 sources
  669. //
  670. //----------------------------------------------------------------------------
  671. STDAPI CoMarshalHresult(LPSTREAM pstm, HRESULT hresult)
  672. {
  673. HRESULT hr;
  674. thkDebugOut((DEB_ITRACE, "CoMarshalHresult\n"));
  675. if (!IsValidInterface(pstm))
  676. {
  677. hr = ResultFromScode(E_INVALIDARG);
  678. }
  679. else
  680. {
  681. SCODE sc;
  682. ULONG cb;
  683. sc = GetScode(hresult);
  684. hr = pstm->Write(&sc, sizeof(sc), &cb);
  685. if (SUCCEEDED(GetScode(hr)) && cb != sizeof(sc))
  686. {
  687. hr = ResultFromScode(STG_E_WRITEFAULT);
  688. }
  689. }
  690. return hr;
  691. }
  692. //+---------------------------------------------------------------------------
  693. //
  694. // Function: CoUnmarshalHresult, Local
  695. //
  696. // History: Taken straight from OLE2 sources
  697. //
  698. //----------------------------------------------------------------------------
  699. STDAPI CoUnmarshalHresult(LPSTREAM pstm, HRESULT FAR * phresult)
  700. {
  701. HRESULT hr;
  702. thkDebugOut((DEB_ITRACE, "CoUnmarshalHresult\n"));
  703. if (!IsValidPtrOut(phresult, sizeof(HRESULT)))
  704. {
  705. hr = ResultFromScode(E_INVALIDARG);
  706. }
  707. else
  708. {
  709. *phresult = 0;
  710. if (!IsValidInterface(pstm))
  711. {
  712. hr = ResultFromScode(E_INVALIDARG);
  713. }
  714. else
  715. {
  716. SCODE sc;
  717. ULONG cb;
  718. hr = pstm->Read(&sc, sizeof(sc), &cb);
  719. if (SUCCEEDED(GetScode(hr)))
  720. {
  721. if (cb != sizeof(sc))
  722. {
  723. hr = ResultFromScode(STG_E_READFAULT);
  724. }
  725. else
  726. {
  727. *phresult = ResultFromScode(sc);
  728. }
  729. }
  730. }
  731. }
  732. return hr;
  733. }
  734. //+---------------------------------------------------------------------------
  735. //
  736. // Function: IsEqualGUID, Local
  737. //
  738. // History: Taken straight from OLE2 sources
  739. //
  740. //----------------------------------------------------------------------------
  741. #pragma intrinsic(_fmemcmp)
  742. STDAPI_(BOOL) IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
  743. {
  744. //thkDebugOut((DEB_ITRACE, "IsEqualGUID\n"));
  745. return !_fmemcmp(&rguid1, &rguid2, sizeof(GUID));
  746. }
  747. #pragma function(_fmemcmp)
  748. #define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Function: HexStringToDword, private
  752. //
  753. // History: Straight from OLE2 sources
  754. //
  755. //----------------------------------------------------------------------------
  756. static BOOL HexStringToDword(LPCSTR FAR& lpsz, DWORD FAR& Value, int cDigits,
  757. char chDelim)
  758. {
  759. int Count;
  760. Value = 0;
  761. for (Count = 0; Count < cDigits; Count++, lpsz++)
  762. {
  763. if (*lpsz >= '0' && *lpsz <= '9')
  764. {
  765. Value = (Value << 4) + *lpsz - '0';
  766. }
  767. else if (*lpsz >= 'A' && *lpsz <= 'F')
  768. {
  769. Value = (Value << 4) + *lpsz - 'A' + 10;
  770. }
  771. else if (*lpsz >= 'a' && *lpsz <= 'f')
  772. {
  773. Value = (Value << 4) + *lpsz - 'a' + 10;
  774. }
  775. else
  776. {
  777. return(FALSE);
  778. }
  779. }
  780. if (chDelim != 0)
  781. {
  782. return *lpsz++ == chDelim;
  783. }
  784. else
  785. {
  786. return TRUE;
  787. }
  788. }
  789. //+---------------------------------------------------------------------------
  790. //
  791. // Function: GUIDFromString, private
  792. //
  793. // History: Straight from OLE2 sources
  794. //
  795. //----------------------------------------------------------------------------
  796. STDAPI_(BOOL) GUIDFromString(LPCSTR lpsz, LPGUID pguid)
  797. {
  798. DWORD dw;
  799. if (*lpsz++ != '{')
  800. return FALSE;
  801. if (!HexStringToDword(lpsz, pguid->Data1, sizeof(DWORD)*2, '-'))
  802. return FALSE;
  803. if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
  804. return FALSE;
  805. pguid->Data2 = (WORD)dw;
  806. if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
  807. return FALSE;
  808. pguid->Data3 = (WORD)dw;
  809. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  810. return FALSE;
  811. pguid->Data4[0] = (BYTE)dw;
  812. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '-'))
  813. return FALSE;
  814. pguid->Data4[1] = (BYTE)dw;
  815. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  816. return FALSE;
  817. pguid->Data4[2] = (BYTE)dw;
  818. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  819. return FALSE;
  820. pguid->Data4[3] = (BYTE)dw;
  821. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  822. return FALSE;
  823. pguid->Data4[4] = (BYTE)dw;
  824. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  825. return FALSE;
  826. pguid->Data4[5] = (BYTE)dw;
  827. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
  828. return FALSE;
  829. pguid->Data4[6] = (BYTE)dw;
  830. if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '}'))
  831. return FALSE;
  832. pguid->Data4[7] = (BYTE)dw;
  833. return TRUE;
  834. }
  835. //+---------------------------------------------------------------------------
  836. //
  837. // Function: StringFromCLSID, Local
  838. //
  839. // History: Straight from OLE2 sources
  840. //
  841. //----------------------------------------------------------------------------
  842. #define CLSIDSTR_MAX (GUIDSTR_MAX)
  843. STDAPI StringFromCLSID(REFCLSID rclsid, LPSTR FAR* lplpsz)
  844. {
  845. SCODE sc;
  846. char *psz;
  847. thkDebugOut((DEB_ITRACE, "StringFromCLSID\n"));
  848. psz = NULL;
  849. do
  850. {
  851. if (!IsValidPtrOut(lplpsz, sizeof(LPSTR)))
  852. {
  853. sc = E_INVALIDARG;
  854. break;
  855. }
  856. *lplpsz = NULL;
  857. if (!IsValidPtrIn(&rclsid, sizeof(CLSID)))
  858. {
  859. sc = E_INVALIDARG;
  860. break;
  861. }
  862. psz = (char *)TaskAlloc(CLSIDSTR_MAX);
  863. if (psz == NULL)
  864. {
  865. sc = E_OUTOFMEMORY;
  866. break;
  867. }
  868. if (StringFromGUID2(rclsid, psz, CLSIDSTR_MAX) == 0)
  869. {
  870. sc = E_INVALIDARG;
  871. TaskFree(psz);
  872. break;
  873. }
  874. *lplpsz = psz;
  875. sc = S_OK;
  876. } while (FALSE);
  877. return ResultFromScode(sc);
  878. }
  879. //+---------------------------------------------------------------------------
  880. //
  881. // Function: StringFromIID, Local
  882. //
  883. // History: Straight from OLE2 sources
  884. //
  885. //----------------------------------------------------------------------------
  886. STDAPI StringFromIID(REFIID rclsid, LPSTR FAR* lplpsz)
  887. {
  888. SCODE sc;
  889. char *psz;
  890. thkDebugOut((DEB_ITRACE, "StringFromIID\n"));
  891. do
  892. {
  893. if (!IsValidPtrOut(lplpsz, sizeof(LPSTR)))
  894. {
  895. sc = E_INVALIDARG;
  896. break;
  897. }
  898. *lplpsz = NULL;
  899. if (!IsValidPtrIn(&rclsid, sizeof(IID)))
  900. {
  901. sc = E_INVALIDARG;
  902. break;
  903. }
  904. psz = (char *)TaskAlloc(GUIDSTR_MAX);
  905. if (psz == NULL)
  906. {
  907. sc = E_OUTOFMEMORY;
  908. break;
  909. }
  910. if (StringFromGUID2(rclsid, psz, GUIDSTR_MAX) == 0)
  911. {
  912. sc = E_INVALIDARG;
  913. TaskFree(psz);
  914. break;
  915. }
  916. *lplpsz = psz;
  917. sc = S_OK;
  918. } while (FALSE);
  919. return ResultFromScode(sc);
  920. }
  921. //+---------------------------------------------------------------------------
  922. //
  923. // Function: IIDFromString, Local
  924. //
  925. // History: Straight from OLE2 sources
  926. //
  927. //----------------------------------------------------------------------------
  928. STDAPI IIDFromString(LPSTR lpsz, LPIID lpiid)
  929. {
  930. SCODE sc;
  931. thkDebugOut((DEB_ITRACE, "IIDFromString\n"));
  932. sc = S_OK;
  933. if (!IsValidPtrOut(lpiid, sizeof(IID)))
  934. {
  935. sc = E_INVALIDARG;
  936. }
  937. else if (lpsz == NULL)
  938. {
  939. *lpiid = IID_NULL;
  940. }
  941. else if (!IsValidPtrIn(lpsz, sizeof(LPSTR)))
  942. {
  943. sc = E_INVALIDARG;
  944. }
  945. else if (!GUIDFromString(lpsz, lpiid))
  946. {
  947. sc = CO_E_IIDSTRING;
  948. }
  949. return ResultFromScode(sc);
  950. }
  951. //+---------------------------------------------------------------------------
  952. //
  953. // Function: StringFromGUID2, Local
  954. //
  955. // History: Straight from OLE2 sources
  956. //
  957. //----------------------------------------------------------------------------
  958. STDAPI_(int) StringFromGUID2(REFGUID rguid, LPSTR lpsz, int cbMax)
  959. {
  960. thkDebugOut((DEB_ITRACE, "StringFromGUID2\n"));
  961. if (cbMax < GUIDSTR_MAX)
  962. {
  963. return 0;
  964. }
  965. wsprintf(lpsz, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  966. rguid.Data1, rguid.Data2, rguid.Data3,
  967. rguid.Data4[0], rguid.Data4[1],
  968. rguid.Data4[2], rguid.Data4[3],
  969. rguid.Data4[4], rguid.Data4[5],
  970. rguid.Data4[6], rguid.Data4[7]);
  971. return GUIDSTR_MAX;
  972. }
  973. // The following two APIs are now macros but must still be exported
  974. // so use PASCAL-form names to avoid problems with the macros
  975. //+---------------------------------------------------------------------------
  976. //
  977. // Function: GETSCODE, Local
  978. //
  979. // History: Straight from OLE2 sources
  980. //
  981. //----------------------------------------------------------------------------
  982. STDAPI_(SCODE) GETSCODE(HRESULT hr)
  983. {
  984. return GetScode(hr);
  985. }
  986. //+---------------------------------------------------------------------------
  987. //
  988. // Function: RESULTFROMSCODE, Local
  989. //
  990. // History: Straight from OLE2 sources
  991. //
  992. //----------------------------------------------------------------------------
  993. STDAPI RESULTFROMSCODE(SCODE sc)
  994. {
  995. return ResultFromScode(sc);
  996. }
  997. //+---------------------------------------------------------------------------
  998. //
  999. // Function: PropagateResult, Local
  1000. //
  1001. // History: Straight from OLE2 sources
  1002. //
  1003. //----------------------------------------------------------------------------
  1004. STDAPI PropagateResult(HRESULT hrPrev, SCODE scNew)
  1005. {
  1006. thkDebugOut((DEB_ITRACE, "PropagateResult\n"));
  1007. return (HRESULT)((scNew & 0x800FFFFF) | ((DWORD)hrPrev & 0x7FF00000)
  1008. + 0x100000);
  1009. }
  1010. //+---------------------------------------------------------------------------
  1011. //
  1012. // Function: FnAssert, Local
  1013. //
  1014. // History: Straight from OLE2 sources
  1015. //
  1016. //----------------------------------------------------------------------------
  1017. #if DBG == 1
  1018. static char lpBuffer[512];
  1019. static char lpLocBuffer[256];
  1020. #endif
  1021. STDAPI FnAssert( LPSTR lpstrExpr,
  1022. LPSTR lpstrMsg,
  1023. LPSTR lpstrFileName,
  1024. UINT iLine )
  1025. {
  1026. #if DBG == 1
  1027. int iResult;
  1028. wsprintf(lpBuffer, "Assertion \"%s\" failed! %s", lpstrExpr, lpstrMsg);
  1029. wsprintf(lpLocBuffer, "File %s, line %d; (A=exit; R=break; I=continue)",
  1030. lpstrFileName, iLine);
  1031. iResult = MessageBox(NULL, lpLocBuffer, lpBuffer,
  1032. MB_ABORTRETRYIGNORE | MB_SYSTEMMODAL);
  1033. if (iResult == IDRETRY)
  1034. {
  1035. DebugBreak();
  1036. }
  1037. else if (iResult == IDABORT)
  1038. {
  1039. CoFreeAllLibraries();
  1040. FatalAppExit(0, "Assertion failure");
  1041. }
  1042. #endif
  1043. return NOERROR;
  1044. }
  1045. //
  1046. // NOTE- These APIs are exported by the .DEF file, but are not documented,
  1047. // nor is there any code in the 16-bit world to deal with them. Each of these
  1048. // needs to be investigated to determine what we need to do to implement them.
  1049. //
  1050. // LRPCDISPATCH
  1051. // REMCONNECTTOOBJECT
  1052. // REMCREATEREMOTEHANDLER
  1053. // REMALLOCOID
  1054. // LRPCFREEMONITORDATA
  1055. // TIMERCALLBACKPROC
  1056. // COSETACKSTATE
  1057. // COGETCLASSEXT
  1058. // LRPCCALL
  1059. // LRPCREGISTERMONITOR
  1060. // CLSIDFROMOLE1CLASS
  1061. // COOPENCLASSKEY
  1062. // LRPCGETTHREADWINDOW
  1063. // LRPCREVOKEMONITOR
  1064. // COHANDLEINCOMINGCALL
  1065. // REMGETINFOFORCID
  1066. //
  1067. // The below stubs probably don't clean up the stack properly either!!!
  1068. #define UNDEFINED_DEF_ENTRY(x) STDAPI x ( void ) \
  1069. { return ResultFromScode(E_NOTIMPL); }
  1070. UNDEFINED_DEF_ENTRY( LRPCDISPATCH )
  1071. UNDEFINED_DEF_ENTRY( REMCONNECTTOOBJECT )
  1072. UNDEFINED_DEF_ENTRY( REMCREATEREMOTEHANDLER )
  1073. UNDEFINED_DEF_ENTRY( REMALLOCOID )
  1074. UNDEFINED_DEF_ENTRY( LRPCFREEMONITORDATA )
  1075. UNDEFINED_DEF_ENTRY( TIMERCALLBACKPROC )
  1076. UNDEFINED_DEF_ENTRY( COSETACKSTATE )
  1077. UNDEFINED_DEF_ENTRY( COGETCLASSEXT )
  1078. UNDEFINED_DEF_ENTRY( LRPCCALL )
  1079. UNDEFINED_DEF_ENTRY( LRPCREGISTERMONITOR )
  1080. UNDEFINED_DEF_ENTRY( CLSIDFROMOLE1CLASS )
  1081. UNDEFINED_DEF_ENTRY( COOPENCLASSKEY )
  1082. UNDEFINED_DEF_ENTRY( LRPCGETTHREADWINDOW )
  1083. UNDEFINED_DEF_ENTRY( LRPCREVOKEMONITOR )
  1084. UNDEFINED_DEF_ENTRY( COHANDLEINCOMINGCALL )
  1085. UNDEFINED_DEF_ENTRY( REMGETINFOFORCID )
  1086. UNDEFINED_DEF_ENTRY( OLE1CLASSFROMCLSID2 )
  1087. UNDEFINED_DEF_ENTRY( REMLOOKUPSHUNK )
  1088. UNDEFINED_DEF_ENTRY( REMFREEOID )