/*++

Copyright (C) 1997-2001  Microsoft Corporation

Module Name:

    dataobj.cpp

Abstract:

    header file defines CDataObject class

Author:

    William Hsieh (williamh) created

Revision History:


--*/

#include "devmgr.h"
#include "DataObj.h"


unsigned int CDataObject::m_cfNodeType       = RegisterClipboardFormat(CCF_NODETYPE);
unsigned int CDataObject::m_cfNodeTypeString = RegisterClipboardFormat(CCF_SZNODETYPE);
unsigned int CDataObject::m_cfDisplayName    = RegisterClipboardFormat(CCF_DISPLAY_NAME);
unsigned int CDataObject::m_cfCoClass        = RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
unsigned int CDataObject::m_cfSnapinInternal    = RegisterClipboardFormat(SNAPIN_INTERNAL);
unsigned int CDataObject::m_cfMachineName    = RegisterClipboardFormat(MMC_SNAPIN_MACHINE_NAME);
unsigned int CDataObject::m_cfClassGuid      = RegisterClipboardFormat(DEVMGR_SNAPIN_CLASS_GUID);
unsigned int CDataObject::m_cfDeviceID       = RegisterClipboardFormat(DEVMGR_SNAPIN_DEVICE_ID);

//
// IUnknown interface implementation
//

ULONG
CDataObject::AddRef()
{
    ::InterlockedIncrement((LONG*)&m_Ref);
    return m_Ref;
}

ULONG
CDataObject::Release()
{
    ::InterlockedDecrement((LONG*)&m_Ref);
    if (!m_Ref) {
        delete this;
        return 0;
    }
    return m_Ref;
}

STDMETHODIMP
CDataObject::QueryInterface(
                           REFIID riid,
                           void** ppv
                           )
{
    if (!ppv)
        return E_INVALIDARG;
    HRESULT hr = S_OK;

    if (IsEqualIID(riid, IID_IUnknown))
        *ppv = (IUnknown*)this;
    else if (IsEqualIID(riid, IID_IDataObject)) {
        *ppv = this;
    } else {
        hr = E_NOINTERFACE;
    }
    if (SUCCEEDED(hr))
        AddRef();
    else
        *ppv = NULL;
    return hr;
}

HRESULT
CDataObject::Initialize(
                       DATA_OBJECT_TYPES Type,
                       COOKIE_TYPE      ct,
                       CCookie* pCookie,
                       String& strMachineName
                       )
{
    try {
        m_strMachineName = strMachineName;
        m_pCookie = pCookie;
        m_Type = Type;
        m_ct = ct;
    } catch (CMemoryException* e) {
        e->Delete();
        return E_OUTOFMEMORY;
    }
    return S_OK;

}


