/*++

Copyright (c) 1998  Microsoft Corporation

Module Name:

    faxshell.cpp

Abstract:

    fax tiff data column provider

Author:

    Andrew Ritz (andrewr) 2-27-98

Environment:

    user-mode

Notes:


Revision History:

    2-27-98 (andrewr) Created.
    8-06-99 (steveke) Major rewrite -> changed from shell extension to column provider

--*/




#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <shlwapip.h>
#include <faxcom.h>
#include <faxcom_i.c>
#include <initguid.h>
#include "faxutil.h"

#include "resource.h"
#include "faxshell.h"



extern "C" int APIENTRY
DllMain(
    HINSTANCE  hInstance,
    DWORD      dwReason,
    LPVOID     pContext
)
/*++

Routine Description:

  DLL entry point

Arguments:

  hInstance - handle to the module
  dwReason - indicates the reason for being called
  pContext - pointer to the context

Return Value:

  TRUE on success

--*/
{
    if (dwReason == DLL_PROCESS_ATTACH) {
        g_hInstance = hInstance;
    }

    return TRUE;
}



STDAPI
DllGetClassObject(
    REFCLSID  rclsid,
    REFIID    riid,
    LPVOID    *ppvOut
)
/*++

Routine Description:

  Retrieves the class object

Arguments:

  rclsid - clsid for the class object
  riid - reference to the identifier of the interface
  ppvOut - interface pointer of the requested identifier

Return Value:

  S_OK on success

--*/
{
    if (ppvOut == NULL) {
        return E_INVALIDARG;
    }

    *ppvOut = NULL;

    // Verify the class id is CLSID_FaxShellExtension
    if (IsEqualCLSID(rclsid, CLSID_FaxShellExtension) == FALSE)
    {
        return CLASS_E_CLASSNOTAVAILABLE;
    }

    // Instantiate a class factory object
    CClassFactory *pClassFactory = new CClassFactory();

    if (pClassFactory == NULL)
    {
        return E_OUTOFMEMORY;
    }

    // Get the interface pointer from QueryInterface and copy it to *ppvOut
    HRESULT hr = pClassFactory->QueryInterface(riid, ppvOut);
    pClassFactory->Release();

    return hr;
}



STDAPI
DllCanUnloadNow(
    VOID
)
/*++

Routine Description:

  Determines whether the the Dll is in use.

Arguments:

  None

Return Value:

  S_OK if the Dll can be unloaded, S_FALSE if the Dll cannot be unloaded

--*/
{
    return (InterlockedCompareExchange(&cLockCount, 0, 0) == 0) ? S_OK : S_FALSE;
}



STDMETHODIMP
CClassFactory::CreateInstance(
    LPUNKNOWN   pUnknown,
    REFIID      riid,
    LPVOID FAR  *ppvOut
)
/*++

Routine Description:

  Creates an uninitialized object

Arguments:

  pUnknown - pointer to controlling IUnknown
  riid - reference to the identifier of the interface
  ppvOut - interface pointer of the requested identifier

Return Value:

  S_OK on success

--*/
{
    if (ppvOut == NULL)
    {
        return E_INVALIDARG;
    }

    *ppvOut = NULL;

    if (pUnknown != NULL)
    {
        return CLASS_E_NOAGGREGATION;
    }

    // Instantiate a fax column provider object
    CFaxColumnProvider *pFaxColumnProvider = new CFaxColumnProvider();

    if (pFaxColumnProvider == NULL)
    {
        return E_OUTOFMEMORY;
    }

    // Get the interface pointer from QueryInterface and copy it to *ppvOut
    HRESULT hr = pFaxColumnProvider->QueryInterface(riid, ppvOut);
    pFaxColumnProvider->Release();

    return hr;
}



STDMETHODIMP
CFaxColumnProvider::GetColumnInfo(
    DWORD         dwIndex,
    SHCOLUMNINFO  *psci
)
/*++

Routine Description:

  Provides information about a column

Arguments:

  dwIndex - column's zero based index
  psci - pointer to an SHCOLUMNINFO structure to hold the column information

Return Value:

  S_OK on success

--*/
{
    ZeroMemory(psci, sizeof(SHCOLUMNINFO));
    
    if (dwIndex < ColumnTableCount)
    {
        WCHAR szColumnName[MAX_COLUMN_NAME_LEN];
        
        // Load the column name
        LoadString(g_hInstance, ColumnTable[dwIndex].dwId, szColumnName, ColumnTable[dwIndex].dwSize);
        lstrcpy(psci->wszTitle, szColumnName);
        lstrcpy(psci->wszDescription, szColumnName);

        psci->scid = *ColumnTable[dwIndex].pscid;
        psci->cChars = lstrlen(szColumnName) + 1;
        psci->vt = ColumnTable[dwIndex].vt;
        psci->fmt = LVCFMT_LEFT;
        psci->csFlags = SHCOLSTATE_TYPE_STR;

        return S_OK;
    }

    return S_FALSE;
}



