//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1998 - 1999
//
//  File:       irprops.cpp
//
//--------------------------------------------------------------------------

// irprops.cpp : Defines the initialization routines for the DLL.
//

#include "precomp.hxx"
#include "irprops.h"
#include "irpropsheet.h"
#include "debug.h"


BOOL InitInstance();
INT ExitInstance();
BOOL IsFirstInstance();
INT_PTR WINAPI DoPropertiesA(HWND hwnd, LPCSTR CmdLine);
INT_PTR WINAPI DoPropertiesW(HWND hwnd, LPCWSTR CmdLine);


HINSTANCE gHInst;

//
// This records the current active property sheet window handle created
// by this instance. It is set/reset by CIrPropSheet object.
//
HWND        g_hwndPropSheet = NULL;
HANDLE      g_hMutex = NULL;
BOOL        g_bFirstInstance = TRUE;

//
// This records our registered message for inter-instances communications
// The message is registered in CIrpropsApp::InitInstance.
//
UINT        g_uIPMsg;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


extern "C" {

BOOL APIENTRY
DllMain(HANDLE hDll,
        DWORD dwReason,
        LPVOID lpReserved)
{
    IRINFO((_T("DllMain reason %x"), dwReason));
    switch (dwReason) {
    case DLL_PROCESS_ATTACH:
        gHInst = (HINSTANCE) hDll;
        return InitInstance(); 
        break;

    case DLL_PROCESS_DETACH:
        return ExitInstance();
        break;

    case DLL_THREAD_DETACH:
        break;

    case DLL_THREAD_ATTACH:
        break;

    default:
        break;
    }

    return TRUE;
}

}

////////////////////////////////////////////////////////////////////////
//some globals

APPLETS IRApplet[NUM_APPLETS] = {
    {IDI_IRPROPS, IDS_APPLETNAME, IDS_APPLETDESC}
};


/////////////////////////////////////////////////////////////////////////
//  CPlApplet function for the control panel
//
LONG CALLBACK CPlApplet(
                        HWND hwndCPL,
                        UINT uMsg,
                        LPARAM lParam1,
                        LPARAM lParam2)
{
    int i;
    LPCPLINFO lpCPlInfo;

    i = (int) lParam1;

    IRINFO((_T("CplApplet message %x"), uMsg));
    switch (uMsg)
    {
    case CPL_INIT:      // first message, sent once
        if (!IrPropSheet::IsIrDASupported()) {
            HPSXA hpsxa;
            //
            //  Check for any installed extensions.
            //
            hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, sc_szRegWireless, 8);
            if (hpsxa) {
                //
                // We have extensions installed so we have to show the CPL, 
                // whether IRDA exists or not.
                //
                SHDestroyPropSheetExtArray(hpsxa);
                return TRUE;
            }
            return FALSE;
        }
        return TRUE;
    case CPL_GETCOUNT:  // second message, sent once
        return NUM_APPLETS;
        break;
    case CPL_INQUIRE: // third message, sent once per application
        lpCPlInfo = (LPCPLINFO) lParam2;
        lpCPlInfo->lData = 0;
        lpCPlInfo->idIcon = IRApplet[i].icon;
        lpCPlInfo->idName = IRApplet[i].namestring;
        lpCPlInfo->idInfo = IRApplet[i].descstring;
        break;

    case CPL_STARTWPARMSA:
        if (-1 == DoPropertiesA(hwndCPL, (LPCSTR)lParam2))
            MsgBoxWinError(hwndCPL);
        // return true so that we won't get CPL_DBLCLK.
        return 1;
        break;
    case CPL_STARTWPARMSW:
        if (-1 == DoPropertiesW(hwndCPL, (LPCWSTR)lParam2))
            MsgBoxWinError(hwndCPL);
        // return true so that we won't get CPL_DBLCLK.
        return 1;
        break;
    case CPL_DBLCLK:    // application icon double-clicked
        if (-1 == DoPropertiesA(hwndCPL, (LPCSTR)lParam2))
            MsgBoxWinError(hwndCPL);
    return 1;
        break;
    case CPL_STOP:      // sent once per application before CPL_EXIT
        break;
    case CPL_EXIT:    // sent once before FreeLibrary is called
        break;
    default:
        break;
    }

    return 0;
}