STDMETHODIMP
CDataObject::GetDataHere(
                        LPFORMATETC lpFormatetc,
                        LPSTGMEDIUM lpMedium
                        )
{
    HRESULT hr = S_OK;

    try {
        const CLIPFORMAT cf = lpFormatetc->cfFormat;
        hr = DV_E_FORMATETC;
        SafeInterfacePtr<IStream> StreamPtr;

        if (TYMED_HGLOBAL == lpMedium->tymed) {
            ULONG ulWritten;
            hr = CreateStreamOnHGlobal(lpMedium->hGlobal, FALSE, &StreamPtr);

            if (S_OK == hr) {
                const NODEINFO* pni = &NodeInfo[m_ct];
                ASSERT(pni->ct == m_ct);

                if (cf == m_cfNodeType) {
                    const GUID* pGuid = &pni->Guid;
                    hr = StreamPtr->Write(pGuid, sizeof(GUID), &ulWritten);
                } else if (cf == m_cfNodeTypeString) {
                    const TCHAR *pszGuid = pni->GuidString;
                    hr = StreamPtr->Write(pszGuid,
                                          (wcslen(pszGuid) + 1) * sizeof(TCHAR),
                                          &ulWritten
                                         );
                } else if (cf == m_cfDisplayName) {
                    if (pni->idsFormat) {
                        String strDisplayName;
                        TCHAR Format[LINE_LEN];
                        TCHAR LocalMachine[LINE_LEN];
                        ::LoadString(g_hInstance, pni->idsFormat, Format, sizeof(Format)/sizeof(TCHAR));
                        LPCTSTR MachineName = m_strMachineName;

                        if (m_strMachineName.IsEmpty()) {
                            ::LoadString(g_hInstance, IDS_LOCAL_MACHINE, LocalMachine,
                                         sizeof(LocalMachine) / sizeof(TCHAR));
                            MachineName = LocalMachine;
                        }

                        strDisplayName.Format(Format, MachineName);
                        hr = StreamPtr->Write(strDisplayName,
                                              (strDisplayName.GetLength() + 1) * sizeof(TCHAR),
                                              &ulWritten
                                             );
                    }
                } else if (cf == m_cfSnapinInternal) {
                    INTERNAL_DATA tID;
                    tID.ct = m_ct;
                    tID.dot = m_Type;
                    tID.cookie = (MMC_COOKIE)m_pCookie;
                    hr = StreamPtr->Write(&tID,
                                          sizeof(INTERNAL_DATA),
                                          &ulWritten
                                         );
                } else if (cf == m_cfCoClass) {
                    hr = StreamPtr->Write(&CLSID_DEVMGR,
                                          sizeof(CLSID),
                                          &ulWritten
                                         );
                } else if (cf == m_cfMachineName) {
                    if (!m_strMachineName.IsEmpty()) {
                        hr = StreamPtr->Write((LPCTSTR)m_strMachineName,
                                              (m_strMachineName.GetLength()+1) * sizeof(TCHAR),
                                              NULL);
                    } else {
                        TCHAR Nothing[1];
                        Nothing[0] = _T('\0');
                        hr = StreamPtr->Write(Nothing, sizeof(Nothing), NULL);
                    }
                } else if (cf == m_cfClassGuid) {
                    if (COOKIE_TYPE_RESULTITEM_CLASS == m_pCookie->GetType()) {
                        CClass* pClass = (CClass*)m_pCookie->GetResultItem();
                        ASSERT(pClass);
                        LPGUID pClassGuid = *pClass;
                        hr = StreamPtr->Write(pClassGuid, sizeof(GUID), NULL);
                    }
                } else if (cf == m_cfDeviceID) {
                    if (COOKIE_TYPE_RESULTITEM_DEVICE == m_pCookie->GetType()) {
                        CDevice* pDevice = (CDevice*)m_pCookie->GetResultItem();
                        ASSERT(pDevice);
                        LPCTSTR DeviceID = pDevice->GetDeviceID();

                        hr = StreamPtr->Write(DeviceID,
                                              (wcslen(DeviceID) + 1) * sizeof(TCHAR),
                                              NULL
                                             );
                    }
                } else {
                    hr = DV_E_FORMATETC;
                }
            }
        }
    } catch (CMemoryException* e) {
        e->Delete();
        hr = E_OUTOFMEMORY;
    }

    return hr;
}


STDMETHODIMP
CDataObject::GetData(
                    LPFORMATETC lpFormatetc,
                    LPSTGMEDIUM lpMedium
                    )
{
    return E_NOTIMPL;
}

STDMETHODIMP
CDataObject::EnumFormatEtc(
                          DWORD dwDirection,
                          LPENUMFORMATETC* ppEnumFormatEtc
                          )
{
    return E_NOTIMPL;
}