STDMETHODIMP
CFaxColumnProvider::GetItemData(
    LPCSHCOLUMNID    pscid,
    LPCSHCOLUMNDATA  pscd,
    VARIANT          *pvarData
)
/*++

Routine Description:

  Provides column data for a specified file

Arguments:

  pscid - SHCOLUMNID structure that identifies the column
  pscd - SHCOLUMNDATA structure that specifies the file
  pvarData - pointer to a VARIANT with the data for the file

Return Value:

  S_OK if file data is returned, S_FALSE if the file is not supported by the column provider and no data is returned

--*/
{
    // hr is the result of an object method
    HRESULT  hr = S_FALSE;
    // FaxData is the fax tiff data
    BSTR     FaxData = NULL;

    // Check if file is a directory, which is not supported
    if ((pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == TRUE)
    {
        return S_FALSE;
    }

    // Check if file is supported, i.e. pscd->pwszExt == L".tif"
    if (lstrcmpi(pscd->pwszExt, L".tif") != 0)
    {
        return S_FALSE;
    }

    // Check if the IFaxTiff object exists
    if (m_IFaxTiff == NULL)
    {
        // Create the IFaxTiff object
        hr = CoCreateInstance(CLSID_FaxTiff, NULL, CLSCTX_INPROC_SERVER, IID_IFaxTiff, (LPVOID *) &m_IFaxTiff);
        if (FAILED(hr) == TRUE)
        {
            return hr;
        }
    }

    // Set the full path and file name of the fax tiff
    hr = m_IFaxTiff->put_Image((LPWSTR) pscd->wszFile);
    if (FAILED(hr) == TRUE)
    {
       return hr;
    }

    // Retrieve the fax tiff data
    switch (pscid->pid)
    {
        case PID_SENDERNAME:
            hr = m_IFaxTiff->get_SenderName(&FaxData);
            break;

        case PID_RECIPIENTNAME:
            hr = m_IFaxTiff->get_RecipientName(&FaxData);
            break;

        case PID_RECIPIENTNUMBER:
            hr = m_IFaxTiff->get_RecipientNumber(&FaxData);
            break;

        case PID_CSID:
            hr = m_IFaxTiff->get_Csid(&FaxData);
            break;

        case PID_TSID:
            hr = m_IFaxTiff->get_Tsid(&FaxData);
            break;

        case PID_RECEIVETIME:
            hr = m_IFaxTiff->get_ReceiveTime(&FaxData);
            break;

        case PID_CALLERID:
            hr = m_IFaxTiff->get_CallerId(&FaxData);
            break;

        case PID_ROUTING:
            hr = m_IFaxTiff->get_Routing(&FaxData);
            break;

        default:
            hr = S_FALSE;
    }

    if (FAILED(hr) == TRUE)
    {
       goto e0;
    }

    // Set the column data
    pvarData->vt = VT_BSTR;
    pvarData->bstrVal = SysAllocString(FaxData);
    SysFreeString(FaxData);

    if (pvarData->bstrVal == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto e0;
    }

    hr = S_OK;

e0:
    // Close the file
    m_IFaxTiff->put_Image(L"");

    return hr;
}



STDAPI
DllRegisterServer(
   VOID
)
/*++

Routine Description:

  Function for the in-process server to create its registry entries

Return Value:

  S_OK on success

--*/
{
    // hKey is a handle to the registry key
    HKEY   hKey;
    // szKeyName is the name of a registry key
    WCHAR  szKeyName[MAX_PATH];

    // Register the COM object

    wsprintf(szKeyName, L"%s\\%s", REGKEY_CLASSES_CLSID, REGKEY_FAXSHELL_CLSID);
    hKey = OpenRegistryKey(HKEY_CLASSES_ROOT, szKeyName, TRUE, NULL);
    if (hKey == NULL)
    {
        return E_FAIL;
    }

    SetRegistryString(hKey, NULL, REGVAL_FAXSHELL_TEXT);

    RegCloseKey(hKey);

    wsprintf(szKeyName, L"%s\\%s\\%s", REGKEY_CLASSES_CLSID, REGKEY_FAXSHELL_CLSID, REGKEY_INPROC);
    hKey = OpenRegistryKey(HKEY_CLASSES_ROOT, szKeyName, TRUE, NULL);
    if (hKey == NULL)
    {
        return E_FAIL;
    }

    SetRegistryString(hKey, REGVAL_THREADING, REGVAL_APARTMENT);
    SetRegistryStringExpand(hKey, NULL, REGVAL_LOCATION);

    RegCloseKey(hKey);

    // Register the column provider

    wsprintf(szKeyName, L"%s\\%s", REGKEY_COLUMNHANDLERS, REGKEY_FAXSHELL_CLSID);
    hKey = OpenRegistryKey(HKEY_CLASSES_ROOT, szKeyName, TRUE, NULL);
    if (hKey == NULL)
    {
        return E_FAIL;
    }

    SetRegistryString(hKey, NULL, REGVAL_FAXSHELL_TEXT);

    RegCloseKey(hKey);

    return S_OK;
}



STDAPI
DllUnregisterServer(
   VOID
)
/*++

Routine Description:

  Function for the in-process server to remove its registry entries

Return Value:

  S_OK on success

--*/
{
    // szKeyName is the name of a registry key
    WCHAR  szKeyName[MAX_PATH];

    // Unregister the COM object

    wsprintf(szKeyName, L"%s\\%s", REGKEY_CLASSES_CLSID, REGKEY_FAXSHELL_CLSID);
    if (DeleteRegistryKey(HKEY_CLASSES_ROOT, szKeyName) == FALSE)
    {
        return E_FAIL;
    }

    // Unregister the column provider

    wsprintf(szKeyName, L"%s\\%s", REGKEY_COLUMNHANDLERS, REGKEY_FAXSHELL_CLSID);
    if (DeleteRegistryKey(HKEY_CLASSES_ROOT, szKeyName) == FALSE)
    {
        return E_FAIL;
    }

    return S_OK;
}