// **************************************************************************

//

// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
// File:  OLESRVR.CPP
//
// Description:
//		  Event provider sample - COM server implementations
//
// History:
//
// **************************************************************************

#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <locale.h>

#include <wbemidl.h>
#include <initguid.h>

#include "evprov.h"

static HINSTANCE g_hInstance;

//***************************************************************************
//
//  DllMain
//
//***************************************************************************

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,
    DWORD dwReason,
    LPVOID lpReserved
    )
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        g_hInstance = hinstDLL;
        setlocale(LC_ALL, "");    
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
    }

    return TRUE;
}



//***************************************************************************
//
//  class CFactory
//
//***************************************************************************

class CFactory : public IClassFactory
{
    ULONG           m_cRef;
    CLSID           m_ClsId;

public:
    CFactory(const CLSID & ClsId);
    ~CFactory();

    //
    // IUnknown members
    //
    STDMETHODIMP         QueryInterface(REFIID, LPVOID *);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);

    //
    // IClassFactory members
    //
    STDMETHODIMP     CreateInstance(LPUNKNOWN, REFIID, LPVOID *);
    STDMETHODIMP     LockServer(BOOL);
};




//***************************************************************************
//
// Count number of objects and number of locks on this DLL.
//
//***************************************************************************

static ULONG g_cObj = 0;
static ULONG g_cLock = 0;



//***************************************************************************
//
//  DllGetClassObject
//
//***************************************************************************

extern "C"
HRESULT APIENTRY DllGetClassObject(
    REFCLSID rclsid,
    REFIID riid,
    LPVOID * ppv
    )
{
    HRESULT         hr;


    CFactory *pFactory;

    //
    //  Verify the caller is asking for our type of object.
    //
    if (CLSID_MyEventProvider != rclsid) 
            return E_FAIL;

    //
    // Check that we can provide the interface.
    //
    if (IID_IUnknown != riid && IID_IClassFactory != riid)
        return E_NOINTERFACE;

    //
    // Get a new class factory.
    //
    pFactory = new CFactory(rclsid);

    if (!pFactory)
        return E_OUTOFMEMORY;

    //
    // Verify we can get an instance.
    //
    hr = pFactory->QueryInterface(riid, ppv);

    if (FAILED(hr))
        delete pFactory;

    return hr;
}

//***************************************************************************
//
//  DllCanUnloadNow
//
//***************************************************************************
extern "C"
HRESULT APIENTRY DllCanUnloadNow(void)
{
    SCODE sc = TRUE;

    if (g_cObj || g_cLock)
        sc = S_FALSE;

    return sc;
}

//***************************************************************************
//
//***************************************************************************

void ObjectCreated(DWORD dwType)
{
    InterlockedIncrement((LONG *) &g_cObj);
}

void ObjectDestroyed(DWORD dwType)
{
    InterlockedDecrement((LONG *) &g_cObj);
}


//***************************************************************************
//
//  CFactory::CFactory
//
//***************************************************************************

CFactory::CFactory(const CLSID & ClsId)
{
    m_cRef = 0;
    m_ClsId = ClsId;
    ObjectCreated(0);
}

//***************************************************************************
//
//  CFactory::~CFactory
//
//***************************************************************************

CFactory::~CFactory()
{
    // nothing
    ObjectDestroyed(0);
}

//***************************************************************************
//
//  CFactory::QueryInterface, AddRef and Release
//
//***************************************************************************

STDMETHODIMP CFactory::QueryInterface(REFIID riid, LPVOID * ppv)
{
    *ppv = 0;

    if (IID_IUnknown==riid || IID_IClassFactory==riid)
    {
        *ppv = this;
        AddRef();
        return NOERROR;
    }

    return E_NOINTERFACE;
}


ULONG CFactory::AddRef()
{
    return ++m_cRef;
}


ULONG CFactory::Release()
{
    if (0 != --m_cRef)
        return m_cRef;
    delete this;
    return 0;
}

//***************************************************************************
//
//  CFactory::CreateInstance
//
//***************************************************************************