HRESULT ExtractData(
                   IDataObject* pIDataObject,
                   unsigned int cfClipFormat,
                   BYTE*    pBuffer,
                   DWORD    cbBuffer
                   )
{

    if (NULL == pIDataObject || NULL == pBuffer)
        return E_POINTER;

    HRESULT hr = S_OK;
    FORMATETC FormatEtc = {(CLIPFORMAT)cfClipFormat, NULL, DVASPECT_CONTENT, -1 , TYMED_HGLOBAL};
    STGMEDIUM StgMedium = {TYMED_HGLOBAL, NULL};

    StgMedium.hGlobal = ::GlobalAlloc(GMEM_SHARE, cbBuffer);
    if (NULL == StgMedium.hGlobal) {
        ASSERT(FALSE);
        hr = E_OUTOFMEMORY;
    } else {
        hr = pIDataObject->GetDataHere(&FormatEtc, &StgMedium);
        if (SUCCEEDED(hr)) {
            BYTE* pData = reinterpret_cast<BYTE*>(::GlobalLock(StgMedium.hGlobal));
            if (NULL == pData) {
                ASSERT(FALSE);
                hr = E_UNEXPECTED;
            } else {
                ::memcpy(pBuffer, pData, cbBuffer);
                ::GlobalUnlock(StgMedium.hGlobal);
            }
        }
        ::GlobalFree(StgMedium.hGlobal);
    }
    return hr;
}

#if 0

/////////////////////////////////////////////////////////////////////
////
/// Helper functions to extact data from the given IDataObject
///

HRESULT ExtractData(IDataObject* piDataObject,
                    unsigned int cfClipFormat,
                    BYTE*    pBuffer,
                    DWORD    cbBuffer
                   );
HRESULT ExtractString(IDataObject* piDataObject,
                      unsigned int cfClipFormat,
                      String* pstr,
                      DWORD    cchMax
                     );



HRESULT
ExtractData(
           IDataObject* piDataObject,
           unsigned int cfClipFormat,
           BYTE*    pBuffer,
           DWORD    cbBuffer
           )
{
    HRESULT hr = S_OK;
    FORMATETC Formatetc = {cfClipFormat, NULL, DVASPET_CONTENT, -1, TYMED_HGLOBAL};
    STGMEDIUM Stgmedium = {TYMED_HGLOBAL, NULL};
    Stgmedium.hGlobal = ::GlobalAlloc(GMEM_SHARE, cbBuffer);

    if (NULL == Stgmedium.hGlobal) {
        ASSERT(FASLE);
        AfxThrowMemoryException();
        hr = E_OUTOFMEMORY;
        return hr;
    }
    hr = piDataObject->GetDataHere(&Formatetc, &Stgmedium);
    if (FAILED(hr)) {
        ASSERT(FALSE);
        return hr;
    }
    BYTE* pData = reinterpret_cast<BYTE*>(::GlobalLock(Stgmedium.hGlobal));
    if (NULL == pData) {
        ASSERT(FALSE);
        hr = E_UNEXPECTED;
    }
    ::memcpy(pBuffer, pData, cbBuffer);
    return hr;
}

HRESULT
ExtractString(
             IDataObject* piDataObject,
             unsigned int cfClipFormat,
             String* pstr
             DWORD   cbMax
             )
{
    FORMATETC Formatetc = {cfClipFormat, NULL, DVASPET_CONTENT, -1, TYMED_HGLOBAL};
    STGMEDIUM Stgmedium = {TYMED_HGLOBAL, NULL};
    Stgmedium.hGlobal = ::GlobalAlloc(GMEM_SHARE, cbBuffer);

    if (NULL == Stgmedium.hGlobal) {
        ASSERT(FASLE);
        AfxThrowMemoryException();
        hr = E_OUTOFMEMORY;
        return hr;
    }
    HRESULT hr = piDataObject->GetDataHere(&Formatetc, &Stgmedium);
    if (FAILED(hr)) {
        ASSERT(FALSE);
        return hr;
    }
    LPTSTR pszData = reinterpret_cast<LPTSTR>(::GlobalLock(Stgmedium.hGlobal));
    if (NULL == pszData) {
        ASSERT(FALSE);
        return E_UNEXPECTTED;
    }
    USES_CONVERSION;
    *pstr = OLE2T(pszData);
    return S_OK;
}
#endif