When the command "guest-fsfreeze-freeze" is executed it causes the VSS service to log the error below in the Event Viewer. This error is caused by an issue in the function "CommitSnapshots" in provider.cpp: * When VSS_TIMEOUT_MSEC expires the funtion returns E_ABORT. This causes the error #12293. |event id| error | * 12293 : Volume Shadow Copy Service error: Error calling a routine on a Shadow Copy Provider {00000000-0000-0000-0000-000000000000}. Routine details CommitSnapshots [hr = 0x80004004, Operation aborted. Signed-off-by: Sameeh Jubran <sameeh@daynix.com> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
		
			
				
	
	
		
			534 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			534 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * QEMU Guest Agent win32 VSS Provider implementations
 | 
						|
 *
 | 
						|
 * Copyright Hitachi Data Systems Corp. 2013
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *  Tomoki Sekiyama   <tomoki.sekiyama@hds.com>
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | 
						|
 * See the COPYING file in the top-level directory.
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "vss-common.h"
 | 
						|
#include <inc/win2003/vscoordint.h>
 | 
						|
#include <inc/win2003/vsprov.h>
 | 
						|
 | 
						|
#define VSS_TIMEOUT_MSEC (60*1000)
 | 
						|
 | 
						|
static long g_nComObjsInUse;
 | 
						|
HINSTANCE g_hinstDll;
 | 
						|
 | 
						|
/* VSS common GUID's */
 | 
						|
 | 
						|
