/*******************************************************************************
*
*  (C) COPYRIGHT MICROSOFT CORP., 1998
*
*  TITLE:       AddDevice.cpp
*
*  VERSION:     2.0
*
*  AUTHOR:      Marke
*
*  DATE:        9 Jan, 1998
*
*  DESCRIPTION:
*   Temp UI for adding Wia remote devices
*
*******************************************************************************/
#include "precomp.h"
#include "stiexe.h"

#include <wiamindr.h>
#include <wiadbg.h>

#include "wiacfact.h"
#include "devmgr.h"
#include "devinfo.h"
#include "resource.h"
#include "helpers.h"

//
// global info
//

WIA_ADD_DEVICE  *gpAddDev;
IWiaDevMgr      *gpIWiaDevMgr;

extern HINSTANCE g_hInst;

#define REGSTR_PATH_STICONTROL_W            L"System\\CurrentControlSet\\Control\\StillImage"
#define REGSTR_PATH_STICONTROL_DEVLIST_W    L"System\\CurrentControlSet\\Control\\StillImage\\DevList"

#ifdef WINNT

/**************************************************************************\
* AddDeviceDlgProc
*
*   Dialog proc for add device dialog.
*
* Arguments:
*
*   hDlg    - window handle of the dialog box
*   message - type of message
*   wParam  - message-specific information
*   lParam  - message-specific information
*
* Return Value:
*
*    Status
*
* History:
*
*    1/11/1999 Original Version
*
\**************************************************************************/

INT_PTR
APIENTRY AddDeviceDlgProc(
   HWND     hDlg,
   UINT     message,
   WPARAM   wParam,
   LPARAM   lParam
)
{
    LPWSTR lpwstrName;
    UINT ui;
    UINT uButton;

    switch (message) {
    case WM_INITDIALOG:

        //
        // default is local
        //

        CheckRadioButton(hDlg,IDC_LOCAL,IDC_REMOTE,IDC_REMOTE);

        break;

        case WM_COMMAND:
            switch(wParam) {


                //
                // end function
                //

                case IDOK:

                    lpwstrName = &gpAddDev->wszServerName[0];

                    ui = GetDlgItemTextW(hDlg,IDC_DRIVER_NAME,lpwstrName,MAX_PATH);

                    uButton = (UINT)SendDlgItemMessage(hDlg,IDC_LOCAL,BM_GETCHECK,0,0);

                    if (uButton == 1) {
                        gpAddDev->bLocal = TRUE;
                    } else {
                        gpAddDev->bLocal = FALSE;
                    }

                    EndDialog(hDlg, FALSE);
                    return (TRUE);

               case IDCANCEL:
                    EndDialog(hDlg, FALSE);
                    return (TRUE);
            }
            break;
    }
    return (FALSE);
}

/**************************************************************************\
* DevListDlgProc
*
*   Dialog proc for device list dialog.
*
* Arguments:
*
*   hDlg    - window handle of the dialog box
*   message - type of message
*   wParam  - message-specific information
*   lParam  - message-specific information
*
* Return Value:
*
*    Status
*
* History:
*
*    1/11/1999 Original Version
*
\**************************************************************************/

