554 lines
19 KiB
C++
554 lines
19 KiB
C++
// shimgvw.cpp : Implementation of DLL Exports.
|
|
|
|
#include "precomp.h"
|
|
#include "resource.h"
|
|
#include "cfdefs.h"
|
|
#include "advpub.h"
|
|
|
|
#include "initguid.h"
|
|
#include "shimgvw.h"
|
|
#include "guids.h"
|
|
#include "shutil.h"
|
|
#include <gdiplusImaging.h>
|
|
|
|
#define DECLARE_DEBUG
|
|
#define SZ_DEBUGINI "ccshell.ini"
|
|
#define SZ_DEBUGSECTION "Shell Image View"
|
|
#define SZ_MODULE "SHIMGVW"
|
|
#include <debug.h>
|
|
|
|
#define DECL_CRTFREE
|
|
#include <crtfree.h>
|
|
|
|
#include "prevCtrl.h" // for CPreview
|
|
|
|
#define IIDSTR_IExtractImage "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
|
|
#define REGSTR_APPROVED "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"
|
|
|
|
LPCSTR const c_rgszDocFileExts[] =
|
|
{
|
|
".doc",
|
|
".dot",
|
|
".xls",
|
|
".xlt",
|
|
".obd",
|
|
".obt",
|
|
".ppt",
|
|
".pot",
|
|
".mic",
|
|
".mix",
|
|
".fpx",
|
|
".mpp"
|
|
};
|
|
|
|
LPCSTR const c_rgszHtmlExts[] =
|
|
{
|
|
".html",
|
|
".htm",
|
|
".url",
|
|
".mhtml",
|
|
".mht",
|
|
".xml",
|
|
".nws",
|
|
".eml"
|
|
};
|
|
|
|
CComModule _Module;
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
OBJECT_ENTRY(CLSID_Preview, CPreview)
|
|
OBJECT_ENTRY(CLSID_GdiThumbnailExtractor, CGdiPlusThumb)
|
|
OBJECT_ENTRY(CLSID_DocfileThumbnailHandler, CDocFileThumb)
|
|
OBJECT_ENTRY(CLSID_HtmlThumbnailExtractor, CHtmlThumb)
|
|
END_OBJECT_MAP()
|
|
|
|
CF_TABLE_BEGIN(g_ObjectInfo)
|
|
CF_TABLE_ENTRY(&CLSID_ShellImageDataFactory, CImageDataFactory_CreateInstance, COCREATEONLY),
|
|
CF_TABLE_ENTRY(&CLSID_PhotoVerbs, CPhotoVerbs_CreateInstance, COCREATEONLY),
|
|
CF_TABLE_ENTRY(&CLSID_AutoplayForSlideShow, CAutoplayForSlideShow_CreateInstance, COCREATEONLY),
|
|
CF_TABLE_ENTRY(&CLSID_ImagePropertyHandler, CImageData_CreateInstance, COCREATEONLY),
|
|
CF_TABLE_ENTRY(&CLSID_ImageRecompress, CImgRecompress_CreateInstance, COCREATEONLY),
|
|
CF_TABLE_END(g_ObjectInfo)
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DLL Entry Point
|
|
|
|
extern "C"
|
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
|
|
{
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
SHFusionInitializeFromModule(hInstance);
|
|
_Module.Init(ObjectMap, hInstance);
|
|
DisableThreadLibraryCalls(hInstance);
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
_Module.Term();
|
|
SHFusionUninitialize();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Used to determine whether the DLL can be unloaded by OLE
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// some types can only wallpaper on win32
|
|
#ifdef _WIN64
|
|
#define IMAGEOPTION_CANWALLPAPER_WIN32 0
|
|
#else
|
|
#define IMAGEOPTION_CANWALLPAPER_WIN32 IMAGEOPTION_CANWALLPAPER
|
|
#endif
|
|
|
|
#define IMGOPT_ALL (IMAGEOPTION_CANWALLPAPER | IMAGEOPTION_CANROTATE)
|
|
#define IMGOPT_ALLW32 (IMAGEOPTION_CANWALLPAPER_WIN32 | IMAGEOPTION_CANROTATE)
|
|
#define IMGOPT_NONE 0
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Returns a class factory to create an object of the requested type
|
|
|
|
typedef struct { LPTSTR szExt; LPTSTR pszContentType; LPTSTR szProgId; LPTSTR szProgram; DWORD dwOpts;} FILETYPEINFO;
|
|
// { ".EXT", "progid", old program, IMGOPT
|
|
FILETYPEINFO g_rgExtentions[] = {
|
|
{ TEXT(".bmp"), TEXT("image/bmp"), TEXT("Paint.Picture"), TEXT("mspaint.exe"), IMGOPT_ALL, },
|
|
{ TEXT(".dib"), TEXT("image/bmp"), TEXT("Paint.Picture"), TEXT("mspaint.exe"), IMGOPT_ALL, },
|
|
{ TEXT(".emf"), NULL, TEXT("emffile"), TEXT(""), IMGOPT_NONE, },
|
|
{ TEXT(".gif"), TEXT("image/gif"), TEXT("giffile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".jfif"),TEXT("image/jpeg"), TEXT("pjpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".jpg"), TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".jpe"), TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".jpeg"),TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".png"), TEXT("image/png"), TEXT("pngfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
|
|
{ TEXT(".tif"), TEXT("image/tiff"), TEXT("TIFImage.Document"), TEXT("KodakPrv.exe"), IMGOPT_NONE, },
|
|
{ TEXT(".tiff"),TEXT("image/tiff"), TEXT("TIFImage.Document"), TEXT("KodakPrv.exe"), IMGOPT_NONE, },
|
|
{ TEXT(".wmf"), NULL, TEXT("wmffile"), TEXT(""), IMGOPT_NONE, },
|
|
};
|
|
|
|
const TCHAR c_szBitmapIcon[] = TEXT("shimgvw.dll,1");
|
|
const TCHAR c_szDefaultIcon[] = TEXT("shimgvw.dll,2");
|
|
const TCHAR c_szJPegIcon[] = TEXT("shimgvw.dll,3");
|
|
const TCHAR c_szTifIcon[] = TEXT("shimgvw.dll,4");
|
|
|
|
// we might have to create a missing Prog ID so we need to know its default info.
|
|
typedef struct { LPCTSTR szProgID; int iResId; LPCTSTR szIcon; BOOL fDone; } PROGIDINFO;
|
|
// { "ProgID" "Description" "DefaultIcon" done? }
|
|
PROGIDINFO g_rgProgIDs[] = {
|
|
{ TEXT("emffile"), IDS_EMFIMAGE, c_szDefaultIcon, FALSE },
|
|
{ TEXT("giffile"), IDS_GIFIMAGE, c_szDefaultIcon, FALSE },
|
|
{ TEXT("jpegfile"), IDS_JPEGIMAGE, c_szJPegIcon, FALSE },
|
|
{ TEXT("Paint.Picture"), IDS_BITMAPIMAGE, c_szBitmapIcon, FALSE },
|
|
{ TEXT("pjpegfile"), IDS_JPEGIMAGE, c_szJPegIcon, FALSE },
|
|
{ TEXT("pngfile"), IDS_PNGIMAGE, c_szDefaultIcon, FALSE },
|
|
{ TEXT("TIFImage.Document"),IDS_TIFIMAGE, c_szTifIcon, FALSE },
|
|
{ TEXT("wmffile"), IDS_WMFIMAGE, c_szDefaultIcon, FALSE },
|
|
};
|
|
|
|
BOOL _ShouldSlamVerb(HKEY hkProgid, BOOL fForce, PCWSTR pszKey, PCWSTR pszApp, PCWSTR pszModule)
|
|
{
|
|
if (!fForce)
|
|
{
|
|
TCHAR szOld[MAX_PATH*2];
|
|
DWORD cbOld = sizeof(szOld);
|
|
if (ERROR_SUCCESS == SHGetValue(hkProgid, pszKey, NULL, NULL, szOld, &cbOld) && *szOld)
|
|
{
|
|
// if we know about this app, then blow it away
|
|
if ((*pszApp && StrStrI(szOld, pszApp))
|
|
|| StrStrI(szOld, pszModule)
|
|
|| StrStrI(szOld, TEXT("wangimg.exe"))) // NT4 app
|
|
{
|
|
fForce = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fForce = TRUE;
|
|
}
|
|
}
|
|
|
|
return fForce;
|
|
}
|
|
|
|
BOOL _ExtIsProgid(PCTSTR pszExt, PCTSTR pszProgid, DWORD dwOpts)
|
|
{
|
|
// default to take-over
|
|
BOOL fRet = TRUE;
|
|
TCHAR sz[MAX_PATH];
|
|
// make sure this is in the openwith list
|
|
wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s\\OpenWithProgids"), pszExt);
|
|
SHSetValue(HKEY_CLASSES_ROOT, sz, pszProgid, REG_NONE, NULL, NULL);
|
|
// make sure the flags are set for our verbs to show up
|
|
wnsprintf(sz, ARRAYSIZE(sz), TEXT("SystemFileAssociations\\%s"), pszExt);
|
|
SHSetValue(HKEY_CLASSES_ROOT, sz, TEXT("ImageOptionFlags"), REG_DWORD, &dwOpts, sizeof(dwOpts));
|
|
|
|
SHSetValue(HKEY_CLASSES_ROOT, pszExt, TEXT("PerceivedType"), REG_SZ, TEXT("image"), sizeof(TEXT("image")));
|
|
|
|
DWORD cb = sizeof(sz);
|
|
if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, sz, &cb))
|
|
{
|
|
// empty or match is good
|
|
fRet = (!*sz || 0 == StrCmpI(sz, pszProgid));
|
|
}
|
|
|
|
// always remove bogus Trident IExtractImage entries
|
|
wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s\\shellex\\{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"), pszExt);
|
|
SHDeleteKey(HKEY_CLASSES_ROOT, sz);
|
|
PathRemoveFileSpec(sz);
|
|
SHDeleteEmptyKey(HKEY_CLASSES_ROOT, sz);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
PROGIDINFO *_ShouldSetupProgid(FILETYPEINFO *pfti, BOOL fForce)
|
|
{
|
|
PROGIDINFO *ppi = NULL;
|
|
if (_ExtIsProgid(pfti->szExt, pfti->szProgId, pfti->dwOpts) || fForce)
|
|
{
|
|
// take it over
|
|
SHSetValue(HKEY_CLASSES_ROOT, pfti->szExt, NULL, REG_SZ, pfti->szProgId, CbFromCch(lstrlen(pfti->szProgId)+1));
|
|
if (pfti->pszContentType)
|
|
{
|
|
SHSetValue(HKEY_CLASSES_ROOT, pfti->szExt, TEXT("Content Type"), REG_SZ, pfti->pszContentType, CbFromCch(lstrlen(pfti->pszContentType)+1));
|
|
}
|
|
|
|
// we now know that szProgID is the ProgID for this extention.
|
|
// look up the index into the ProgID table to see if we did this one already.
|
|
int iProgIdIndex;
|
|
for (iProgIdIndex=0; iProgIdIndex<ARRAYSIZE(g_rgProgIDs); iProgIdIndex++)
|
|
{
|
|
if (0 == StrCmpI(g_rgProgIDs[iProgIdIndex].szProgID, pfti->szProgId))
|
|
{
|
|
if (!g_rgProgIDs[iProgIdIndex].fDone)
|
|
ppi = &g_rgProgIDs[iProgIdIndex];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ppi;
|
|
}
|
|
|
|
|
|
void RegisterFileType(FILETYPEINFO *pfti, BOOL fForce)
|
|
{
|
|
PROGIDINFO *ppi = _ShouldSetupProgid(pfti, fForce);
|
|
if (ppi)
|
|
{
|
|
// this ProgID is in our table
|
|
HKEY hkeyProgId;
|
|
LRESULT lres = RegCreateKeyEx(HKEY_CLASSES_ROOT,
|
|
pfti->szProgId,
|
|
0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ|KEY_WRITE, NULL,
|
|
&hkeyProgId, NULL);
|
|
|
|
if (ERROR_SUCCESS == lres)
|
|
{
|
|
LPCTSTR pszIcon = ppi->szIcon;
|
|
TCHAR szModPath[MAX_PATH];
|
|
GetModuleFileName(_Module.GetModuleInstance(), szModPath, ARRAYSIZE(szModPath));
|
|
PCWSTR pszModule = PathFindFileName(szModPath);
|
|
TCHAR szCmd[MAX_PATH * 2];
|
|
// should we slam the default value?
|
|
// to progid = "EXT file"
|
|
if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\open\\command", pfti->szProgram, pszModule))
|
|
{
|
|
SHDeleteKey(hkeyProgId, TEXT("shell\\open"));
|
|
wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("rundll32.exe %s,ImageView_Fullscreen %%1"), szModPath);
|
|
SHRegSetPath(hkeyProgId, TEXT("shell\\open\\command"), NULL, szCmd, 0);
|
|
SHStringFromGUID(CLSID_PhotoVerbs, szCmd, ARRAYSIZE(szCmd));
|
|
SHSetValue(hkeyProgId, TEXT("shell\\open\\DropTarget"), TEXT("Clsid"), REG_SZ, szCmd, CbFromCch(lstrlen(szCmd)+1));
|
|
wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("@%s,%d"), pszModule, -IDS_PREVIEW_CTX);
|
|
SHSetValue(hkeyProgId, TEXT("shell\\open"), TEXT("MuiVerb"), REG_SZ, szCmd, CbFromCch(lstrlen(szCmd)+1));
|
|
SHRegSetPath(hkeyProgId, TEXT("DefaultIcon"), NULL, pszIcon, 0);
|
|
}
|
|
|
|
if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\printto\\command", TEXT("mspaint.exe"), pszModule))
|
|
{
|
|
SHDeleteKey(hkeyProgId, TEXT("shell\\printto"));
|
|
wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("rundll32.exe %s,ImageView_PrintTo /pt \"%%1\" \"%%2\" \"%%3\" \"%%4\""), szModPath);
|
|
SHRegSetPath(hkeyProgId, TEXT("shell\\printto\\command"), NULL, szCmd, 0);
|
|
}
|
|
|
|
// this will delete print verb
|
|
// print is added in selfreg under HKCR\SystemFileAssociations\image\Print
|
|
if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\print\\command", TEXT("mspaint.exe"), pszModule))
|
|
{
|
|
SHDeleteKey(hkeyProgId, TEXT("shell\\print"));
|
|
}
|
|
|
|
// Modify the EditFlags: it's okay to run these without prompting...
|
|
DWORD dwEditFlags = 0;
|
|
DWORD cbEditFlags = sizeof(dwEditFlags);
|
|
SHGetValue(hkeyProgId, NULL, TEXT("EditFlags"), NULL, &dwEditFlags, &cbEditFlags);
|
|
dwEditFlags |= 0x00010000; // turn on the "okay to run without prompt" flag
|
|
SHSetValue(hkeyProgId, NULL, TEXT("EditFlags"), REG_DWORD, &dwEditFlags, sizeof(dwEditFlags));
|
|
|
|
RegCloseKey(hkeyProgId);
|
|
}
|
|
ppi->fDone = TRUE;
|
|
}
|
|
}
|
|
|
|
HRESULT _CallRegInstall(LPCSTR szSection, BOOL bUninstall)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HINSTANCE 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(_Module.GetModuleInstance(), 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;
|
|
}
|
|
|
|
void _FixupProgid(PCSTR pszExt, PCSTR pszProgid)
|
|
{
|
|
HKEY hk;
|
|
DWORD dwRet = RegOpenKeyExA(HKEY_CLASSES_ROOT, pszExt, 0, KEY_QUERY_VALUE, &hk);
|
|
if (dwRet == ERROR_SUCCESS)
|
|
{
|
|
// if its empty, then we need to fix it up.
|
|
CHAR sz[MAX_PATH];
|
|
DWORD cb = sizeof(sz);
|
|
if (ERROR_SUCCESS == SHGetValueA(hk, NULL, NULL, NULL, sz, &cb) && !*sz)
|
|
{
|
|
SHSetValueA(hk, NULL, NULL, REG_SZ, pszProgid, CbFromCchA(lstrlenA(pszProgid)+1));
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT RegisterHandler(const LPCSTR *ppszExts, UINT cExts, LPCSTR pszIID, LPCSTR pszCLSID)
|
|
{
|
|
for (UINT cKey = 0; cKey < cExts; cKey ++)
|
|
{
|
|
CHAR szKey[MAX_PATH];
|
|
wnsprintfA(szKey, ARRAYSIZE(szKey), "SystemFileAssociations\\%s\\shellex\\%s", *ppszExts, pszIID);
|
|
SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
|
|
SHSetValueA(HKEY_CLASSES_ROOT, szKey, NULL, REG_SZ, pszCLSID, CbFromCch(lstrlenA(pszCLSID)+1));
|
|
ppszExts++;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT UnregisterHandler(const LPCSTR *ppszExts, UINT cExts, LPCSTR pszIID, LPCSTR pszCLSID)
|
|
{
|
|
for (UINT cKey = 0; cKey < cExts; cKey ++)
|
|
{
|
|
CHAR szKey[MAX_PATH];
|
|
CHAR szCLSID[256];
|
|
DWORD dwSize = sizeof(szCLSID);
|
|
wnsprintfA(szKey, ARRAYSIZE(szKey), "SystemFileAssociations\\%s\\shellex\\%s", *ppszExts, pszIID);
|
|
if (ERROR_SUCCESS == SHGetValueA(HKEY_CLASSES_ROOT, szKey, NULL, NULL, &szCLSID, &dwSize))
|
|
{
|
|
if (!StrCmpIA(szCLSID, pszCLSID))
|
|
{
|
|
SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
|
|
}
|
|
}
|
|
dwSize = sizeof(szCLSID);
|
|
wnsprintfA(szKey, ARRAYSIZE(szKey), "%s\\shellex\\%s", *ppszExts, pszIID);
|
|
if (ERROR_SUCCESS == SHGetValueA(HKEY_CLASSES_ROOT, szKey, NULL, NULL, &szCLSID, &dwSize))
|
|
{
|
|
if (!StrCmpIA(szCLSID, pszCLSID))
|
|
{
|
|
SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
|
|
}
|
|
}
|
|
ppszExts++;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDAPI DllRegisterServer(void)
|
|
{
|
|
// REVIEW: should this be done only in DLLInstall?
|
|
for (int i=0; i<ARRAYSIZE(g_rgExtentions); i++)
|
|
{
|
|
RegisterFileType(g_rgExtentions+i, FALSE);
|
|
}
|
|
|
|
RegisterHandler(c_rgszDocFileExts, ARRAYSIZE(c_rgszDocFileExts), IIDSTR_IExtractImage, CLSIDSTR_DocfileThumbnailHandler);
|
|
UnregisterHandler(c_rgszHtmlExts, ARRAYSIZE(c_rgszHtmlExts), IIDSTR_IExtractImage, CLSIDSTR_HtmlThumbnailExtractor);
|
|
|
|
_CallRegInstall("RegDll", TRUE);
|
|
|
|
// powerpoint gets freaked by empty extension keys.
|
|
_FixupProgid(".ppt", "Powerpoint.Show.7");
|
|
_FixupProgid(".pot", "Powerpoint.Template");
|
|
|
|
// registers object, typelib and all interfaces in typelib
|
|
return _Module.RegisterServer(TRUE);
|
|
}
|
|
|
|
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
_Module.UnregisterServer();
|
|
|
|
UnregisterHandler(c_rgszDocFileExts, ARRAYSIZE(c_rgszDocFileExts), IIDSTR_IExtractImage, CLSIDSTR_DocfileThumbnailHandler);
|
|
UnregisterHandler(c_rgszHtmlExts, ARRAYSIZE(c_rgszHtmlExts), IIDSTR_IExtractImage, CLSIDSTR_HtmlThumbnailExtractor);
|
|
|
|
_CallRegInstall("UnRegDll", TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
|
|
{
|
|
if (bInstall)
|
|
{
|
|
BOOL fForce = StrStrIW(pszCmdLine, L"/FORCE") != 0;
|
|
for (int i=0; i<ARRAYSIZE(g_rgExtentions); i++)
|
|
{
|
|
RegisterFileType(g_rgExtentions+i, fForce);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DllRegisterServer - Adds entries to the system registry
|
|
|
|
//
|
|
// 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
|
|
|
|
// 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)
|
|
{
|
|
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (void *)GET_ICLASSFACTORY(this);
|
|
_Module.Lock();
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
|
|
{
|
|
_Module.Lock();
|
|
return 2;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::Release()
|
|
{
|
|
_Module.Unlock();
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
|
{
|
|
*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.
|
|
//
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
else
|
|
{
|
|
LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
|
|
|
|
if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
IUnknown *punk;
|
|
HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = punk->QueryInterface(riid, ppv);
|
|
punk->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
_Module.Lock();
|
|
else
|
|
_Module.Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Object constructor
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
|
{
|
|
// handle non-ATL objects first
|
|
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;
|
|
_Module.Lock();
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try the ATL way....
|
|
return _Module.GetClassObject(rclsid, riid, ppv);
|
|
}
|
|
|
|
|