CoHack* APIs

 

These are a bunch of what I call CoHack* APIs. They are almost always needed and so thought this would save some of your time.   If you have ideas for other such APIs feel free to send them to me... :-)[Back To COM Samples Gallery Page]

 

HRESULT CoHackGetCLSIDOfFTM()

HRESULT CoHackIsObjectApartmentNeutral()

HRESULT CoHackIsMTA()

HRESULT CoHackIsSTA()

new.gif (111 bytes)COHACK_APTTYPE CoHackGetAptType()

HRESULT CoHackIsStdProxy()

HRESULT CoHackGetCurrentLogicalThreadId()

HRESULT CoHackIsInterfaceTypeLibMarshaled()

 


HRESULT CoHackGetCLSIDOfFTM(/*out*/CLSID* pclsid) [Back to Top]
{
    HRESULT hr = E_FAIL;
    IUnknown* pUnk = 0;
    *pclsid = GUID_NULL;

    struct FakeUnknown : public IUnknown
    {
        STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
        {
            if (riid == IID_IUnknown)
                return reinterpret_cast<IUnknown*>(*ppv =                                         static_cast<IUnknown*>(this))->AddRef(), S_OK;
            else
                return (*ppv = 0), E_NOINTERFACE;
        }
        STDMETHODIMP_(ULONG) AddRef() { return 99; }
        STDMETHODIMP_(ULONG) Release() { return 99; }
    }FakeUnk;

    hr = ::CoCreateFreeThreadedMarshaler(&FakeUnk,&pUnk);
    if(SUCCEEDED(hr))
    {
        CComQIPtr<IMarshal> spMarshal(pUnk);
        hr = spMarshal->GetUnmarshalClass(IID_IUnknown, &FakeUnk,                                              MSHCTX_INPROC,0,MSHLFLAGS_NORMAL, pclsid);
        spMarshal.Release();spMarshal.p = 0;
        pUnk->Release(); pUnk = 0;
    }
    return hr;
}


//This one is useful when you are an outer object aggregating FTM
//and holding interface pointers as class members.
//If you want to determine whether the IP you are holding also aggregate
//FTM - so that you don't have to use GIT or for whatever reason, this API is for you
//Apartment Neutral == FTM aggregator == doesn't care in which apartment it's in

[Back to Top]

HRESULT CoHackIsObjectApartmentNeutral(/*[in]*/IUnknown* pUnk, /*[out]*/bool* pb)
{
    *pb = false;
    CComPtr<IMarshal> spMarshal;
    HRESULT hr = pUnk->QueryInterface(IID_IMarshal,(void**)&spMarshal);
    if(FAILED(hr)) return hr;
   
    CLSID clsid;
   
    struct FakeUnknown : public IUnknown
    {
        STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
        {
            if (riid == IID_IUnknown)
                return reinterpret_cast<IUnknown*>(*ppv =                                         static_cast<IUnknown*>(this))->AddRef(), S_OK;
            else
                return (*ppv = 0), E_NOINTERFACE;
        }
        STDMETHODIMP_(ULONG) AddRef() { return 99; }
        STDMETHODIMP_(ULONG) Release() { return 99; }
    }FakeUnk;

    hr = spMarshal->GetUnmarshalClass(IID_IUnknown, &FakeUnk, MSHCTX_INPROC, 0,                     MSHLFLAGS_NORMAL,&clsid);


   if(FAILED(hr)) { spMarshal.Release(); return hr; }

   CLSID clsidFTM;
   hr = CoHackGetCLSIDOfFTM(&clsidFTM);
   if(FAILED(hr)) { return hr; }
   
    *pb = ( memcmp(&clsidFTM,&clsid, sizeof(CLSID)) == 0 );
   
    spMarshal.Release();
    return hr;
}


//S_OK - if MTA
//S_FALSE - if Not
OR some error

HRESULT CoHackIsMTA()    [Back to Top]
{
    if(SUCCEEDED(CoInitializeEx(0, COINIT_MULTITHREADED)))
    {
        ::CoUninitialize();return S_OK;
    }
    else
    {
        return S_FALSE; //RPC_E_CHANGED_MODE or E_OUTOFMEMORY, E_UNEXPECTED etc.
    }
}


//S_OK - if STA
//S_FALSE - if Not
OR some error

HRESULT CoHackIsSTA()    [Back to Top]
{

    if(SUCCEEDED(CoInitializeEx(0, COINIT_APARTMENTTHREADED)))
    {
        ::CoUninitialize();return S_OK;
    }
    else
    {
        return S_FALSE; //RPC_E_CHANGED_MODE or E_OUTOFMEMORY, E_UNEXPECTED etc.
    }
 
}


#define x86TEB 0x18                                          [Back to Top]

#pragma warning (disable:4035) //warning C4035: : no return value blah blah