STDMETHODIMP CFactory::CreateInstance(
    LPUNKNOWN pUnkOuter,
    REFIID riid,
    LPVOID * ppvObj)
{
    IUnknown* pObj;
    HRESULT  hr;

    //
    //  Defaults
    //
    *ppvObj=NULL;
    hr = E_OUTOFMEMORY;

    //
    // We aren't supporting aggregation.
    //
    if (pUnkOuter)
        return CLASS_E_NOAGGREGATION;

    if (m_ClsId == CLSID_MyEventProvider)
    {
        pObj = (IWbemProviderInit *) new CMyEventProvider;
    }

    if (!pObj)
        return hr;

    //
    //  Initialize the object and verify that it can return the
    //  interface in question.
    //                                         
    hr = pObj->QueryInterface(riid, ppvObj);

    //
    // Kill the object if initial creation or Init failed.
    //
    if (FAILED(hr))
        delete pObj;

    return hr;
}

//***************************************************************************
//
//***************************************************************************

STDMETHODIMP CFactory::LockServer(BOOL fLock)
{
    if (fLock)
        InterlockedIncrement((LONG *) &g_cLock);
    else
        InterlockedDecrement((LONG *) &g_cLock);

    return NOERROR;
}




//***************************************************************************
//
//  DllRegisterServer
//
//  Standard OLE entry point for registering the server.
//
//  RETURN VALUES:
//
//      S_OK        Registration was successful
//      E_FAIL      Registration failed.
//
//***************************************************************************

extern "C"
HRESULT APIENTRY DllRegisterServer(void)
{
    wchar_t Path[1024];
    wchar_t *pGuidStr = 0;
    wchar_t KeyPath[1024];

    // Where are we?
    // =============
    GetModuleFileNameW(g_hInstance, Path, 1024);

    // Convert CLSID to string.
    // ========================

    StringFromCLSID(CLSID_MyEventProvider, &pGuidStr);
    swprintf(KeyPath, L"CLSID\\\\%s", pGuidStr);

    HKEY hKey;
    LONG lRes = RegCreateKeyW(HKEY_CLASSES_ROOT, KeyPath, &hKey);
    if (lRes)
        return E_FAIL;

    wchar_t *pName = L"WMI Sample Event Provider";
    RegSetValueExW(hKey, 0, 0, REG_SZ, (const BYTE *) pName, (DWORD)(wcslen(pName) * 2 + 2));

    HKEY hSubkey;
    lRes = RegCreateKey(hKey, "InprocServer32", &hSubkey);

    RegSetValueExW(hSubkey, 0, 0, REG_SZ, (const BYTE *) Path, (DWORD)(wcslen(Path) * 2 + 2));
    RegSetValueExW(hSubkey, L"ThreadingModel", 0, REG_SZ, (const BYTE *) L"Both", (DWORD)(wcslen(L"Both") * 2 + 2));

    RegCloseKey(hSubkey);
    RegCloseKey(hKey);

    CoTaskMemFree(pGuidStr);

    return S_OK;
}

//***************************************************************************
//
//  DllUnregisterServer
//
//  Standard OLE entry point for unregistering the server.
//
//  RETURN VALUES:
//
//      S_OK        Unregistration was successful
//      E_FAIL      Unregistration failed.
//
//***************************************************************************

extern "C"
HRESULT APIENTRY DllUnregisterServer(void)
{
    wchar_t *pGuidStr = 0;
    HKEY hKey;
    wchar_t KeyPath[256];

    StringFromCLSID(CLSID_MyEventProvider, &pGuidStr);
    swprintf(KeyPath, L"CLSID\\%s", pGuidStr);

    // Delete InProcServer32 subkey.
    // =============================
    LONG lRes = RegOpenKeyW(HKEY_CLASSES_ROOT, KeyPath, &hKey);
    if (lRes)
        return E_FAIL;

    RegDeleteKeyW(hKey, L"InprocServer32");
    RegCloseKey(hKey);

    // Delete CLSID GUID key.
    // ======================

    lRes = RegOpenKeyW(HKEY_CLASSES_ROOT, L"CLSID", &hKey);
    if (lRes)
        return E_FAIL;

    RegDeleteKeyW(hKey, pGuidStr);
    RegCloseKey(hKey);

    CoTaskMemFree(pGuidStr);

    return S_OK;
}