INT_PTR
APIENTRY DevListDlgProc(
   HWND hDlg,
   UINT message,
   WPARAM wParam,
   LPARAM lParam
   )
{
    static LONG cDevice = 0;
    static BSTR bstrDevice[16];

    switch (message) {
    case WM_INITDIALOG:
        if (gpIWiaDevMgr != NULL) {

            IEnumWIA_DEV_INFO   *pWiaEnumDevInfo;
            HRESULT              hr;
            LONG                 cDevice = 0;

            //
            // get device list, only want to see local devices
            //

            hr = gpIWiaDevMgr->EnumDeviceInfo(WIA_DEVINFO_ENUM_LOCAL,&pWiaEnumDevInfo);

            if (hr == S_OK) {

                do
                {
                    IWiaPropertyStorage  *pIWiaPropStg;
                    ULONG cEnum;

                    //
                    // get next device
                    //

                    hr = pWiaEnumDevInfo->Next(1,&pIWiaPropStg,&cEnum);

                    if (hr == S_OK)
                    {
                        //
                        // read device name
                        //

                        PROPSPEC        PropSpec[2];
                        PROPVARIANT     PropVar[2];

                        memset(PropVar,0,sizeof(PropVar));

                        PropSpec[0].ulKind = PRSPEC_PROPID;
                        PropSpec[0].propid = WIA_DIP_DEV_ID;

                        PropSpec[1].ulKind = PRSPEC_PROPID;
                        PropSpec[1].propid = WIA_DIP_DEV_DESC;

                        hr = pIWiaPropStg->ReadMultiple(sizeof(PropSpec)/sizeof(PROPSPEC),
                                            PropSpec,
                                            PropVar);

                        if (hr == S_OK)
                        {
                            CHAR szTemp[ MAX_PATH ];

                            //
                            // make sure property is string based
                            //

                            if (PropVar[0].vt == VT_BSTR)
                            {

                                //WideCharToMultiByte(CP_ACP,
                                //          0,
                                //          PropVar[1].bstrVal,
                                //          -1,
                                //          szTemp,
                                //          MAX_PATH,
                                //          NULL,
                                //          NULL);
                                //
                                //SendDlgItemMessage(hDlg,IDC_COMBO1,CB_INSERTSTRING,cDevice,(long)szTemp);
                                //

                                SendDlgItemMessageW(hDlg,IDC_COMBO1,CB_INSERTSTRING,cDevice,(LONG_PTR)PropVar[1].bstrVal);

                                bstrDevice[cDevice] = ::SysAllocString(PropVar[0].bstrVal);
                                cDevice++;

                            }

                            FreePropVariantArray(sizeof(PropSpec)/sizeof(PROPSPEC),PropVar);
                        }
                        else {
                            ReportReadWriteMultipleError(hr, "DevListDlgProc", NULL, TRUE, sizeof(PropSpec)/sizeof(PROPSPEC), PropSpec);
                        }
                        pIWiaPropStg->Release();
                    }

                } while (hr == S_OK);

                SendDlgItemMessage(hDlg,IDC_COMBO1,CB_SETCURSEL,0,0);

                pWiaEnumDevInfo->Release();
            } else {
                TCHAR msg[MAX_PATH];

                wsprintf(msg,TEXT("Error code = 0x%lx"),hr);
                MessageBox(NULL,msg,TEXT("Error in EnumDeviceInfo"),MB_OK);
                EndDialog(hDlg, FALSE);
            }
        }

        break;

        case WM_COMMAND:
            switch(wParam) {


                //
                // end function
                //

                case IDOK:
                {

                    LRESULT lRet = SendDlgItemMessage(hDlg,IDC_COMBO1,CB_GETCURSEL,0,0);

                    if (lRet != CB_ERR) {

                        gpAddDev->bstrDeviceID = bstrDevice[lRet];

                        bstrDevice[lRet] = NULL;

                        for (int index=0;index<cDevice;index++) {
                            if (bstrDevice[index] != NULL) {
                                    SysFreeString(bstrDevice[index] );
                            }
                        }

                    }


                    EndDialog(hDlg, (lRet != CB_ERR));

                    return (TRUE);
                }

               case IDCANCEL:

                   for (int index=0;index<cDevice;index++) {
                        if (bstrDevice[index] != NULL) {
                                SysFreeString(bstrDevice[index] );
                        }
                    }

                    EndDialog(hDlg, FALSE);
                    return (TRUE);
            }
            break;
    }
    return (FALSE);
}


PROPID propidDev[WIA_NUM_DIP] =
{
    WIA_DIP_DEV_ID       ,
    WIA_DIP_VEND_DESC    ,
    WIA_DIP_DEV_DESC     ,
    WIA_DIP_DEV_TYPE     ,
    WIA_DIP_PORT_NAME    ,
    WIA_DIP_DEV_NAME     ,
    WIA_DIP_SERVER_NAME  ,
    WIA_DIP_REMOTE_DEV_ID,
    WIA_DIP_UI_CLSID
};

