/******************************************************************
   PrintSys.CPP -- WMI provider class implementation

   Generated by Microsoft WMI Code Generation Engine
  
   TO DO: - See individual function headers
          - When linking, make sure you link to framedyd.lib & 
            msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail).

   Description: 
   
  
  
******************************************************************/

#include "pchealth.h"
#include "PrintSys.h"


/////////////////////////////////////////////////////////////////////////////
//  tracing stuff

#ifdef THIS_FILE
#undef THIS_FILE
#endif
static char __szTraceSourceFile[] = __FILE__;
#define THIS_FILE __szTraceSourceFile
#define TRACE_ID    DCID_PRINTERDRIVER


/////////////////////////////////////////////////////////////////////////////
//  initialization

CPrintSys MyPrintSysSet (PROVIDER_NAME_PRINTSYS, PCH_NAMESPACE) ;


/////////////////////////////////////////////////////////////////////////////
//  Property names

const static WCHAR *c_wszGenDrv              = L"GenDrv";
const static WCHAR *c_wszName                = L"Name";
const static WCHAR *c_wszPath                = L"Path";
const static WCHAR *c_wszUniDrv              = L"UniDrv";
const static WCHAR *c_wszUsePrintMgrSpooling = L"UsePrintMgrSpooling";


//////////////////////////////////////////////////////////////////////////////
// construction / destruction

// ***************************************************************************
CPrintSys::CPrintSys (LPCWSTR lpwszName, LPCWSTR lpwszNameSpace ) :
    Provider(lpwszName, lpwszNameSpace)
{
    m_pParamOut = NULL;
    m_pCurrent  = NULL;
    m_pParamIn  = NULL;
    m_lFlags    = 0;
}

// ***************************************************************************
CPrintSys::~CPrintSys()
{
}


//////////////////////////////////////////////////////////////////////////////
// exposed methods

// *****************************************************************************
HRESULT CPrintSys::EnumerateInstances(MethodContext *pMethodContext, long lFlags)
{
    TraceFunctEnter("CPrintSys::EnumerateInstances");

    HRESULT hr = WBEM_S_NO_ERROR;

    //  Create a new instance of PCH_Printer Class based on the passed-in MethodContext
    CInstancePtr pPrintSysInst(CreateNewInstance(pMethodContext), false);

    hr = this->GetObject(pPrintSysInst, 0);
    
    TraceFunctLeave();
    return hr;
}

// *****************************************************************************
HRESULT CPrintSys::ExecMethod (const CInstance& Instance,
                              const BSTR bstrMethodName,
                              CInstance *pInParams, CInstance *pOutParams,
                              long lFlags)
{
    return WBEM_E_PROVIDER_NOT_CAPABLE; 
}