const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
 | 
						|
    {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
 | 
						|
const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
 | 
						|
    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
 | 
						|
 | 
						|
const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
 | 
						|
    {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
 | 
						|
const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
 | 
						|
    {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
 | 
						|
const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
 | 
						|
    {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
 | 
						|
const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
 | 
						|
    {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
 | 
						|
 | 
						|
const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
 | 
						|
    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
 | 
						|
 | 
						|
 | 
						|
void LockModule(BOOL lock)
 | 
						|
{
 | 
						|
    if (lock) {
 | 
						|
        InterlockedIncrement(&g_nComObjsInUse);
 | 
						|
    } else {
 | 
						|
        InterlockedDecrement(&g_nComObjsInUse);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Empty enumerator for VssObject */
 | 
						|
 | 
						|
class CQGAVSSEnumObject : public IVssEnumObject
 | 
						|
{
 | 
						|
public:
 | 
						|
    STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
 | 
						|
    STDMETHODIMP_(ULONG) AddRef();
 | 
						|
    STDMETHODIMP_(ULONG) Release();
 | 
						|
 | 
						|
    /* IVssEnumObject Methods */
 | 
						|
    STDMETHODIMP Next(
 | 
						|
        ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
 | 
						|
    STDMETHODIMP Skip(ULONG celt);
 | 
						|
    STDMETHODIMP Reset(void);
 | 
						|
    STDMETHODIMP Clone(IVssEnumObject **ppenum);
 | 
						|
 | 
						|
    /* CQGAVSSEnumObject Methods */
 | 
						|
    CQGAVSSEnumObject();
 | 
						|
    ~CQGAVSSEnumObject();
 | 
						|
 | 
						|
private:
 | 
						|
    long m_nRefCount;
 | 
						|
};
 | 
						|
 | 
						|
CQGAVSSEnumObject::CQGAVSSEnumObject()
 | 
						|
{
 | 
						|
    m_nRefCount = 0;
 | 
						|
    LockModule(TRUE);
 | 
						|
}
 | 
						|
 | 
						|
CQGAVSSEnumObject::~CQGAVSSEnumObject()
 | 
						|
{
 | 
						|
    LockModule(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
 | 
						|
{
 | 
						|
    if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
 | 
						|
        *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    *ppObj = NULL;
 | 
						|
    return E_NOINTERFACE;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
 | 
						|
{
 | 
						|
    return InterlockedIncrement(&m_nRefCount);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
 | 
						|
{
 | 
						|
    long nRefCount = InterlockedDecrement(&m_nRefCount);
 | 
						|
    if (m_nRefCount == 0) {
 | 
						|
        delete this;
 | 
						|
    }
 | 
						|
    return nRefCount;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVSSEnumObject::Next(
 | 
						|
    ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
 | 
						|
{
 | 
						|
    *pceltFetched = 0;
 | 
						|
    return S_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
 | 
						|
{
 | 
						|
    return S_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVSSEnumObject::Reset(void)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
 | 
						|
{
 | 
						|
    return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* QGAVssProvider */
 | 
						|
 | 
						|
class CQGAVssProvider :
 | 
						|
    public IVssSoftwareSnapshotProvider,
 | 
						|
    public IVssProviderCreateSnapshotSet,
 | 
						|
    public IVssProviderNotifications
 | 
						|
{
 | 
						|
public:
 | 
						|
    STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
 | 
						|
    STDMETHODIMP_(ULONG) AddRef();
 | 
						|
    STDMETHODIMP_(ULONG) Release();
 | 
						|
 | 
						|
    /* IVssSoftwareSnapshotProvider Methods */
 | 
						|
    STDMETHODIMP SetContext(LONG lContext);
 | 
						|
    STDMETHODIMP GetSnapshotProperties(
 | 
						|
        VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
 | 
						|
    STDMETHODIMP Query(
 | 
						|
        VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
 | 
						|
        VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
 | 
						|
    STDMETHODIMP DeleteSnapshots(
 | 
						|
        VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
 | 
						|
        BOOL bForceDelete, LONG *plDeletedSnapshots,
 | 
						|
        VSS_ID *pNondeletedSnapshotID);
 | 
						|
    STDMETHODIMP BeginPrepareSnapshot(
 | 
						|
        VSS_ID SnapshotSetId, VSS_ID SnapshotId,
 | 
						|
        VSS_PWSZ pwszVolumeName, LONG lNewContext);
 | 
						|
    STDMETHODIMP IsVolumeSupported(
 | 
						|
        VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
 | 
						|
    STDMETHODIMP IsVolumeSnapshotted(
 | 
						|
        VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
 | 
						|
        LONG *plSnapshotCompatibility);
 | 
						|
    STDMETHODIMP SetSnapshotProperty(
 | 
						|
        VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
 | 
						|
        VARIANT vProperty);
 | 
						|
    STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
 | 
						|
    STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
 | 
						|
 | 
						|
    /* IVssProviderCreateSnapshotSet Methods */
 | 
						|
    STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
 | 
						|
    STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
 | 
						|
    STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
 | 
						|
    STDMETHODIMP PostCommitSnapshots(
 | 
						|
        VSS_ID SnapshotSetId, LONG lSnapshotsCount);
 | 
						|
    STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
 | 
						|
    STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
 | 
						|
    STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
 | 
						|
 | 
						|
    /* IVssProviderNotifications Methods */
 | 
						|
    STDMETHODIMP OnLoad(IUnknown *pCallback);
 | 
						|
    STDMETHODIMP OnUnload(BOOL bForceUnload);
 | 
						|
 | 
						|
    /* CQGAVssProvider Methods */
 | 
						|
    CQGAVssProvider();
 | 
						|
    ~CQGAVssProvider();
 | 
						|
 | 
						|
private:
 | 
						|
    long m_nRefCount;
 | 
						|
};
 | 
						|
 | 
						|
CQGAVssProvider::CQGAVssProvider()
 | 
						|
{
 | 
						|
    m_nRefCount = 0;
 | 
						|
    LockModule(TRUE);
 | 
						|
}
 | 
						|
 | 
						|
CQGAVssProvider::~CQGAVssProvider()
 | 
						|
{
 | 
						|
    LockModule(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
 | 
						|
{
 | 
						|
    if (riid == IID_IUnknown) {
 | 
						|
        *ppObj = static_cast<void*>(this);
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    if (riid == IID_IVssSoftwareSnapshotProvider) {
 | 
						|
        *ppObj = static_cast<void*>(
 | 
						|
            static_cast<IVssSoftwareSnapshotProvider*>(this));
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    if (riid == IID_IVssProviderCreateSnapshotSet) {
 | 
						|
        *ppObj = static_cast<void*>(
 | 
						|
            static_cast<IVssProviderCreateSnapshotSet*>(this));
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    if (riid == IID_IVssProviderNotifications) {
 | 
						|
        *ppObj = static_cast<void*>(
 | 
						|
            static_cast<IVssProviderNotifications*>(this));
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    *ppObj = NULL;
 | 
						|
    return E_NOINTERFACE;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
 | 
						|
{
 | 
						|
    return InterlockedIncrement(&m_nRefCount);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
 | 
						|
{
 | 
						|
    long nRefCount = InterlockedDecrement(&m_nRefCount);
 | 
						|
    if (m_nRefCount == 0) {
 | 
						|
        delete this;
 | 
						|
    }
 | 
						|
    return nRefCount;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * IVssSoftwareSnapshotProvider methods
 | 
						|
 */
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
 | 
						|
    VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
 | 
						|
{
 | 
						|
    return VSS_E_OBJECT_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::Query(
 | 
						|
    VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
 | 
						|
    VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
 | 
						|
{
 | 
						|
    try {
 | 
						|
        *ppEnum = new CQGAVSSEnumObject;
 | 
						|
    } catch (...) {
 | 
						|
        return E_OUTOFMEMORY;
 | 
						|
    }
 | 
						|
    (*ppEnum)->AddRef();
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
 | 
						|
    VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
 | 
						|
    BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
 | 
						|
{
 | 
						|
    *plDeletedSnapshots = 0;
 | 
						|
    *pNondeletedSnapshotID = SourceObjectId;
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
 | 
						|
    VSS_ID SnapshotSetId, VSS_ID SnapshotId,
 | 
						|
    VSS_PWSZ pwszVolumeName, LONG lNewContext)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
 | 
						|
    VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
 | 
						|
{
 | 
						|
    HANDLE hEventFrozen;
 | 
						|
 | 
						|
    /* Check if a requester is qemu-ga by whether an event is created */
 | 
						|
    hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
 | 
						|
    if (!hEventFrozen) {
 | 
						|
        *pbSupportedByThisProvider = FALSE;
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    CloseHandle(hEventFrozen);
 | 
						|
 | 
						|
    *pbSupportedByThisProvider = TRUE;
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
 | 
						|
    BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
 | 
						|
{
 | 
						|
    *pbSnapshotsPresent = FALSE;
 | 
						|
    *plSnapshotCompatibility = 0;
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
 | 
						|
    VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
 | 
						|
{
 | 
						|
    return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
 | 
						|
{
 | 
						|
    return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
 | 
						|
    VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
 | 
						|
{
 | 
						|
    return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * IVssProviderCreateSnapshotSet methods
 | 
						|
 */
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    HRESULT hr = S_OK;
 | 
						|
    HANDLE hEventFrozen, hEventThaw, hEventTimeout;
 | 
						|
 | 
						|
    hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
 | 
						|
    if (!hEventFrozen) {
 | 
						|
        return E_FAIL;
 | 
						|
    }
 | 
						|
 | 
						|
    hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
 | 
						|
    if (!hEventThaw) {
 | 
						|
        CloseHandle(hEventFrozen);
 | 
						|
        return E_FAIL;
 | 
						|
    }
 | 
						|
 | 
						|
    hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
 | 
						|
    if (!hEventTimeout) {
 | 
						|
        CloseHandle(hEventFrozen);
 | 
						|
        CloseHandle(hEventThaw);
 | 
						|
        return E_FAIL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Send event to qemu-ga to notify filesystem is frozen */
 | 
						|
    SetEvent(hEventFrozen);
 | 
						|
 | 
						|
    /* Wait until the snapshot is taken by the host. */
 | 
						|
    if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
 | 
						|
        /* Send event to qemu-ga to notify the provider is timed out */
 | 
						|
        SetEvent(hEventTimeout);
 | 
						|
    }
 | 
						|
 | 
						|
    CloseHandle(hEventThaw);
 | 
						|
    CloseHandle(hEventFrozen);
 | 
						|
    CloseHandle(hEventTimeout);
 | 
						|
    return hr;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
 | 
						|
    VSS_ID SnapshotSetId, LONG lSnapshotsCount)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * IVssProviderNotifications methods
 | 
						|
 */
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
 | 
						|
{
 | 
						|
    return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * CQGAVssProviderFactory class
 | 
						|
 */
 | 
						|
 | 
						|
class CQGAVssProviderFactory : public IClassFactory
 | 
						|
{
 | 
						|
public:
 | 
						|
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
 | 
						|
    STDMETHODIMP_(ULONG) AddRef();
 | 
						|
    STDMETHODIMP_(ULONG) Release();
 | 
						|
    STDMETHODIMP CreateInstance(
 | 
						|
        IUnknown *pUnknownOuter, REFIID iid, void **ppv);
 | 
						|
    STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
 | 
						|
 | 
						|
    CQGAVssProviderFactory();
 | 
						|
    ~CQGAVssProviderFactory();
 | 
						|
 | 
						|
private:
 | 
						|
    long m_nRefCount;
 | 
						|
};
 | 
						|
 | 
						|
CQGAVssProviderFactory::CQGAVssProviderFactory()
 | 
						|
{
 | 
						|
    m_nRefCount = 0;
 | 
						|
    LockModule(TRUE);
 | 
						|
}
 | 
						|
 | 
						|
CQGAVssProviderFactory::~CQGAVssProviderFactory()
 | 
						|
{
 | 
						|
    LockModule(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
 | 
						|
{
 | 
						|
    if (riid == IID_IUnknown || riid == IID_IClassFactory) {
 | 
						|
        *ppv = static_cast<void*>(this);
 | 
						|
        AddRef();
 | 
						|
        return S_OK;
 | 
						|
    }
 | 
						|
    *ppv = NULL;
 | 
						|
    return E_NOINTERFACE;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
 | 
						|
{
 | 
						|
    return InterlockedIncrement(&m_nRefCount);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
 | 
						|
{
 | 
						|
    long nRefCount = InterlockedDecrement(&m_nRefCount);
 | 
						|
    if (m_nRefCount == 0) {
 | 
						|
        delete this;
 | 
						|
    }
 | 
						|
    return nRefCount;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
 | 
						|
    IUnknown *pUnknownOuter, REFIID iid, void **ppv)
 | 
						|
{
 | 
						|
    CQGAVssProvider *pObj;
 | 
						|
 | 
						|
    if (pUnknownOuter) {
 | 
						|
        return CLASS_E_NOAGGREGATION;
 | 
						|
    }
 | 
						|
    try {
 | 
						|
        pObj = new CQGAVssProvider;
 | 
						|
    } catch (...) {
 | 
						|
        return E_OUTOFMEMORY;
 | 
						|
    }
 | 
						|
    HRESULT hr = pObj->QueryInterface(iid, ppv);
 | 
						|
    if (FAILED(hr)) {
 | 
						|
        delete pObj;
 | 
						|
    }
 | 
						|
    return hr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * DLL functions
 | 
						|
 */
 | 
						|
 | 
						|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 | 
						|
{
 | 
						|
    CQGAVssProviderFactory *factory;
 | 
						|
    try {
 | 
						|
        factory = new CQGAVssProviderFactory;
 | 
						|
    } catch (...) {
 | 
						|
        return E_OUTOFMEMORY;
 | 
						|
    }
 | 
						|
    factory->AddRef();
 | 
						|
    HRESULT hr = factory->QueryInterface(riid, ppv);
 | 
						|
    factory->Release();
 | 
						|
    return hr;
 | 
						|
}
 | 
						|
 | 
						|
STDAPI DllCanUnloadNow()
 | 
						|
{
 | 
						|
    return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
EXTERN_C
 | 
						|
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
 | 
						|
{
 | 
						|
    if (dwReason == DLL_PROCESS_ATTACH) {
 | 
						|
        g_hinstDll = hinstDll;
 | 
						|
        DisableThreadLibraryCalls(hinstDll);
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
}
 |