windows-nt/Source/XPSP1/NT/printscan/ui/photowiz/dll.cpp
2020-09-26 16:20:57 +08:00

626 lines
17 KiB
C++

/*****************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 2000
*
* TITLE: dll.cpp
*
* VERSION: 1.0, stolen from netplwiz
*
* AUTHOR: RickTu
*
* DATE: 10/12/00
*
* DESCRIPTION: DLL main & class factory code
*
*****************************************************************************/
#include "precomp.h"
#pragma hdrstop
// shell/lib files look for this instance variable
HINSTANCE g_hInst = 0;
LONG g_cLocks = 0;
ATOM g_cPreviewClassWnd = 0;
// guids for our stuff
// some guids are in shguidp.lib. We need to move them out of the shell depot into printscan at some point
const GUID IID_ISetWaitEventForTesting = {0xd61e2fe1, 0x4af8, 0x4dbd, {0xb8, 0xad, 0xe7, 0xe0, 0x7a, 0xdc, 0xf9, 0x0f}};
// DLL lifetime stuff
STDAPI_(BOOL) DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_hInst = hinstDLL;
SHFusionInitializeFromModuleID( hinstDLL, 123 );
WIA_DEBUG_CREATE(hinstDLL);
WIA_TRACE((TEXT("DLL_PROCESS_ATTACH called on photowiz.dll")));
CPreviewWindow::s_RegisterClass(hinstDLL);
break;
case DLL_PROCESS_DETACH:
WIA_TRACE((TEXT("DLL_PROCESS_DETACH called on photowiz.dll")));
if (g_cPreviewClassWnd)
{
UnregisterClass( (LPCTSTR)g_cPreviewClassWnd, hinstDLL );
}
SHFusionUninitialize();
WIA_REPORT_LEAKS();
WIA_DEBUG_DESTROY();
break;
case DLL_THREAD_ATTACH:
// WIA_TRACE((TEXT("DLL_THREAD_ATTACH called on photowiz.dll")));
break;
case DLL_THREAD_DETACH:
// WIA_TRACE((TEXT("DLL_THREAD_DETACH called on photowiz.dll")));
break;
}
return TRUE;
}
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
{
return S_OK;
}
STDAPI DllCanUnloadNow()
{
HRESULT hr = (g_cLocks == 0) ? S_OK:S_FALSE;
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllCanUnloadNowRef, ref count is %d, hr = 0x%x"),g_cLocks,hr));
WIA_RETURN_HR(hr);
}
STDAPI_(void) DllAddRef(void)
{
InterlockedIncrement(&g_cLocks);
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllAddRef, new ref count is %d"),g_cLocks));
}
STDAPI_(void) DllRelease(void)
{
InterlockedDecrement(&g_cLocks);
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllRelease, new ref count is %d"),g_cLocks));
}
/*****************************************************************************
_CallRegInstall
Helper function to allow us to invoke our .inf for installation...
*****************************************************************************/
HRESULT _CallRegInstall(LPCSTR szSection, BOOL bUninstall)
{
HRESULT hr = E_FAIL;
HINSTANCE hinstAdvPack = NULL;
//
// Get system32 directory..
//
TCHAR szAdvPackPath[ MAX_PATH ];
UINT uDirLen = lstrlen( TEXT("\\system32\\advpack.dll")+1 );
UINT uRes;
*szAdvPackPath = 0;
uRes = GetSystemWindowsDirectory( szAdvPackPath, MAX_PATH - uDirLen );
if (uRes && (uRes <= (MAX_PATH-uDirLen)))
{
lstrcat( szAdvPackPath, TEXT("\\system32\\advpack.dll") );
hinstAdvPack = LoadLibrary( szAdvPackPath );
}
if (hinstAdvPack)
{
REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
if (pfnri)
{
STRENTRY seReg[] = {
{ "25", "%SystemRoot%" },
{ "11", "%SystemRoot%\\system32" },
};
STRTABLE stReg = { ARRAYSIZE(seReg), seReg };
hr = pfnri(g_hInst, szSection, &stReg);
if (bUninstall)
{
// ADVPACK will return E_UNEXPECTED if you try to uninstall
// (which does a registry restore) on an INF section that was
// never installed. We uninstall sections that may never have
// been installed, so ignore this error
hr = ((E_UNEXPECTED == hr) ? S_OK : hr);
}
}
FreeLibrary(hinstAdvPack);
}
return hr;
}
STDAPI DllRegisterServer()
{
_CallRegInstall("UnregDll", TRUE);
return _CallRegInstall("RegDll", FALSE);
}
STDAPI DllUnregisterServer()
{
return _CallRegInstall("UnregDll", TRUE);
}
HMODULE GetThreadHMODULE( LPTHREAD_START_ROUTINE pfnThreadProc )
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(pfnThreadProc, &mbi, sizeof(mbi)))
{
TCHAR szModule[MAX_PATH];
if (GetModuleFileName((HMODULE)mbi.AllocationBase, szModule, ARRAYSIZE(szModule)))
{
return LoadLibrary(szModule);
}
}
return NULL;
}
STDAPI PPWCoInitialize(void)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr))
{
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
}
return hr;
}
/*****************************************************************************
ClassFactory code
<Notes>
*****************************************************************************/
//
// This array holds information needed for ClassFacory.
// OLEMISC_ flags are used by shembed and shocx.
//
// PERF: this table should be ordered in most-to-least used order
//
#define OIF_ALLOWAGGREGATION 0x0001
CF_TABLE_BEGIN(g_ObjectInfo)
CF_TABLE_ENTRY( &CLSID_PrintPhotosDropTarget, CPrintPhotosDropTarget_CreateInstance, COCREATEONLY),
CF_TABLE_ENTRY( &CLSID_PrintPhotosWizard, CPrintPhotosWizard_CreateInstance, COCREATEONLY),
CF_TABLE_END(g_ObjectInfo)
// constructor for CObjectInfo.
CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
DWORD dwClassFactFlagsIn)
{
pclsid = pclsidin;
pfnCreateInstance = pfnCreatein;
piid = piidIn;
piidEvents = piidEventsIn;
lVersion = lVersionIn;
dwOleMiscFlags = dwOleMiscFlagsIn;
dwClassFactFlags = dwClassFactFlagsIn;
}
// static class factory (no allocs!)
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::QueryInterface")));
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = (void *)GET_ICLASSFACTORY(this);
DllAddRef();
WIA_TRACE((TEXT("returning our class factory & S_OK")));
return NOERROR;
}
*ppvObj = NULL;
WIA_ERROR((TEXT("returning E_NOINTERFACE")));
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::AddRef")));
DllAddRef();
return 2;
}
STDMETHODIMP_(ULONG) CClassFactory::Release()
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::Release")));
DllRelease();
return 1;
}
STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::CreateInstance")));
*ppv = NULL;
if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
{
// It is technically illegal to aggregate an object and request
// any interface other than IUnknown. Enforce this.
//
WIA_ERROR((TEXT("we don't support aggregation, returning CLASS_E_NOAGGREGATION")));
return CLASS_E_NOAGGREGATION;
}
else
{
LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
{
WIA_ERROR((TEXT("we don't support aggregation, returning CLASS_E_NOAGGREGATION")));
return CLASS_E_NOAGGREGATION;
}
IUnknown *punk;
HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
if (SUCCEEDED(hres))
{
hres = punk->QueryInterface(riid, ppv);
punk->Release();
}
//_ASSERT(FAILED(hres) ? *ppv == NULL : TRUE);
WIA_RETURN_HR(hres);
}
}
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::LockServer")));
if (fLock)
DllAddRef();
else
DllRelease();
return S_OK;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("DllGetClassObject")));
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
*ppv = NULL;
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
{
for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
{
if (IsEqualGUID(rclsid, *(pcls->pclsid)))
{
*ppv = (void*)pcls;
DllAddRef(); // class factory holds DLL ref count
hr = S_OK;
}
}
}
#ifdef ATL_ENABLED
if (hr == CLASS_E_CLASSNOTAVAILABLE)
hr = AtlGetClassObject(rclsid, riid, ppv);
#endif
WIA_RETURN_HR(hr);
}
STDMETHODIMP UsePPWForPrintTo( LPCMINVOKECOMMANDINFO pCMI, IDataObject * pdo )
{
WIA_PUSH_FUNCTION_MASK((TRACE_PRINTTO, TEXT("UsePPWForPrintTo")));
HRESULT hr = E_INVALIDARG;
CSimpleString strPrinterName;
if (pCMI &&
((pCMI->cbSize == sizeof(CMINVOKECOMMANDINFO)) || (pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX))) &&
pdo)
{
//
// Keep a reference on the data object while we do our thing...
//
pdo->AddRef();
//
// Get printer to use...
//
if ( (pCMI->cbSize == sizeof(CMINVOKECOMMANDINFO)) ||
(pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && (!(pCMI->fMask & CMIC_MASK_UNICODE)))
)
{
//
// printer name is first token on the line, but it might be quoted...
//
CHAR szPrinterName[ MAX_PATH ];
LPCSTR p = pCMI->lpParameters;
INT i = 0;
if (p)
{
//
// skip beginning "'s, if any
//
while (*p && (*p == '\"'))
{
p++;
}
//
// Copy first param, which would be printer name...
//
while ( *p && (*p != '\"'))
{
szPrinterName[i++] = *p;
p++;
}
szPrinterName[i] = 0;
}
//
// Convert into CSimpleString...
strPrinterName.Assign(CSimpleStringConvert::NaturalString(CSimpleStringAnsi(szPrinterName)));
}
else if ((pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) && (pCMI->fMask & CMIC_MASK_UNICODE))
{
LPCMINVOKECOMMANDINFOEX pCMIEX = (LPCMINVOKECOMMANDINFOEX) pCMI;
WCHAR szwPrinterName[ MAX_PATH ];
LPCWSTR p = pCMIEX->lpParametersW;
INT i = 0;
if (p)
{
//
// skip beginning "'s, if any
//
while (*p && (*p == L'\"'))
{
p++;
}
//
// Copy first param, which would be printer name...
//
while ( *p && (*p != L'\"'))
{
szwPrinterName[i++] = *p;
p++;
}
szwPrinterName[i] = 0;
}
//
// Convert into CSimpleString...
strPrinterName.Assign(CSimpleStringConvert::NaturalString(CSimpleStringWide(szwPrinterName)));
}
WIA_TRACE((TEXT("UsePPWForPrintTo - printer name to use is [%s]"),strPrinterName.String()));
//
// Create wizard object in UI less mode...
//
CWizardInfoBlob * pWizInfo = new CWizardInfoBlob( pdo, FALSE, TRUE );
if (pWizInfo)
{
//
// create full page print template...
//
WIA_TRACE((TEXT("UsePPWForPrintTo - constructing full page template")));
pWizInfo->ConstructPrintToTemplate();
//
// Get a list of items...
//
WIA_TRACE((TEXT("UsePPWForPrintTo - adding items to print to pWizInfo")));
pWizInfo->AddAllPhotosFromDataObject();
//
// Mark all items as selected for printing...
//
LONG nItemCount = pWizInfo->CountOfPhotos(FALSE);
WIA_TRACE((TEXT("UsePPWForPrintTo - there are %d photos to be marked for printing"),nItemCount));
//
// Loop through all the photos and add them...
//
CListItem * pItem = NULL;
for (INT i=0; i < nItemCount; i++)
{
//
// Get the item in question
//
pItem = pWizInfo->GetListItem(i,FALSE);
if (pItem)
{
pItem->SetSelectionState(TRUE);
}
}
//
// Set up for printing...
//
pWizInfo->SetPrinterToUse( strPrinterName.String() );
HANDLE hPrinter = NULL;
if (OpenPrinter( (LPTSTR)strPrinterName.String(), &hPrinter, NULL ) && hPrinter)
{
LONG lSize = DocumentProperties( NULL, hPrinter, (LPTSTR)strPrinterName.String(), NULL, NULL, 0 );
if (lSize)
{
DEVMODE * pDevMode = (DEVMODE *) new BYTE[ lSize ];
if (pDevMode)
{
if (IDOK == DocumentProperties( NULL, hPrinter, (LPTSTR)strPrinterName.String(), NULL, pDevMode, DM_OUT_BUFFER ))
{
WIA_TRACE((TEXT("UsePPWForPrintTo - setting devmode to use")));
pWizInfo->SetDevModeToUse( pDevMode );
}
delete [] pDevMode;
}
}
}
if (hPrinter)
{
ClosePrinter(hPrinter);
}
//
// Create HDC for the printer...
//
HDC hDC = CreateDC( TEXT("WINSPOOL"), pWizInfo->GetPrinterToUse(), NULL, pWizInfo->GetDevModeToUse() );
if (hDC)
{
DOCINFO di = {0};
di.cbSize = sizeof(DOCINFO);
//
// turn on ICM for this hDC
//
WIA_TRACE((TEXT("UsePPWForPrintTo - setting ICM mode on for hDC")));
SetICMMode( hDC, ICM_ON );
//
// Lets use the template name for the document name...
//
CSimpleString strTitle;
CTemplateInfo * pTemplateInfo = NULL;
if (SUCCEEDED(pWizInfo->GetTemplateByIndex( 0 ,&pTemplateInfo)) && pTemplateInfo)
{
pTemplateInfo->GetTitle( &strTitle );
}
//
// Let's remove the ':' at the end if there is one
//
INT iLen = strTitle.Length();
if (iLen && (strTitle[(INT)iLen-1] == TEXT(':')))
{
strTitle.Truncate(iLen);
}
di.lpszDocName = strTitle;
WIA_TRACE((TEXT("UsePPWForPrintTo - calling StartDoc")));
if (StartDoc( hDC, &di ) > 0)
{
//
// Loop through until we've printed all the photos...
//
INT iPageCount = 0;
if (SUCCEEDED(hr = pWizInfo->GetCountOfPrintedPages( 0, &iPageCount )))
{
WIA_TRACE((TEXT("UsePPWForPrintTo - iPageCount is %d"),iPageCount));
for (INT iPage = 0; iPage < iPageCount; iPage++)
{
//
// Print the page...
//
if (StartPage( hDC ) > 0)
{
WIA_TRACE((TEXT("UsePPWForPrintTo - printing page %d"),iPage));
hr = pWizInfo->RenderPrintedPage( 0, iPage, hDC, NULL, (float)0.0, NULL );
EndPage( hDC );
}
else
{
WIA_ERROR((TEXT("UsePPWForPrintTo - StartPage failed w/GLE = %d"),GetLastError()));
}
}
}
WIA_TRACE((TEXT("UsePPWForPrintTo - calling EndDoc")));
EndDoc( hDC );
}
DeleteDC( hDC );
}
delete pWizInfo;
}
pdo->Release();
}
WIA_RETURN_HR(hr);
}