inline DWORD CoHackGetTLSValue(void) { __asm mov eax, fs:[x86TEB]
                                       __asm mov eax, [eax+0x0F80]
                                       __asm mov eax, [eax+0x0C] }
#pragma warning (default:4035)

typedef enum tagCOHACK_APTTYPE
{
    COHACK_APTTYPE_TNA        = 0,
    COHACK_APTTYPE_STA        = 1,
    COHACK_APTTYPE_MTA        = 2
} COHACK_APTTYPE;

COHACK_APTTYPE CoHackGetAptType()
{
    DWORD dw = CoHackGetTLSValue();
    return (dw & 0x800) ? COHACK_APTTYPE_TNA : (dw & 0x80) ? COHACK_APTTYPE_STA :COHACK_APTTYPE_MTA;
}

//Thanks to Kevin Jones of DevelopMentor for giving the offsets in the TEB,

//where the apartment types are stored, on the ATL listserver. He said he had tested them for STA and MTA on NT4.

//I experimented with these magic numbers<g> and added the stuff for the Thread Neutral Apartment

//on NT5 and also verified Kevin's offsets for NT5beta.

//Apparently the value stored in TLS index/returned by CoHackGetTLSValue(), is a bunch of ORed

//flags which keep on changing depending on if the object is created directly

//in the creator's apartment or a COM created apartment; on whether the

//object is inproc or out-of-proc etc.etc. CoHackGetAptType() looks for the magic number

//out of the bunch of ORed flags and seems to work reliably in all scenarios,

//so far:-)

//Notes: Checked for NT4 and NT5beta. Won't work for Win9x


//If you want to determine whether you have a raw pointer or a pointer to a proxy

//S_OK - proxy

//FAILED() - raw pointer

//Earlier I was just checking if I could successfully Table Marshal the given interface pointer.

//Thanks to Keith Brown for suggesting more efficient & reliable ways. Thanks, Keith!

HRESULT CoHackIsStdProxy(/*[in]*/IUnknown* pUnk)     [Back to Top]
{
    CComPtr<IUnknown> spFakePM;

    //Note that we are just interested in the return value of QI()

   return pUnk->QueryInterafce(IID_IProxyManager,(void**)&spFakePM);

}


//If you want to implement locks based on logical thread affinity
//this API is for you.
//

HRESULT CoHackGetCurrentLogicalThreadId(UUID *pCID)     [Back to Top]
{
    if(!pCID) { return E_POINTER; }
    typedef HRESULT (_stdcall*lpCoGetCurrentLogicalThreadId)(UUID *);
    lpCoGetCurrentLogicalThreadId CoGetCurrentLogicalThreadId;

    HINSTANCE hLibOLE32 = LoadLibrary(_T("OLE32.DLL"));
   
    if (!hLibOLE32)
        return E_FAIL;
   
    CoGetCurrentLogicalThreadId = (HRESULT (_stdcall *)(UUID *))GetProcAddress                             (hLibOLE32,"CoGetCurrentLogicalThreadId");
   
    HRESULT hr = E_FAIL;   
    if (CoGetCurrentLogicalThreadId)
        hr = CoGetCurrentLogicalThreadId(pCID);
   
    FreeLibrary(hLibOLE32);
    return hr;
}


//S_OK - If the IID is typelib marshaled
//S_FALSE if Not
HRESULT CoHackIsInterfaceTypeLibMarshaled(REFIID riid)
   [Back to Top]
{
    //Look for the ProxyStubClsID32 key for the given interface
    // in the registry . If its PSOAInterface its typelib marshaled
    TCHAR psz[1024],szValue[1024];
    LPOLESTR lp = 0;
    lstrcpy(psz,_T("Interface\\"));
    ::StringFromIID(riid,&lp);
    USES_CONVERSION;
    lstrcat(psz,OLE2A(lp));
    ::CoTaskMemFree(lp);lp = 0;   

    HKEY hk;
    HRESULT hr = E_UNEXPECTED;
    if (::RegOpenKey( HKEY_CLASSES_ROOT, psz, &hk) == ERROR_SUCCESS)
    {
        LONG cb = sizeof(szValue);
        if (::RegQueryValue(hk,_T("ProxyStubClsid32"), szValue, &cb) ==                                              ERROR_SUCCESS)
        {
            TCHAR szPSOA[1024];
            const CLSID clsidPSOA = {0x00020424,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};

            ::StringFromCLSID(clsidPSOA,&lp);
            lstrcpy(szPSOA,OLE2A(lp));
           
            if(lstrcmp(szValue,szPSOA) == 0)
                hr = S_OK;
            else
                hr = S_FALSE;

            ::CoTaskMemFree(lp);lp = 0;
        }
        ::RegCloseKey(hk) ;
    }       
    return hr;
}


This page and the source contained in(or referred to) by this page are Copyright (c) 1998, Dharma Shukla.
All rights reserved. No warrenties extended. Use at your own risk.
Do send Comments/Bugs to me :-)