////////////////////////////////////
// (C) COPYRIGHT MICROSOFT CORP., 1998-1999
//
// FILE: EXTEND.CPP
//
// DESCRIPTION: Implements core DLL routines as well as web view extensions.
//
#include "precomp.h"
#pragma hdrstop
#include <string.h>
#include <tchar.h>
#include "resource.h"

#include "extidl_i.c"

CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_TestShellExt,  CShellExt)
OBJECT_ENTRY(CLSID_TestUIExtension,  CWiaUIExtension)
END_OBJECT_MAP()


STDAPI DllRegisterServer(void)
{

    // registers object, typelib and all interfaces in typelib
    return _Module.RegisterServer(TRUE);
}


STDAPI DllUnregisterServer(void)
{
    return _Module.UnregisterServer();
}


EXTERN_C
BOOL
DllMain(
    HINSTANCE   hinst,
    DWORD       dwReason,
    LPVOID      lpReserved)
{
    switch (dwReason) {
        case DLL_PROCESS_ATTACH:

            _Module.Init (ObjectMap, hinst);
            DisableThreadLibraryCalls(hinst);

            break;

        case DLL_PROCESS_DETACH:
            _Module.Term();
            break;
    }
    return TRUE;
}


extern "C" STDMETHODIMP DllCanUnloadNow(void)
{
    return _Module.GetLockCount()==0 ? S_OK : S_FALSE;
}

extern "C" STDAPI DllGetClassObject(
    REFCLSID    rclsid,
    REFIID      riid,
    LPVOID      *ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);

}


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

ShowMessage

Utility function for displaying messageboxes

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

BOOL ShowMessage (HWND hParent, INT idCaption, INT idMessage)
{
    MSGBOXPARAMS mbp;
    BOOL bRet;
    INT  i;

    ZeroMemory (&mbp, sizeof(mbp));
    mbp.cbSize = sizeof(mbp);
    mbp.hwndOwner = hParent;
    mbp.hInstance = g_hInst;
    mbp.lpszText = MAKEINTRESOURCE(idMessage);
    mbp.lpszCaption = MAKEINTRESOURCE(idCaption);
    mbp.dwStyle = MB_OK | MB_APPLMODAL;

    i = MessageBoxIndirect (&mbp);
    bRet = (IDOK==i);
    return bRet;
}

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

FindLastID

Utility for getting the last relative pidl from a full pidl

******************************************************************************/
// unsafe macros
#define _ILSkip(pidl, cb)       ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
#define ILNext(pidl)           _ILSkip(pidl, (pidl)->mkid.cb)

LPITEMIDLIST
FindLastID(LPCITEMIDLIST pidl)
{
    LPCITEMIDLIST pidlLast = pidl;
    LPCITEMIDLIST pidlNext = pidl;

    if (pidl == NULL)
        return NULL;

    // Find the last one
    while (pidlNext->mkid.cb)
    {
        pidlLast = pidlNext;
        pidlNext = ILNext(pidlLast);
    }

    return (LPITEMIDLIST)pidlLast;
}

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

CreateDeviceFromID

Utility for attaching to WIA and getting a root IWiaItem interface

*****************************************************************************/
HRESULT
CreateDeviceFromId (LPWSTR szDeviceId, IWiaItem **ppItem)
{
    IWiaDevMgr *pDevMgr;
    HRESULT hr = CoCreateInstance (CLSID_WiaDevMgr,
                                   NULL,
                                   CLSCTX_LOCAL_SERVER,
                                   IID_IWiaDevMgr,
                                   reinterpret_cast<LPVOID*>(&pDevMgr));
    if (SUCCEEDED(hr))
    {
        BSTR strId = SysAllocString (szDeviceId);
        hr = pDevMgr->CreateDevice (strId, ppItem);
        SysFreeString (strId);
        pDevMgr->Release ();
    }
    return hr;
}

/*****************************************************************************\

    GetNamesFromDataObject

    Return the list of selected item identifiers. Each identifier is of the form
    "<DEVICEID>::<FULL PATH NAME>". the list is double-null terminated

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

LPWSTR
GetNamesFromDataObject (IDataObject *lpdobj, UINT *puItems)
{
    FORMATETC fmt;
    STGMEDIUM stg;
    LPWSTR szRet = NULL;
    LPWSTR szCurrent;
    UINT nItems;
    size_t size;
    if (puItems)
    {
        *puItems = 0;
    }

    fmt.cfFormat = (CLIPFORMAT) RegisterClipboardFormat (TEXT("WIAItemNames"));
    fmt.dwAspect = DVASPECT_CONTENT;
    fmt.lindex = -1;
    fmt.ptd = NULL;
    fmt.tymed = TYMED_HGLOBAL;

    if (lpdobj && puItems && SUCCEEDED(lpdobj->GetData (&fmt, &stg)))
    {
        szCurrent = reinterpret_cast<LPWSTR>(GlobalLock (stg.hGlobal));

        // count the number of items in the double-null terminated string
        szRet  = szCurrent;
        nItems = 0;
        while (*szRet)
        {
            nItems++;
            while (*szRet)
            {
                szRet++;
            }
            szRet++;
        }
        *puItems = nItems;
        size = (szRet-szCurrent+1)*sizeof(WCHAR);
        szRet = new WCHAR[size];
        CopyMemory (szRet, szCurrent, size);
        GlobalUnlock (stg.hGlobal);
        GlobalFree (stg.hGlobal);
    }
    return szRet;
}

CWiaUIExtension::CWiaUIExtension(void)
{
}

CWiaUIExtension::~CWiaUIExtension(void)
{
}

//
// IWiaUIExtension
//
STDMETHODIMP CWiaUIExtension::DeviceDialog( PDEVICEDIALOGDATA pDeviceDialogData )
{
    //
    // We are not going to implement an actual device dialog here.  Just say "hi" and return.
    //
    MessageBox( NULL, TEXT("CWiaUIExtension::DeviceDialog is being called"), TEXT("DEBUG"), 0 );
    return E_NOTIMPL;
}

STDMETHODIMP CWiaUIExtension::GetDeviceIcon( BSTR bstrDeviceId, HICON *phIcon, ULONG nSize )
{
    //
    // Load an icon, and copy it, using CopyIcon, so it will still be valid if our interface is freed
    //
    HICON hIcon = reinterpret_cast<HICON>(LoadImage( _Module.m_hInst, MAKEINTRESOURCE(IDI_TESTDEVICE), IMAGE_ICON, nSize, nSize, LR_DEFAULTCOLOR ));
    if (hIcon)
    {
        *phIcon = CopyIcon(hIcon);
        DestroyIcon(hIcon);
        return S_OK;
    }
    return E_NOTIMPL;
}

STDMETHODIMP CWiaUIExtension::GetDeviceBitmapLogo( BSTR bstrDeviceId, HBITMAP *phBitmap, ULONG nMaxWidth, ULONG nMaxHeight )
{
    //
    // This method is never actually called currently.  It is only here for future use.
    //
    MessageBox( NULL, TEXT("CWiaUIExtension::GetDeviceBitmapLogo is being called"), TEXT("DEBUG"), 0 );
    return E_NOTIMPL;
}