//
// This function presents the Wireless link property sheet.
// INPUT:
//  hwndParent  -- window handle to be used as parent window of
//          the property sheet
//  lpCmdLine -- optional command line
//           'n" (n in decimal) is start page number(zero-based).
// OUTPUT:
//  Return value of PropertySheet API
INT_PTR
DoPropertiesW(
    HWND    hwndParent,
    LPCWSTR lpCmdLine
    )
{
    INT_PTR Result;
    INT   StartPage;
    
    IRINFO((_T("DoPropertiesW")));
    //
    // Assuming no start page was specified.
    //
    StartPage = -1;
    //
    // Command line specifies start page number
    //
    if (lpCmdLine)
    {
        // skip white chars
        while (_T('\0') != *lpCmdLine &&
               (_T(' ') == *lpCmdLine || _T('\t') == *lpCmdLine))
        {
            lpCmdLine++;
        }
        if (_T('0') <= *lpCmdLine && _T('9') >= *lpCmdLine)
        {
            StartPage = 0;
            do
            {
                StartPage = StartPage * 10 + *lpCmdLine - _T('0');
                lpCmdLine++;
            } while (_T('0') <= *lpCmdLine && _T('9') >= *lpCmdLine);
        }
    }
    if (!IsFirstInstance() || NULL != g_hwndPropSheet)
    {
        IRINFO((_T("Not the first instance")));
        HWND hwndPropSheet = HWND_DESKTOP;
        if (NULL == g_hwndPropSheet)
        {
            IRINFO((_T("No window created")));
            //
            // We are not the first instance. Look for the property sheet
            // window created by the first instance.
            //
            EnumWindows(EnumWinProc, (LPARAM)&hwndPropSheet);
        }
        else
        {
            IRINFO((_T("Window active")));
            //
            // This is not the first call and we have a
            // property sheet active(same process, multiple calls)
            //
            hwndPropSheet = g_hwndPropSheet;
        }
        if (HWND_DESKTOP != hwndPropSheet)
        {
            IRINFO((_T("Found the active property sheet.")));
            //
            // We found the active property sheet
            //
            // Select the new active page if necessary
            //
            if (-1 != StartPage)
            PropSheet_SetCurSel(hwndPropSheet, NULL, StartPage);
    
            //
            // bring the property sheet to the foreground.
            //
            ::SetForegroundWindow(hwndPropSheet);
        }
        Result = IDCANCEL;
    }
    else
    {
        IRINFO((_T("First instance, creating propertysheet")));
        IrPropSheet PropSheet(gHInst, IDS_APPLETNAME, hwndParent, StartPage);
    }
    return Result;
}

//
// This is our callback function for EnumWindows API.
// It probes for each window handle to see if it is the property sheet
// window created by the previous instance. If it is, it returns
// the window handle in the provided buffer, lParam)
// Input:
//  hWnd -- the window handle
//  lParam -- (HWND *)
// Output:
//  TRUE -- Let Windows continue to call us
//  FALSE -- Stop Windows from calling us again
//
BOOL
CALLBACK
EnumWinProc(
    HWND hWnd,
    LPARAM lParam
    )
{
    //
    // Verify with this window to see if it is the one we are looking for.
    //
    LRESULT lr;
    lr = ::SendMessage(hWnd, g_uIPMsg, (WPARAM)IPMSG_SIGNATURECHECK,
               (LPARAM)IPMSG_REQUESTSIGNATURE);
    if (IPMSG_REPLYSIGNATURE == lr)
    {
    if (lParam)
    {
        // this is the one
        *((HWND *)(lParam)) = hWnd;
    }
    //
    // We are done with enumeration.
    //
    return FALSE;
    }
    return TRUE;
}

INT_PTR
DoPropertiesA(
    HWND hwndParent,
    LPCSTR lpCmdLine
    )
{
    WCHAR CmdLineW[MAX_PATH];
    UINT Size;
    if (!lpCmdLine)
        return DoPropertiesW(hwndParent, NULL);
    MultiByteToWideChar(CP_ACP, 0, lpCmdLine, -1, CmdLineW, sizeof(CmdLineW) / sizeof(WCHAR));
    return DoPropertiesW(hwndParent, CmdLineW);
}


// This function creates and displays a message box for the given
// win32 error(or last error)
// INPUT:
//  hwndParent -- the parent window for the will-be-created message box
//  Type       -- message styles(MB_xxxx)
//  Error      -- Error code. If the value is 0
//            GetLastError() will be called to retreive the
//            real error code.
//  CaptionId  -- optional string id for caption
// OUTPUT:
//  the value return from MessageBox
//
int
MsgBoxWinError(
    HWND hwndParent,
    DWORD Options,
    DWORD Error,
    int  CaptionId
    )
{
    if (ERROR_SUCCESS == Error)
    Error = GetLastError();

    // nonsense to report success!
    if (ERROR_SUCCESS == Error)
    return IDOK;

    TCHAR szMsg[MAX_PATH];
    TCHAR szCaption[MAX_PATH];

    if (!CaptionId)
    CaptionId = IDS_APPLETNAME;
    ::LoadString(gHInst, CaptionId, szCaption, sizeof(szCaption) / sizeof(TCHAR));
    FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
          NULL, Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
          szMsg, sizeof(szMsg) / sizeof(TCHAR), NULL);
    return MessageBox(hwndParent, szMsg, szCaption, Options);
}

BOOL InitInstance()
{
    //
    // Try to create a named mutex. This give us a clue
    // if we are the first instance. We will not close
    // the mutex until exit.
    //
    g_hMutex = CreateMutex(NULL, TRUE, SINGLE_INST_MUTEX);
    if (g_hMutex)
    {
        g_bFirstInstance = ERROR_ALREADY_EXISTS != GetLastError();
        //
        // register a message for inter-instances communication
        //
        g_uIPMsg = RegisterWindowMessage(WIRELESSLINK_INTERPROCESSMSG);
        SHFusionInitializeFromModuleID(gHInst, 124);
        return TRUE;
    }
    return FALSE;
}

BOOL ExitInstance()
{
    if (g_hMutex)
    {
        CloseHandle(g_hMutex);
        g_hMutex = NULL;
    }
    SHFusionUninitialize();
    return TRUE;
}

BOOL IsFirstInstance()
{
    return g_bFirstInstance;
}