LPOLESTR pszPropName[WIA_NUM_DIP] =
{
    WIA_DIP_DEV_ID_STR,
    WIA_DIP_VEND_DESC_STR,
    WIA_DIP_DEV_DESC_STR,
    WIA_DIP_DEV_TYPE_STR,
    WIA_DIP_PORT_NAME_STR,
    WIA_DIP_DEV_NAME_STR,
    WIA_DIP_SERVER_NAME_STR,
    WIA_DIP_REMOTE_DEV_ID_STR,
    WIA_DIP_UI_CLSID_STR
};

DWORD pszPropType[WIA_NUM_DIP] =
{
    REG_SZ,
    REG_SZ,
    REG_SZ,
    REG_DWORD,
    REG_SZ,
    REG_SZ,
    REG_SZ,
    REG_SZ,
    REG_SZ
};

/**************************************************************************\
*  WriteDeviceProperties
*
*   Write all device information properties to registry.
*
* Arguments:
*
*   hKeySetup - Open registry key.
*   pAddDev   - Add device information data.
*
* Return Value:
*
*   status
*
* History:
*
*    9/2/1998 Original Version
*
\**************************************************************************/

HRESULT
WriteDeviceProperties(
    HKEY hKeySetup,
    WIA_ADD_DEVICE *pAddDev
    )
{
    DBG_FN(::WriteDeviceProperties);
    HRESULT hr = S_OK;
    HKEY    hKeyDevice;
    LONG    lResult;

    //
    // build device connection name as SERVER-INDEX
    //

    WCHAR wszTemp[MAX_PATH];
    WCHAR *wszServer = pAddDev->wszServerName;
    WCHAR *wszIndex  = pAddDev->bstrDeviceID;

    //
    // skip leading \\ if it is there
    //

    if (wszServer[0] == L'\\') {
        wszServer = &wszServer[2];
    }

    //
    // skip STI CLASS
    //

    wszIndex = &wszIndex[39];

    lstrcpyW(wszTemp,wszServer);
    lstrcatW(wszTemp,L"-");
    lstrcatW(wszTemp,wszIndex);

    //
    // try to create remote device
    //

    IWiaItem *pWiaItemRoot = NULL;

    hr = gpIWiaDevMgr->CreateDevice(pAddDev->bstrDeviceID, &pWiaItemRoot);

    if (hr == S_OK) {


        //
        // read device properties
        //

        IWiaPropertyStorage *piprop;

        hr = pWiaItemRoot->QueryInterface(IID_IWiaPropertyStorage,(void **)&piprop);

        if (hr == S_OK) {

            //
            // read dev info prop
            //

            PROPSPEC        PropSpec[WIA_NUM_DIP];
            PROPVARIANT     PropVar[WIA_NUM_DIP];

            memset(PropVar,0,sizeof(PropVar));

            for (int Index = 0;Index<WIA_NUM_DIP;Index++)
            {
                PropSpec[Index].ulKind = PRSPEC_PROPID;
                PropSpec[Index].propid = propidDev[Index];
            }

            hr = piprop->ReadMultiple(sizeof(PropSpec)/sizeof(PROPSPEC),
                                      PropSpec,
                                      PropVar);

            if (hr == S_OK) {

                //
                // create device registry entry
                //

                lResult = RegCreateKeyExW(
                                    hKeySetup,
                                    wszTemp,
                                    0,
                                    NULL,
                                    REG_OPTION_NON_VOLATILE,
                                    KEY_ALL_ACCESS,
                                    NULL,
                                    &hKeyDevice,
                                    NULL) ;

                if (lResult != ERROR_SUCCESS) {
                    FreePropVariantArray(sizeof(PropSpec)/sizeof(PROPSPEC),PropVar);
                    piprop->Release();
                    pWiaItemRoot->Release();
                    return E_FAIL;
                }


                for (Index = 0;Index<WIA_NUM_DIP;Index++)
                {
                    //
                    // write dev info values to registry
                    //

                    if (pszPropType[Index] == REG_SZ) {

                        //
                        // write string prop
                        //

                        if (PropVar[Index].vt == VT_BSTR) {

                            RegSetValueExW(hKeyDevice,
                                  (LPCWSTR)pszPropName[Index],
                                  0,
                                  pszPropType[Index],
                                  (const UCHAR *)PropVar[Index].bstrVal,
                                  (lstrlenW(PropVar[Index].bstrVal)+1) * sizeof(WCHAR)) ;
                        }

                    } else {

                        //
                        // write int prop
                        //

                        RegSetValueExW(hKeyDevice,
                                  (LPCWSTR)pszPropName[Index],
                                  0,
                                  pszPropType[Index],
                                  (const UCHAR *)&PropVar[Index].lVal,
                                  sizeof(DWORD)) ;

                    }

                }

                //
                // server name must be remote server
                //

                RegSetValueExW(hKeyDevice,
                                  (LPCWSTR)WIA_DIP_SERVER_NAME_STR,
                                  0,
                                  REG_SZ,
                                  (LPBYTE)pAddDev->wszServerName,
                                  (lstrlenW(pAddDev->wszServerName)+1) * sizeof(WCHAR)) ;

                //
                // need a local device ID
                //

                {
                    WCHAR wszLocalID[MAX_PATH];


                    DWORD dwType = REG_SZ;
                    DWORD dwSize = MAX_PATH;

                    RegQueryValueExW(hKeyDevice,
                                               (LPCWSTR)WIA_DIP_DEV_ID_STR,
                                               0,
                                               &dwType,
                                               (LPBYTE)wszLocalID,
                                               &dwSize);
                    //
                    // copy dev id to remote dev id. This is used in calls to
                    // remote dev manager to create the device
                    //

                    RegSetValueExW(hKeyDevice,
                                  (LPCWSTR)WIA_DIP_REMOTE_DEV_ID_STR,
                                  0,
                                  REG_SZ,
                                  (LPBYTE)wszLocalID,
                                  (lstrlenW(wszLocalID)+1) * sizeof(WCHAR)) ;

                    //
                    // make local dev id unique
                    //

                    lstrcatW(wszLocalID,pAddDev->wszServerName);

                    RegSetValueExW(hKeyDevice,
                                  (LPCWSTR)WIA_DIP_DEV_ID_STR,
                                  0,
                                  REG_SZ,
                                  (LPBYTE)wszLocalID,
                                  (lstrlenW(wszLocalID)+1) * sizeof(WCHAR)) ;
                }

                RegCloseKey(hKeyDevice);

            }
            else {
                ReportReadWriteMultipleError(hr, "WriteDeviceProperties", NULL, TRUE, sizeof(PropSpec)/sizeof(PROPSPEC), PropSpec);
            }
            FreePropVariantArray(sizeof(PropSpec)/sizeof(PROPSPEC),PropVar);

            piprop->Release();
        }
        DBG_ERR(("WriteDeviceProperties, QI for IID_IWiaPropertyStorage failed"));
        pWiaItemRoot->Release();
    }
    else {
    }
    return hr;
}

