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

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: COMLOCAL.CXX (16 bit target)
//
// Contents: CompObj APIs
//
// Functions:
//
// History: 16-Dec-93 JohannP Created
//
//--------------------------------------------------------------------------
#include <headers.cxx>
#pragma hdrstop
#include <ole2ver.h>
#include <ole2sp.h>
#include <olecoll.h>
#include <map_kv.h>
#include "comlocal.hxx"
#include "map_htsk.h"
#include "etask.hxx"
#include "call32.hxx"
#include "apilist.hxx"
UINT v_pidHighWord = 1; // incremented each time used
IMalloc FAR* v_pMallocShared = NULL; // is not addrefed
// Note: bug 3698
// MsPub is not calling CoInitialize befor calling OpenStorage to
// preview templates. This pointer has an addref!
// When this pointer is not NULL CoGetMalloc was called prior to CoInitialize
// The pointer is transfered as soon as CoInitialize is called by any task.
IMalloc FAR* v_pMallocPreShared = NULL;
BOOL SetupSharedAllocator(Etask FAR& etask);
//+---------------------------------------------------------------------------
//
// Function: TaskAlloc, private
//
// Synopsis: Allocates task memory
//
// Arguments: [cb] - Number of bytes to allocate
//
// Returns: Pointer to memory or NULL
//
// History: 03-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
LPVOID __loadds FAR PASCAL TaskAlloc(ULONG cb)
{
HRESULT hr;
LPMALLOC lpMalloc = NULL;
LPVOID lpv;
hr = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
if (FAILED(GetScode(hr)) )
{
lpv = NULL;
}
else
{
thkAssert(lpMalloc != NULL && "CoGetMalloc pMalloce is NULL\n");
lpv = lpMalloc->Alloc(cb);
lpMalloc->Release();
}
return lpv;
}
//+---------------------------------------------------------------------------
//
// Function: TaskFree, private
//
// Synopsis: Free task memory
//
// Arguments: [pv] - Memory
//
// History: 03-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
void __loadds FAR PASCAL TaskFree(LPVOID pv)
{
HRESULT hr;
LPMALLOC lpMalloc;
hr = CoGetMalloc(MEMCTX_TASK, &lpMalloc);
if (SUCCEEDED(GetScode(hr)))
{
lpMalloc->Free(pv);
lpMalloc->Release();
}
}
#if defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Function: IsProcessIn32Context, private
//
// Synopsis: Returns true if current process is 32-bits.
//
// Arguments: None.
//
// History: 03-Jan-95 KentCe Created
//
// Remarks: This function takes advantage of internal Chicago data
// structures. No other method available.
//
//----------------------------------------------------------------------------
BOOL IsProcessIn32Context(void)
{
LPBYTE pTaskFlag;
//
// Create a pointer to the 0x16 byte of the task structure.
//
pTaskFlag = (LPBYTE)MAKELONG(0x16, GetCurrentTask());
//
// Bit 4 (0x10) is only true when we are a 32-bit process.
//
if (*pTaskFlag & 0x10)
return TRUE;
return FALSE;
}
#endif
//+---------------------------------------------------------------------------
//
// Method: SetupSharedAllocator
//
// Synopsis: Allocats the shared allocator and
// initializes the etask shared allocator
//
// Arguments: [etask] --
//
// Returns:
//
// History: 2-03-95 JohannP (Johann Posch) Created
//
// Notes: call by CoInitialize and DllEntryPoint
//
//----------------------------------------------------------------------------
BOOL SetupSharedAllocator(Etask FAR& etask)
{
// we must ensure we have a shared allocator now since that is where the
// etask map wiil be stored; if another process already created it, use it;
// this is so we always use the same shared pool of memory for all
// processes (so the DidAlloc method returns 1 for the same call from
// different process); the pointer refers to shared memory within
// the blocks managed by the IMalloc implementation and the
// vtable is always valid on Windows; the global pointer carries
// no ref count on its own; changes might be requires on
// other platforms.
if (v_pMallocPreShared != NULL)
{
// Note: fix for bug 3698;l MsPub not calling CoInitialize
// transfer addref from preshared to task entry
etask.m_pMallocShared = v_pMallocPreShared;
v_pMallocShared = v_pMallocPreShared;
v_pMallocPreShared = NULL;
}
else if (v_pMallocShared != NULL)
{
(etask.m_pMallocShared = v_pMallocShared)->AddRef();
}
else
{
// sets pMalloc to NULL on error
CoCreateStandardMalloc(MEMCTX_SHARED, &etask.m_pMallocShared);
v_pMallocShared = etask.m_pMallocShared;
thkAssert(v_pMallocShared != NULL && "SetupSharedAllocator failed!");
}
return (v_pMallocShared != NULL) ? TRUE : FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: CoInitialize, Split
//
// Synopsis:
//
// Effects:
//
// Arguments: [pMalloc] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 2-28-94 kevinro Created
// 3-08-94 BobDay Added code from \\ole\slm\...\compobj.cpp
//
// Notes:
//
//----------------------------------------------------------------------------
// initialize compobj; errors: S_FALSE, E_OUTOFMEMORY
STDAPI CoInitialize(IMalloc FAR* pMalloc)
{
LPMALLOC pmlNull = NULL;
HRESULT hresult;
HTASK htask;
Etask etask;
thkDebugOut((DEB_ITRACE, "CoInitialize\n"));
thkDebugOut((DEB_APIS16, "CoInitilaize called on Process (%X) \n", GetCurrentProcess()));
#if defined(_CHICAGO_)
//
// Prevent 32-bit MPLAYER from loading a 16-bit DLL's which in turns
// uses 16-bit OLE2. We can't handle the condition of a 32-bit process
// thunking up thru the 16:32 OLE2 interop layer. So return an error
// and not fault out.
//
if (IsProcessIn32Context())
return ResultFromScode(E_OUTOFMEMORY);
etask.m_Dllinits = 0;
#endif
// if already init, bump count and return S_FALSE
if ( IsEtaskInit(htask, etask)
&& IsValidInterface((etask.m_pMalloc)) )
{
if ( etask.m_inits != ETASK_FAKE_INIT )
{
etask.m_inits++;
thkVerify(SetEtask(htask, etask));
return ResultFromScode(S_FALSE);
}
//
// CoInitialize has been called after we've done a fake call for them
// we can just take over their allocator and get rid of our fake one.
//
if ( pMalloc != NULL )
{
etask.m_pMalloc->Release(); // Get rid of the old task allocator
etask.m_pMalloc = pMalloc;
etask.m_pMalloc->AddRef();
}
else
{
//
// It would be nice if we could assert that the fake task
// allocator was a default task allocator. i.e. no operation
// were really needed!
//
}
//
// "We need to have a way to clean up any fake calls to
// CoInitialize. Should the application go away after using one of
// the apis that caused us to do a fake CoInitialize in the first
// place, and should the application exit without really making a
// call to CoInitialize eventually, then we wouldn't know enough to
// clean up... I think this is ok for now. Most apps do call
// CoInitialize eventually."
//
etask.m_inits = 1;
thkAssert(etask.m_pMalloc != NULL); // now have task allocator in all cases
thkVerify(SetEtask(htask, etask));
return ResultFromScode(S_OK);
}
#ifdef _CHICAGO_
else if (etask.m_Dllinits == 0)
{
// Note: we might end up here since some app call
// CoInitialize in LibMain. The call to our DllEntryPoint
// will follow.
if (!Call32Initialize())
{
return ResultFromScode(E_OUTOFMEMORY);
}
etask.m_htask = GetCurrentProcess();
}
#endif
// set/create task malloc
if (pMalloc != NULL)
{
VDATEIFACE( pMalloc );
(etask.m_pMalloc = pMalloc)->AddRef();
}
else
{
if ((hresult = CoCreateStandardMalloc(MEMCTX_TASK,
&etask.m_pMalloc)) != NOERROR)
return hresult;
}
thkAssert(etask.m_pMalloc != NULL); // now have task allocator in all cases
// set up the shared allocator
if ( etask.m_pMallocShared == NULL
&& SetupSharedAllocator(etask) == FALSE)
{
etask.m_pMalloc->Release(); // was created or AddRef'd above
return ResultFromScode(E_OUTOFMEMORY);
}
// now have shared allocator in all cases
thkAssert(etask.m_pMallocShared != NULL);
// init remaining entries and add entry to table for this app/task pair;
// leave maps null for now (they are allocated on demand)
etask.m_pMallocSBlock = NULL;
etask.m_pMallocPrivate = NULL;
etask.m_pid = MAKELONG(GetCurrentProcess(),v_pidHighWord++);
etask.m_inits = 1;
etask.m_oleinits = 0;
etask.m_reserved = 0;
etask.m_pDlls = NULL;
etask.m_pMapToServerCO = NULL;
etask.m_pMapToHandlerCO = NULL;
etask.m_pArraySH = NULL;
etask.m_pCThrd = NULL;
etask.m_hwndClip = NULL;
etask.m_hwndDde = NULL;
etask.m_punkState = NULL;
if (!SetEtask(htask, etask))
{
ReleaseEtask(NULL, etask);
thkAssert(0 && "CompObj: CoInitialize SetEtask failed.");
return ResultFromScode(E_OUTOFMEMORY);
}
// Initialize the thunk manager for this apartment.
if (SUCCEEDED(hresult = CallThkMgrInitialize()))
{
//
// Now transition into 32-bit world to give it a chance for
// initialization at this time.
//
// Never pass the 16-bit allocator on to 32-bits
pMalloc = NULL;
hresult = (HRESULT)CallObjectInWOW(THK_API_METHOD(THK_API_CoInitialize),
PASCAL_STACK_PTR(pMalloc) );
}
if (FAILED(GetScode(hresult)))
{
ReleaseEtask(htask, etask);
}
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: CoUninitialize, Split
//
// Synopsis:
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 2-28-94 kevinro Created
// 10-Mar-94 BobDay Copied & Merged with compobj.cpp 16-bit
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI_(void) CoUninitialize(void)
{
HTASK htask;
Etask etask;
thkDebugOut((DEB_ITRACE, "CoUninitialize\n"));
thkDebugOut((DEB_APIS16, "CoUninitilaize called on Process (%X) \n", GetCurrentProcess()));
if (!IsEtaskInit(htask, etask))
return;
// if not last uninit, just decrement count and return.
if (etask.m_inits != 1)
{
//
// If a fake init, then just ignore as if we haven't ever init'd
//
if ( etask.m_inits == ETASK_FAKE_INIT )
{
//
// Some slimy app doesn't call CoInitialize but does eventually
// call CoUninitialize. Lets find them if they do!
//
thkAssert(FALSE &&
"CoUninitialize called after fake CoInitialize\n");
}
else
{
etask.m_inits--;
thkVerify(SetEtask(htask, etask));
}
return ;
}
// Some applications pass on module handle of loaded dlls.
// As a result LibMain and WEP is not called in the same process.
// To prevent premature unloading of OleThk32.dll call
// SetReleaseDLL(FALSE)
SetReleaseDLL(FALSE);
//
// Now transition into 32-bit world to give it a chance for
// initialization at this time.
//
CallObjectInWOW(THK_API_METHOD(THK_API_CoUninitialize), NULL );
// Reset dll unloading - see above
SetReleaseDLL(TRUE);
CoFreeAllLibraries();
//
// We do not uninitialize the thunk manager at this point. The app may attempt
// to call additional API's after CoUninitialize. For example, Lotus 1-2-3
// is known to do this, as is Publisher. The thunk manager will clean up
// as part of its thread detach.
//
// the last thing is to remove the allocator and delete the etask for us;
// must lookup again in case contents changed.
if (LookupEtask(htask, etask))
ReleaseEtask(htask, etask);
thkDebugOut((DEB_APIS16, "CoUninitilaize on Process (%X) done.\n", GetCurrentProcess()));
thkDebugOut((DEB_ITRACE, "CoUninitialize exit\n"));
// Note: some apps check the return value if the void function CoUninitialize
// and they fail if it is not NULL like WinOffice Setup 4.3
// Please don't take it out.
_asm mov ax,0;
_asm mov dx,0;
}
//+---------------------------------------------------------------------------
//
// Function: CoGetMalloc, Local
//
// Synopsis:
//
// Effects:
//
// Arguments: [dwMemContext] --
// [ppMalloc] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 2-28-94 kevinro Created
// 10-Mar-94 BobDay Copied & Merged with compobj.cpp 16-bit
//
// Notes:
//
//----------------------------------------------------------------------------
// return pMalloc for the current task; errors: E_INVALIDARG,
// CO_E_NOTINITIALIZED, E_OUTOFMEMORY (not for task or shared allocators)
STDAPI CoGetMalloc(DWORD dwContext, IMalloc FAR* FAR* ppMalloc)
{
Etask etask;
HTASK htask;
thkDebugOut((DEB_ITRACE, " CoGetMalloc\n"));
VDATEPTROUT( ppMalloc, IMalloc FAR* );
// NOTE: we set *ppMalloc to NULL only in the error cases below
// MOre work here!
// need this for the bootstrap case
if (dwContext == MEMCTX_SHARED)
{
if (v_pMallocShared != NULL)
{
*ppMalloc = v_pMallocShared;
goto Exit;
}
// pMallocShared is NULL -- CoInitialize was not called yet.
if (v_pMallocPreShared == NULL)
{
CoCreateStandardMalloc(MEMCTX_SHARED, &v_pMallocPreShared);
if (v_pMallocPreShared != NULL)
{
*ppMalloc = v_pMallocPreShared;
goto Exit;
}
else
{
*ppMalloc = NULL;
return ResultFromScode(CO_E_NOTINITIALIZED);
}
}
else
{
*ppMalloc = v_pMallocPreShared;
goto Exit;
}
}
//
// Clip Art Gallery will call pStream->Stat before calling CoInitialize.
// This causes the thunk logic to allocation 16bit memory which will
// fail at this point. The below code to auto-initialize should this
// happen. (Really just a hack for Clip Art Gallery).
//
if ( !IsEtaskInit(htask, etask)
|| !IsValidInterface((etask.m_pMalloc)) )
{
if (FAILED(CoInitialize(NULL)))
{
*ppMalloc = NULL;
return ResultFromScode(CO_E_NOTINITIALIZED);
}
thkVerify(LookupEtask( htask, etask ));
etask.m_inits = ETASK_FAKE_INIT;
thkVerify(SetEtask(htask, etask));
}
// shared always available if initialized; no need to handle here
thkAssert(dwContext != MEMCTX_SHARED);
if (dwContext == MEMCTX_TASK)
{
thkAssert(etask.m_pMalloc != NULL);
*ppMalloc = etask.m_pMalloc;
}
else
{
#ifdef NOTYET
// contexts which are delay-created
IMalloc FAR* FAR* ppMallocStore;
if (dwContext == MEMCTX_SHAREDBLOCK)
ppMallocStore = &etask.m_pMallocSBlock;
else if (dwContext == MEMCTX_COPRIVATE)
ppMallocStore = &etask.m_pMallocPrivate;
else
{
// invalid context
*ppMalloc = NULL;
return ResultFromScode(E_INVALIDARG);
}
if (*ppMallocStore == NULL)
{
// sets pMalloc to NULL on error
if (CoCreateStandardMalloc(dwContext, ppMallocStore) != NOERROR)
{
*ppMalloc = NULL;
return ResultFromScode(E_OUTOFMEMORY);
}
thkVerify(SetEtask(htask, etask));
}
*ppMalloc = *ppMallocStore;
#else
// invalid context
thkAssert(!"Unknown memctx in CoGetMalloc");
*ppMalloc = NULL;
return ResultFromScode(E_INVALIDARG);
#endif // NOTYET
}
Exit: // have non-null *ppMalloc
thkAssert(*ppMalloc != NULL);
(*ppMalloc)->AddRef();
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: CoGetState, Local
//
// Synopsis: Retrieves task-specific state
//
// Arguments: [ppunk] - IUnknown pointer to fill in
//
// Returns: Appropriate status code
//
// History: 26-Jul-94 DrewB Created
//
// Notes: Private API for OLE automation
//
//----------------------------------------------------------------------------
STDAPI CoGetState(IUnknown FAR * FAR *ppunk)
{
Etask etask;
HTASK htask;
thkDebugOut((DEB_APIS16, "CoGetState called\n"));
if (IsBadWritePtr(ppunk, sizeof(IUnknown *)))
{
thkDebugOut((DEB_APIS16, "CoGetState failed\n"));
return ResultFromScode(E_INVALIDARG);
}
if (!LookupEtask(htask, etask) || etask.m_punkState == NULL )
{
*ppunk = NULL;
thkDebugOut((DEB_APIS16, "CoGetState failed\n"));
return ResultFromScode(S_FALSE);
}
if ( !IsValidInterface((etask.m_punkState)) )
{
*ppunk = NULL;
etask.m_punkState = NULL;
thkDebugOut((DEB_APIS16, "CoGetState failed (invalid interface)\n"));
return ResultFromScode(S_FALSE);
}
*ppunk = etask.m_punkState;
etask.m_punkState->AddRef();
thkDebugOut((DEB_APIS16, "CoGetState done %p\n", *ppunk));
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: CoSetState, Local
//
// Synopsis: Sets task-specific state
//
// Arguments: [punk] - State to set
//
// Returns: Appropriate status code
//
// History: 26-Jul-94 DrewB Created
//
// Notes: Private API for OLE automation
//
//----------------------------------------------------------------------------
STDAPI CoSetState(IUnknown FAR *punk)
{
Etask etask;
HTASK htask;
IUnknown FAR *punkStateOld;
thkDebugOut((DEB_APIS16, "CoSetState called %p\n", punk));
if (punk != NULL && !IsValidInterface(punk))
{
thkDebugOut((DEB_APIS16, "CoSetState called %p failed\n", punk));
return ResultFromScode(E_INVALIDARG);
}
if (!IsEtaskInit(htask, etask))
{
thkDebugOut((DEB_APIS16, "CoSetState called %p failed\n", punk));
return ResultFromScode(S_FALSE);
}
if (punk != NULL)
{
punk->AddRef();
}
punkStateOld = etask.m_punkState;
etask.m_punkState = punk;
thkVerify(SetEtask(htask, etask));
if (punkStateOld != NULL && IsValidInterface(punkStateOld))
{
punkStateOld->Release();
}
thkDebugOut((DEB_APIS16, "CoSetState called %p done\n", punk));
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: CoGetCurrentProcess, Local
//
//----------------------------------------------------------------------------
// returns a unique value for the current task; this routine is
// necessary because htask values from Window get reused periodically.
STDAPI_(DWORD) CoGetCurrentProcess(void)
{
HTASK htask;
Etask etask;
thkDebugOut((DEB_ITRACE, " CoGetCurrentProcess\n"));
if (!IsEtaskInit(htask, etask))
return 0;
return etask.m_pid;
}
//+---------------------------------------------------------------------------
//
// Function: CoBuildVersion, Local
//
//----------------------------------------------------------------------------
STDAPI_(DWORD) CoBuildVersion(VOID)
{
thkDebugOut((DEB_ITRACE, " CoBuildVersion\n"));
// We must return 23 as our major version number to remain
// compatible with shipped OLE 2.01
// OLE 2.01 shipped with minor version 640
// We return a number slightly higher to differentiate
// our product while indicating compatibility
return MAKELONG(700, 23);
}
//+---------------------------------------------------------------------------
//
// Function: CoMarshalHresult, Local
//
// History: Taken straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI CoMarshalHresult(LPSTREAM pstm, HRESULT hresult)
{
HRESULT hr;
thkDebugOut((DEB_ITRACE, "CoMarshalHresult\n"));
if (!IsValidInterface(pstm))
{
hr = ResultFromScode(E_INVALIDARG);
}
else
{
SCODE sc;
ULONG cb;
sc = GetScode(hresult);
hr = pstm->Write(&sc, sizeof(sc), &cb);
if (SUCCEEDED(GetScode(hr)) && cb != sizeof(sc))
{
hr = ResultFromScode(STG_E_WRITEFAULT);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CoUnmarshalHresult, Local
//
// History: Taken straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI CoUnmarshalHresult(LPSTREAM pstm, HRESULT FAR * phresult)
{
HRESULT hr;
thkDebugOut((DEB_ITRACE, "CoUnmarshalHresult\n"));
if (!IsValidPtrOut(phresult, sizeof(HRESULT)))
{
hr = ResultFromScode(E_INVALIDARG);
}
else
{
*phresult = 0;
if (!IsValidInterface(pstm))
{
hr = ResultFromScode(E_INVALIDARG);
}
else
{
SCODE sc;
ULONG cb;
hr = pstm->Read(&sc, sizeof(sc), &cb);
if (SUCCEEDED(GetScode(hr)))
{
if (cb != sizeof(sc))
{
hr = ResultFromScode(STG_E_READFAULT);
}
else
{
*phresult = ResultFromScode(sc);
}
}
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: IsEqualGUID, Local
//
// History: Taken straight from OLE2 sources
//
//----------------------------------------------------------------------------
#pragma intrinsic(_fmemcmp)
STDAPI_(BOOL) IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
//thkDebugOut((DEB_ITRACE, "IsEqualGUID\n"));
return !_fmemcmp(&rguid1, &rguid2, sizeof(GUID));
}
#pragma function(_fmemcmp)
#define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
//+---------------------------------------------------------------------------
//
// Function: HexStringToDword, private
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
static BOOL HexStringToDword(LPCSTR FAR& lpsz, DWORD FAR& Value, int cDigits,
char chDelim)
{
int Count;
Value = 0;
for (Count = 0; Count < cDigits; Count++, lpsz++)
{
if (*lpsz >= '0' && *lpsz <= '9')
{
Value = (Value << 4) + *lpsz - '0';
}
else if (*lpsz >= 'A' && *lpsz <= 'F')
{
Value = (Value << 4) + *lpsz - 'A' + 10;
}
else if (*lpsz >= 'a' && *lpsz <= 'f')
{
Value = (Value << 4) + *lpsz - 'a' + 10;
}
else
{
return(FALSE);
}
}
if (chDelim != 0)
{
return *lpsz++ == chDelim;
}
else
{
return TRUE;
}
}
//+---------------------------------------------------------------------------
//
// Function: GUIDFromString, private
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI_(BOOL) GUIDFromString(LPCSTR lpsz, LPGUID pguid)
{
DWORD dw;
if (*lpsz++ != '{')
return FALSE;
if (!HexStringToDword(lpsz, pguid->Data1, sizeof(DWORD)*2, '-'))
return FALSE;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data2 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data3 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[0] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '-'))
return FALSE;
pguid->Data4[1] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[2] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[3] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[4] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[5] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[6] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '}'))
return FALSE;
pguid->Data4[7] = (BYTE)dw;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: StringFromCLSID, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
#define CLSIDSTR_MAX (GUIDSTR_MAX)
STDAPI StringFromCLSID(REFCLSID rclsid, LPSTR FAR* lplpsz)
{
SCODE sc;
char *psz;
thkDebugOut((DEB_ITRACE, "StringFromCLSID\n"));
psz = NULL;
do
{
if (!IsValidPtrOut(lplpsz, sizeof(LPSTR)))
{
sc = E_INVALIDARG;
break;
}
*lplpsz = NULL;
if (!IsValidPtrIn(&rclsid, sizeof(CLSID)))
{
sc = E_INVALIDARG;
break;
}
psz = (char *)TaskAlloc(CLSIDSTR_MAX);
if (psz == NULL)
{
sc = E_OUTOFMEMORY;
break;
}
if (StringFromGUID2(rclsid, psz, CLSIDSTR_MAX) == 0)
{
sc = E_INVALIDARG;
TaskFree(psz);
break;
}
*lplpsz = psz;
sc = S_OK;
} while (FALSE);
return ResultFromScode(sc);
}
//+---------------------------------------------------------------------------
//
// Function: StringFromIID, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI StringFromIID(REFIID rclsid, LPSTR FAR* lplpsz)
{
SCODE sc;
char *psz;
thkDebugOut((DEB_ITRACE, "StringFromIID\n"));
do
{
if (!IsValidPtrOut(lplpsz, sizeof(LPSTR)))
{
sc = E_INVALIDARG;
break;
}
*lplpsz = NULL;
if (!IsValidPtrIn(&rclsid, sizeof(IID)))
{
sc = E_INVALIDARG;
break;
}
psz = (char *)TaskAlloc(GUIDSTR_MAX);
if (psz == NULL)
{
sc = E_OUTOFMEMORY;
break;
}
if (StringFromGUID2(rclsid, psz, GUIDSTR_MAX) == 0)
{
sc = E_INVALIDARG;
TaskFree(psz);
break;
}
*lplpsz = psz;
sc = S_OK;
} while (FALSE);
return ResultFromScode(sc);
}
//+---------------------------------------------------------------------------
//
// Function: IIDFromString, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI IIDFromString(LPSTR lpsz, LPIID lpiid)
{
SCODE sc;
thkDebugOut((DEB_ITRACE, "IIDFromString\n"));
sc = S_OK;
if (!IsValidPtrOut(lpiid, sizeof(IID)))
{
sc = E_INVALIDARG;
}
else if (lpsz == NULL)
{
*lpiid = IID_NULL;
}
else if (!IsValidPtrIn(lpsz, sizeof(LPSTR)))
{
sc = E_INVALIDARG;
}
else if (!GUIDFromString(lpsz, lpiid))
{
sc = CO_E_IIDSTRING;
}
return ResultFromScode(sc);
}
//+---------------------------------------------------------------------------
//
// Function: StringFromGUID2, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI_(int) StringFromGUID2(REFGUID rguid, LPSTR lpsz, int cbMax)
{
thkDebugOut((DEB_ITRACE, "StringFromGUID2\n"));
if (cbMax < GUIDSTR_MAX)
{
return 0;
}
wsprintf(lpsz, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
rguid.Data1, rguid.Data2, rguid.Data3,
rguid.Data4[0], rguid.Data4[1],
rguid.Data4[2], rguid.Data4[3],
rguid.Data4[4], rguid.Data4[5],
rguid.Data4[6], rguid.Data4[7]);
return GUIDSTR_MAX;
}
// The following two APIs are now macros but must still be exported
// so use PASCAL-form names to avoid problems with the macros
//+---------------------------------------------------------------------------
//
// Function: GETSCODE, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI_(SCODE) GETSCODE(HRESULT hr)
{
return GetScode(hr);
}
//+---------------------------------------------------------------------------
//
// Function: RESULTFROMSCODE, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI RESULTFROMSCODE(SCODE sc)
{
return ResultFromScode(sc);
}
//+---------------------------------------------------------------------------
//
// Function: PropagateResult, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
STDAPI PropagateResult(HRESULT hrPrev, SCODE scNew)
{
thkDebugOut((DEB_ITRACE, "PropagateResult\n"));
return (HRESULT)((scNew & 0x800FFFFF) | ((DWORD)hrPrev & 0x7FF00000)
+ 0x100000);
}
//+---------------------------------------------------------------------------
//
// Function: FnAssert, Local
//
// History: Straight from OLE2 sources
//
//----------------------------------------------------------------------------
#if DBG == 1
static char lpBuffer[512];
static char lpLocBuffer[256];
#endif
STDAPI FnAssert( LPSTR lpstrExpr,
LPSTR lpstrMsg,
LPSTR lpstrFileName,
UINT iLine )
{
#if DBG == 1
int iResult;
wsprintf(lpBuffer, "Assertion \"%s\" failed! %s", lpstrExpr, lpstrMsg);
wsprintf(lpLocBuffer, "File %s, line %d; (A=exit; R=break; I=continue)",
lpstrFileName, iLine);
iResult = MessageBox(NULL, lpLocBuffer, lpBuffer,
MB_ABORTRETRYIGNORE | MB_SYSTEMMODAL);
if (iResult == IDRETRY)
{
DebugBreak();
}
else if (iResult == IDABORT)
{
CoFreeAllLibraries();
FatalAppExit(0, "Assertion failure");
}
#endif
return NOERROR;
}
//
// NOTE- These APIs are exported by the .DEF file, but are not documented,
// nor is there any code in the 16-bit world to deal with them. Each of these
// needs to be investigated to determine what we need to do to implement them.
//
// LRPCDISPATCH
// REMCONNECTTOOBJECT
// REMCREATEREMOTEHANDLER
// REMALLOCOID
// LRPCFREEMONITORDATA
// TIMERCALLBACKPROC
// COSETACKSTATE
// COGETCLASSEXT
// LRPCCALL
// LRPCREGISTERMONITOR
// CLSIDFROMOLE1CLASS
// COOPENCLASSKEY
// LRPCGETTHREADWINDOW
// LRPCREVOKEMONITOR
// COHANDLEINCOMINGCALL
// REMGETINFOFORCID
//
// The below stubs probably don't clean up the stack properly either!!!
#define UNDEFINED_DEF_ENTRY(x) STDAPI x ( void ) \
{ return ResultFromScode(E_NOTIMPL); }
UNDEFINED_DEF_ENTRY( LRPCDISPATCH )
UNDEFINED_DEF_ENTRY( REMCONNECTTOOBJECT )
UNDEFINED_DEF_ENTRY( REMCREATEREMOTEHANDLER )
UNDEFINED_DEF_ENTRY( REMALLOCOID )
UNDEFINED_DEF_ENTRY( LRPCFREEMONITORDATA )
UNDEFINED_DEF_ENTRY( TIMERCALLBACKPROC )
UNDEFINED_DEF_ENTRY( COSETACKSTATE )
UNDEFINED_DEF_ENTRY( COGETCLASSEXT )
UNDEFINED_DEF_ENTRY( LRPCCALL )
UNDEFINED_DEF_ENTRY( LRPCREGISTERMONITOR )
UNDEFINED_DEF_ENTRY( CLSIDFROMOLE1CLASS )
UNDEFINED_DEF_ENTRY( COOPENCLASSKEY )
UNDEFINED_DEF_ENTRY( LRPCGETTHREADWINDOW )
UNDEFINED_DEF_ENTRY( LRPCREVOKEMONITOR )
UNDEFINED_DEF_ENTRY( COHANDLEINCOMINGCALL )
UNDEFINED_DEF_ENTRY( REMGETINFOFORCID )
UNDEFINED_DEF_ENTRY( OLE1CLASSFROMCLSID2 )
UNDEFINED_DEF_ENTRY( REMLOOKUPSHUNK )
UNDEFINED_DEF_ENTRY( REMFREEOID )