You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
631 lines
18 KiB
631 lines
18 KiB
/*****************************************************************************
|
|
*
|
|
* (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;
|
|
|
|
hinstAdvPack = LoadLibrary( TEXT("advpack.dll") );
|
|
|
|
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 (!ppvObj)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
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")));
|
|
|
|
if (!ppv)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*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;
|
|
|
|
if (!ppv)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*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 != '\"') && (i <(ARRAYSIZE(szPrinterName)-1)) )
|
|
{
|
|
szPrinterName[i++] = *p;
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// Ensure NULL termination
|
|
//
|
|
|
|
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'\"') && (i <(ARRAYSIZE(szwPrinterName)-1)) )
|
|
{
|
|
szwPrinterName[i++] = *p;
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// Ensure NULL termination
|
|
//
|
|
|
|
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);
|
|
}
|