/**************************************************************************\
* VerifyRemoteDeviceList
*
*   Open a registry key to the STI device list.
*
* Arguments:
*
*   phKey - Pointer to returned registry key.
*
* Return Value:
*
*    Status
*
* History:
*
*    3/2/1999 Original Version
*
\**************************************************************************/

HRESULT
VerifyRemoteDeviceList(HKEY *phKey)
{
    DBG_FN(::VerifyRemoteDeviceList);
    HRESULT hr;
    LONG    lResult;

    LPWSTR szKeyNameSTI = REGSTR_PATH_STICONTROL_W;
    LPWSTR szKeyNameDev = REGSTR_PATH_STICONTROL_DEVLIST_W;

    HKEY hKeySTI;
    HKEY hKeyDev;

    *phKey = NULL;


    //
    // try to open dev list
    //

    if (RegOpenKeyExW (HKEY_LOCAL_MACHINE,
                      szKeyNameDev,
                      0,
                      KEY_READ | KEY_WRITE,
                      &hKeyDev) == ERROR_SUCCESS) {

        *phKey = hKeyDev;
        return S_OK;
    }

    //
    // open sti device control and create DevList Key
    //

    if (RegOpenKeyExW (HKEY_LOCAL_MACHINE,
                      szKeyNameSTI,
                      0,
                      KEY_READ | KEY_WRITE,
                      &hKeySTI) == ERROR_SUCCESS) {

        //
        // try to create key
        //

        lResult = RegCreateKeyExW(
                            hKeySTI,
                            L"DevList",
                            0,
                            NULL,
                            REG_OPTION_NON_VOLATILE,
                            KEY_ALL_ACCESS,
                            NULL,
                            &hKeyDev,
                            NULL) ;

        if (lResult == ERROR_SUCCESS) {
            *phKey = hKeyDev;
            hr = S_OK;
        } else {
            DBG_ERR(("VerifyRemoteDeviceList: Couldn't create DevList Key"));
            hr = E_FAIL;
        }

        RegCloseKey(hKeySTI);

    } else {

        DBG_ERR(("VerifyRemoteDeviceList: Couldn't open STI DeviceControl Key"));
        hr = E_FAIL;
    }
    return(hr);
}