// *****************************************************************************
HRESULT CPrintSys::GetObject(CInstance* pInstance, long lFlags) 
{ 
    TraceFunctEnter("CPrintSys::GetObject");

    HRESULT hr = WBEM_S_NO_ERROR;

    //  Objects
    IWbemClassObjectPtr pFileObj = NULL;
    
    //  Variants
    CComVariant         varValue;
    CComVariant         varNotAvail             = L"Not Available";

    //   Strings
    CComBSTR            bstrDriverWithPath; 
    CComBSTR            bstrDetails;
    CComBSTR            bstrVersion             = L"Version";
    CComBSTR            bstrFileSize            = L"FileSize";
    CComBSTR            bstrModifiedDate        = L"LastModified";

    LPCTSTR             lpctstrUniDriver        = _T("unidrv.dll");
    LPCTSTR             lpctstrGenDriver        = _T("gendrv.dll");
    LPCTSTR             lpctstrWindows          = _T("Windows");   
    LPCTSTR             lpctstrDevice           = _T("Device");  
    LPCTSTR             lpctstrNoUniDrv         = _T("(unidrv.dll) = NotInstalled");
    LPCTSTR             lpctstrNoGenDrv         = _T("(gendrv.dll) = NotInstalled");
    LPCTSTR             lpctstrPrintersHive     = _T("System\\CurrentControlSet\\Control\\Print\\Printers");
    LPCTSTR             lpctstrYes              = _T("yes");
    LPCTSTR             lpctstrAttributes       = _T("Attributes");
    LPCTSTR             lpctstrSpooler          = _T("Spooler");

    TCHAR               tchBuffer[MAX_PATH + 1];
    TCHAR               tchPrinterKeyName[MAX_PATH + 1];
    TCHAR               *ptchToken;

    //  Booleans
    BOOL                fDriverFound = FALSE;
    BOOL                fAttribFound = FALSE;

    //  DWORDs
    DWORD               dwSize;
    DWORD               dwIndex;
    DWORD               dwType;

    //  Return Values;
    ULONG               ulPrinterAttribs;

    LONG                lRegRetVal;

    struct tm           tm;

    WBEMTime            wbemtime;

    HKEY                hkeyPrinter = NULL;
    HKEY                hkeyPrinters = NULL;

    FILETIME            ft;

    // *** Set the properties associated with the default printer

    
    //  In "win.ini" file under "Windows" section "Device" represents the default printer
    if(GetProfileString(lpctstrWindows, lpctstrDevice, "\0", tchBuffer, MAX_PATH) > 1)
    {
        //  The Above GetProfileString returns "printerName", "PrinterDriver" 
        //   and "PrinterPath" seperated by commas. Ignore "PrinterDriver" 
        //   and use the other two to set the properties.
        ptchToken = _tcstok(tchBuffer, _T(","));
        if(ptchToken != NULL)
        {
            // ** name (token 1)
            varValue = ptchToken;
            if (pInstance->SetVariant(c_wszName, varValue) == FALSE)
                ErrorTrace(TRACE_ID, "SetVariant on Name failed.");
                        
            // ** path (token 3)          
            ptchToken = _tcstok(NULL, _T(","));
            if(ptchToken != NULL)
            {
                // gotta skip the 2nd token cuz it's the printer dirver & we 
                //  don't give a rat's patoshki about it at this moment...
                
                ptchToken = _tcstok(NULL, _T(","));
                if(ptchToken != NULL)
                {
                    varValue = ptchToken;
                    if (pInstance->SetVariant(c_wszPath, varValue) == FALSE)
                        ErrorTrace(TRACE_ID, "Set Variant on Path failed.");
                }
            }
        }
    }

    // couldn't fetch the properties of the default printer, so shove in some
    //  default values...
    else
    {
        //  set Name to "Not Available"
        if (pInstance->SetVariant(c_wszName, varNotAvail) == FALSE)
            ErrorTrace(TRACE_ID, "Se Variant on Name failed.");

        // set Path to "Not Available"
        if (pInstance->SetVariant(c_wszPath, varValue) == FALSE)
            ErrorTrace(TRACE_ID, "Set Variant on Path failed.");
    }


    // *** Set the properties associated with using print manager spooling


    //  First try to get the Spooling  information from the registry which is 
    //   available if there are any installed printers 
    //   HKLM\system\CCS\Control\Print\Printers

    lRegRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpctstrPrintersHive, 0, KEY_READ, &hkeyPrinters);
    if(lRegRetVal == ERROR_SUCCESS)
	{
        // Enumerate the keys under this hive.
        ZeroMemory(&ft, sizeof(ft));
        dwIndex = 0;
        dwSize = MAX_PATH;
        lRegRetVal = RegEnumKeyEx(hkeyPrinters, dwIndex,  tchPrinterKeyName, &dwSize, NULL, NULL, NULL, &ft);
        if(lRegRetVal == ERROR_SUCCESS)
        {
            //  There is atleast one printer installed.
            lRegRetVal = RegOpenKeyEx(hkeyPrinters,  tchPrinterKeyName, 0, KEY_READ, &hkeyPrinter);
            if(lRegRetVal == ERROR_SUCCESS)
            {
                //  Opened the first printer key
                //  Query for , regname "Attributes"
                dwSize = sizeof(DWORD);
                lRegRetVal = RegQueryValueEx(hkeyPrinter, lpctstrAttributes, NULL, &dwType, (LPBYTE)&ulPrinterAttribs, &dwSize);
                if(lRegRetVal == ERROR_SUCCESS)
                {
                    // if the PRINTER_ATTRIBUTE_DIRECT bit in ulPrinterAttribs
                    //  is set, then we have spooling...
                    if((ulPrinterAttribs & PRINTER_ATTRIBUTE_DIRECT) != 0)
                        varValue = VARIANT_FALSE;
                    else
                        varValue = VARIANT_TRUE;

                    if (ulPrinterAttribs > 0)
                        fAttribFound = TRUE;
                }
            }
        }
    }   
    
    if (hkeyPrinter != NULL)
    {
        RegCloseKey(hkeyPrinter);
        hkeyPrinter = NULL;
    }
    if (hkeyPrinters != NULL)
    {
        RegCloseKey(hkeyPrinters);
        hkeyPrinters = NULL;
    }

    if(fAttribFound == FALSE)
    {
        //  If not get the "spooler" key value from the win.ini file.  If the entry is not present default to "yes".
        if(GetProfileString(lpctstrWindows, lpctstrSpooler, _T("yes"), tchBuffer, MAX_PATH) > 1)
        {
            // if it's yes, then we have spooling...
            if(_tcsicmp(tchBuffer, lpctstrYes) == 0)
                varValue = VARIANT_TRUE;
            else
                varValue = VARIANT_FALSE;
        }
    }

    //  Set the Spooling Property.
    if (pInstance->SetVariant(c_wszUsePrintMgrSpooling, varValue) == FALSE)
        ErrorTrace(TRACE_ID, "SetVariant on usePrintManagerSpooling failed.");
    

    // *** Set the properties associated with using print manager spooling


    //  Get the complete path for unidrv.dll
    fDriverFound = getCompletePath(lpctstrUniDriver, bstrDriverWithPath);
    if(fDriverFound)
    {
        // Need to use GetCIMDataFile to get the unidriver properties
        if (SUCCEEDED(GetCIMDataFile(bstrDriverWithPath, &pFileObj)))
        {
            bstrDetails.Empty();

            //  Get the Version & append it to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrVersion, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    bstrDetails.Append(varValue.bstrVal);
                    bstrDetails.Append(_T("  "));
                }
            }

            //  Get the FileSize & append it to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrFileSize, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    bstrDetails.Append(varValue.bstrVal);
                    bstrDetails.Append(_T("  "));
                }
            }

            //  Get the date & time & append them to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrModifiedDate, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    WCHAR *pwsz;

                    // there is a slight problem when WMI returns to us a 
                    //  time that has a '*' in it.  The WBEMTime class plain
                    //  refuses to deal with it.  So change '*'s to '0's...
                    for (pwsz = varValue.bstrVal; *pwsz != L'\0'; pwsz++)
                    {
                        if (*pwsz == L'*')
                            *pwsz = L'0';
                    }

                    wbemtime = varValue.bstrVal;
                    if(wbemtime.GetStructtm(&tm))
                    {
                        varValue = asctime(&tm);
                        bstrDetails.Append(varValue.bstrVal);
                    }
                }
                
            }

            // set the value
            varValue.vt = VT_BSTR;
            varValue.bstrVal = bstrDetails.Detach();
        }

        // Since I don't seem to have unindrv.dll installed, I can't verify 
        //  this, but going by the other WMI providers, GetObject doesn't seem
        //  to like it when u release objects fetched by it.  So, I am not 
        //  going to release it.
        if (pFileObj != NULL)
        {
            // pFileObj->Release();
            pFileObj = NULL;
        }
    }

    // the unidriver dll isn't present.  Use a default value
    else 
    {
        varValue.Clear();
        varValue = lpctstrNoUniDrv;
    }

    // set the property
    if (pInstance->SetVariant(c_wszUniDrv, varValue) == FALSE)
        ErrorTrace(TRACE_ID, "SetVariant on UniDriver failed.");


    // *** Set the properties associated with using print manager spooling

    
    //  Get the complete path for gendrv.dll
    bstrDriverWithPath.Empty();
    fDriverFound =  getCompletePath(lpctstrGenDriver, bstrDriverWithPath);
    if(fDriverFound)
    {
        bstrDetails.Empty();

        // Need to use GetCIMDataFile to get the gen driver properties
        if(SUCCEEDED(GetCIMDataFile(bstrDriverWithPath, &pFileObj)))
        {
            //  Get the Version & append it to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrVersion, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    bstrDetails.Append(varValue.bstrVal);
                    bstrDetails.Append(_T("  "));
                }
            }
            
            //  Get the FileSize & append it to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrFileSize, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    bstrDetails.Append(varValue.bstrVal);
                    bstrDetails.Append(_T("  "));
                }
            }

            //  Get the date & time & append them to the value string...
            varValue.Clear();
            hr = pFileObj->Get(bstrModifiedDate, 0, &varValue, NULL, NULL);
            if(SUCCEEDED(hr))
            {
                if(varValue.vt == VT_BSTR)
                {
                    WCHAR *pwsz;

                    // there is a slight problem when WMI returns to us a 
                    //  time that has a '*' in it.  The WBEMTime class plain
                    //  refuses to deal with it.  So change '*'s to '0's...
                    for (pwsz = varValue.bstrVal; *pwsz != L'\0'; pwsz++)
                    {
                        if (*pwsz == L'*')
                            *pwsz = L'0';
                    }

                    wbemtime = varValue.bstrVal;
                    if(wbemtime.GetStructtm(&tm))
                    {
                        varValue = asctime(&tm);
                        bstrDetails.Append(varValue.bstrVal);
                    }
                }
            }

            // set the value
            varValue.vt = VT_BSTR;
            varValue.bstrVal = bstrDetails.Detach();
        }

        // Since I don't seem to have gendrv.dll installed, I can't verify 
        //  this, but going by the other WMI providers, GetObject doesn't seem
        //  to like it when u release objects fetched by it.  So, I am not 
        //  going to release it.
        if (pFileObj != NULL)
        {
            // pFileObj->Release();
            pFileObj = NULL;
        }
    } 

    // the gen driver dll is not present...
    else 
    {
        varValue.Clear();
        varValue = lpctstrNoGenDrv;
    }

    if (pInstance->SetVariant(c_wszGenDrv, varValue) == FALSE)
        ErrorTrace(TRACE_ID, "SetVariant on GenDrv failed.");


    // WOOHOO!!  We can commit now
    hr = pInstance->Commit();
    if(FAILED(hr))
        ErrorTrace(TRACE_ID, "Error on commiting!");

    TraceFunctLeave();
    return hr;
}

// *****************************************************************************
HRESULT CPrintSys::ExecQuery(MethodContext *pMethodContext, 
                            CFrameworkQuery& Query, long lFlags) 
{ 
    return WBEM_E_PROVIDER_NOT_CAPABLE; 
}

// *****************************************************************************
HRESULT CPrintSys::PutInstance(const CInstance& Instance, long lFlags)
{ 
    return WBEM_E_PROVIDER_NOT_CAPABLE; 
}

// *****************************************************************************
HRESULT CPrintSys::DeleteInstance(const CInstance& Instance, long lFlags)
{ 
    return WBEM_E_PROVIDER_NOT_CAPABLE; 
}