/**************************************************************************\
*  DisplayAddDlg
*
*   Put up the add device dialog.
*
* Arguments:
*
*   pAddDev   - Add device information data.
*
* Return Value:
*
*   status
*
* History:
*
*    9/2/1998 Original Version
*
\**************************************************************************/

HRESULT
DisplayAddDlg(WIA_ADD_DEVICE *pAddDev)
{
    DBG_FN(::DisplayAddDlg);
    if (pAddDev == NULL) {
        return E_INVALIDARG;
    }

    HRESULT         hr = S_OK;

    //
    // if reentrant then need semaphore
    //

    gpAddDev = pAddDev;

    INT_PTR iret = DialogBox(g_hInst,MAKEINTRESOURCE(IDD_ADD_DLG),pAddDev->hWndParent,AddDeviceDlgProc);

    if (iret == -1) {
        int err = GetLastError();
        return HRESULT_FROM_WIN32(err);
    }

    //
    // Remote or local
    //

    if (pAddDev->bLocal == FALSE) {

        //
        // try to connect to remote dev manager
        //

        COSERVERINFO    coServInfo;
        MULTI_QI        multiQI[1];

        multiQI[0].pIID = &IID_IWiaDevMgr;
        multiQI[0].pItf = NULL;

        coServInfo.pwszName    = gpAddDev->wszServerName;
        coServInfo.pAuthInfo   = NULL;
        coServInfo.dwReserved1 = 0;
        coServInfo.dwReserved2 = 0;

        //
        // create connection to dev mgr
        //

        hr = CoCreateInstanceEx(
                CLSID_WiaDevMgr,
                NULL,
                CLSCTX_REMOTE_SERVER,
                &coServInfo,
                1,
                &multiQI[0]
                );

        if (hr == S_OK) {

            gpIWiaDevMgr = (IWiaDevMgr*)multiQI[0].pItf;

            //
            // display list of devices on this server
            //

            INT_PTR iret = DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_DEVLIST),pAddDev->hWndParent,DevListDlgProc);

            if (iret != 0) {

                //
                // add device to auxillary list
                //

                HKEY hKeySetup;

                hr = VerifyRemoteDeviceList(&hKeySetup);

                if (hr == S_OK) {

                    //
                    // look for machine name
                    //

                    hr = WriteDeviceProperties(hKeySetup,pAddDev);

                    RegCloseKey(hKeySetup);
                }

            } else {
                hr = E_FAIL;
            }

            gpIWiaDevMgr->Release();

            gpIWiaDevMgr = NULL;
        }

    } else {

        //
        // local named driver
        //

        return E_NOTIMPL;
    }
    return hr;
}
#endif