windows-nt/Source/XPSP1/NT/shell/ext/netplwiz/pubdrop.cpp
2020-09-26 16:20:57 +08:00

807 lines
26 KiB
C++

#include "stdafx.h"
#include "pubwiz.h"
#pragma hdrstop
typedef struct
{
CLSID clsidWizard; // which wizard is being invoked
IStream *pstrmDataObj; // IDataObject marshall object
IStream *pstrmView; // IFolderView marshall object
} PUBWIZDROPINFO;
// This is the drop target object which exposes the publishing wizard
class CPubDropTarget : public IDropTarget, IPersistFile, IWizardSite, IServiceProvider, CObjectWithSite
{
public:
CPubDropTarget(CLSID clsidWizard, IFolderView *pfv);
~CPubDropTarget();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
STDMETHOD_(ULONG,AddRef)(void);
STDMETHOD_(ULONG,Release)(void);
// IPersist
STDMETHODIMP GetClassID(CLSID *pClassID)
{ *pClassID = _clsidWizard; return S_OK; };
// IPersistFile
STDMETHODIMP IsDirty(void)
{ return S_FALSE; };
STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode)
{ return S_OK; };
STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember)
{ return S_OK; };
STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName)
{ return S_OK; };
STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName)
{ *ppszFileName = NULL; return S_OK; };
// IDropTarget
STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{ *pdwEffect = DROPEFFECT_COPY; return S_OK; };
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{ *pdwEffect = DROPEFFECT_COPY; return S_OK; };
STDMETHODIMP DragLeave(void)
{ return S_OK; };
STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
// IWizardSite
STDMETHODIMP GetPreviousPage(HPROPSHEETPAGE *phPage);
STDMETHODIMP GetNextPage(HPROPSHEETPAGE *phPage);
STDMETHODIMP GetCancelledPage(HPROPSHEETPAGE *phPage)
{ return GetNextPage(phPage); }
// IServiceProvider
STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
private:
CLSID _clsidWizard;
LONG _cRef;
HWND _hwndFrame;
IPublishingWizard *_ppw;
IResourceMap *_prm;
IUnknown *_punkFTM;
IFolderView *_pfv;
TCHAR _szSiteName[MAX_PATH];
TCHAR _szSiteURL[INTERNET_MAX_URL_LENGTH];
// helpers
static void s_FreePubWizDropInfo(PUBWIZDROPINFO *ppwdi);
static DWORD s_PublishThreadProc(void *pv);
void _Publish(IDataObject *pdo);
INT_PTR _InitDonePage(HWND hwnd);
void _OpenSiteURL();
// dialog handlers
static INT_PTR s_WelcomeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ CPubDropTarget *ppdt = s_GetPDT(hwnd, uMsg, lParam); return ppdt->_WelcomeDlgProc(hwnd, uMsg, wParam, lParam); }
static INT_PTR s_DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ CPubDropTarget *ppdt = s_GetPDT(hwnd, uMsg, lParam); return ppdt->_DoneDlgProc(hwnd, uMsg, wParam, lParam); }
static CPubDropTarget* s_GetPDT(HWND hwnd, UINT uMsg, LPARAM lParam);
INT_PTR _WelcomeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR _DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
friend void PublishRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow);
};
// Construction/destruction
CPubDropTarget::CPubDropTarget(CLSID clsidWizard, IFolderView *pfv) :
_clsidWizard(clsidWizard), _cRef(1)
{
// use the FTM to make the call back interface calls unmarshalled
CoCreateFreeThreadedMarshaler(SAFECAST(this, IDropTarget *), &_punkFTM);
// addref the IFolderView object we might be given
IUnknown_Set((IUnknown**)&_pfv, pfv);
DllAddRef();
}
CPubDropTarget::~CPubDropTarget()
{
ATOMICRELEASE(_punkFTM);
ATOMICRELEASE(_pfv);
DllRelease();
}
// Reference counting of the object
ULONG CPubDropTarget::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CPubDropTarget::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CPubDropTarget::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CPubDropTarget, IObjectWithSite), // IID_IObjectWithSite
QITABENT(CPubDropTarget, IWizardSite), // IID_IWizardSite
QITABENT(CPubDropTarget, IDropTarget), // IID_IDropTarget
QITABENT(CPubDropTarget, IPersistFile), // IID_IPersistFile
QITABENT(CPubDropTarget, IServiceProvider), // IID_IServiceProvider
{0, 0},
};
HRESULT hr = QISearch(this, qit, riid, ppv);
if (FAILED(hr) && _punkFTM)
{
hr = _punkFTM->QueryInterface(riid, ppv);
}
return hr;
}
// retrieve the 'this' ptr for the dialog
CPubDropTarget* CPubDropTarget::s_GetPDT(HWND hwnd, UINT uMsg, LPARAM lParam)
{
if (uMsg == WM_INITDIALOG)
{
PROPSHEETPAGE *ppsp = (PROPSHEETPAGE*)lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, ppsp->lParam);
return (CPubDropTarget*)ppsp->lParam;
}
return (CPubDropTarget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
// Welcome dialog.
INT_PTR CPubDropTarget::_WelcomeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
_hwndFrame = GetParent(hwnd);
SendDlgItemMessage(hwnd, IDC_PUB_WELCOME, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
IXMLDOMNode *pdn;
HRESULT hr = _prm->SelectResourceScope(TEXT("dialog"), TEXT("welcome"), &pdn);
if (SUCCEEDED(hr))
{
TCHAR szBuffer[512];
_prm->LoadString(pdn, TEXT("caption"), szBuffer, ARRAYSIZE(szBuffer));
SetDlgItemText(hwnd, IDC_PUB_WELCOME, szBuffer);
_prm->LoadString(pdn, TEXT("description"), szBuffer, ARRAYSIZE(szBuffer));
SetDlgItemText(hwnd, IDC_PUB_WELCOMEPROMPT, szBuffer);
pdn->Release();
}
return TRUE;
}
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
{
#if 0
if (_fSkipWelcome)
{
_fSkipWelcome = FALSE;
HPROPSHEETPAGE hpage;
if (SUCCEEDED(_ppw->GetFirstPage(&hpage)))
{
int i = PropSheet_PageToIndex(GetParent(hwnd), hpage);
if (i > 0) //cannot be zero because that's our index
{
UINT_PTR id = PropSheet_IndexToId(GetParent(hwnd), i);
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)id);
}
}
}
#endif
PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
return TRUE;
}
case PSN_WIZNEXT:
{
HPROPSHEETPAGE hpage;
if (SUCCEEDED(_ppw->GetFirstPage(&hpage)))
{
PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
}
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
return TRUE;
}
}
break;
}
}
return FALSE;
}
// layout the controls on the done page
INT_PTR CPubDropTarget::_InitDonePage(HWND hwnd)
{
HRESULT hrFromTransfer = E_FAIL; // default to that based on not getting any state back!
// these are the states we can read back from the manifest
BOOL fHasSiteName = FALSE;
BOOL fHasNetPlace = FALSE;
BOOL fHasFavorite = FALSE;
BOOL fHasURL = FALSE;
// lets crack the manifest and work out whats what with the publish that
// we just performed.
IXMLDOMDocument *pdocManifest;
HRESULT hr = _ppw->GetTransferManifest(&hrFromTransfer, &pdocManifest);
if (SUCCEEDED(hr))
{
IXMLDOMNode *pdnUploadInfo;
hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdnUploadInfo);
if (hr == S_OK)
{
IXMLDOMElement *pdel;
VARIANT var;
// lets pick up the site name from the manifest, this will be an attribute on the
// upload info element.
hr = pdnUploadInfo->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel));
if (SUCCEEDED(hr))
{
hr = pdel->getAttribute(ATTRIBUTE_FRIENDLYNAME, &var);
if (hr == S_OK)
{
StrCpyN(_szSiteName, var.bstrVal, ARRAYSIZE(_szSiteName));
VariantClear(&var);
fHasSiteName = TRUE;
}
pdel->Release();
}
// lets now try and pick up the site URL node, this is going to either
// be the file target, or HTML UI element.
IXMLDOMNode *pdnURL;
hr = pdnUploadInfo->selectSingleNode(ELEMENT_HTMLUI, &pdnURL);
if (hr == S_FALSE)
hr = pdnUploadInfo->selectSingleNode(ELEMENT_NETPLACE, &pdnURL);
if (hr== S_FALSE)
hr = pdnUploadInfo->selectSingleNode(ELEMENT_TARGET, &pdnURL);
if (hr == S_OK)
{
hr = pdnURL->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel));
if (SUCCEEDED(hr))
{
// attempt to read the HREF attribute, if that is defined
// the we use it, otherwise (for compatibility with B2, we need
// to get the node text and use that instead).
hr = pdel->getAttribute(ATTRIBUTE_HREF, &var);
if (hr != S_OK)
hr = pdel->get_nodeTypedValue(&var);
if (hr == S_OK)
{
StrCpyN(_szSiteURL, var.bstrVal, ARRAYSIZE(_szSiteURL));
VariantClear(&var);
fHasURL = TRUE; // we now have the URL
}
pdel->Release();
}
pdnURL->Release();
}
// lets check for the favorite - if the element is present then we assume that
// it was created.
IXMLDOMNode *pdnFavorite;
hr = pdnUploadInfo->selectSingleNode(ELEMENT_FAVORITE, &pdnFavorite);
if (hr == S_OK)
{
pdnFavorite->Release();
fHasFavorite = TRUE;
}
// lets check for the net place element - if the element is present then we
// will assume it was created.
IXMLDOMNode *pdnNetPlace;
hr = pdnUploadInfo->selectSingleNode(ELEMENT_NETPLACE, &pdnNetPlace);
if (hr == S_OK)
{
pdnNetPlace->Release();
fHasNetPlace = TRUE;
}
pdnUploadInfo->Release();
}
pdocManifest->Release();
}
// adjust the resources on the done page to reflect the wizard that was invoked
// and more importantly the success / failure that ocurred.
IXMLDOMNode *pdn;
hr = _prm->SelectResourceScope(TEXT("dialog"), TEXT("done"), &pdn);
if (SUCCEEDED(hr))
{
TCHAR szBuffer[384 + INTERNET_MAX_URL_LENGTH]; // enough for URL + text
_prm->LoadString(pdn, TEXT("caption"), szBuffer, ARRAYSIZE(szBuffer));
SetDlgItemText(hwnd, IDC_PUB_DONE, szBuffer);
if (hrFromTransfer == HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
_prm->LoadString(pdn, TEXT("cancel"), szBuffer, ARRAYSIZE(szBuffer));
}
else if (FAILED(hrFromTransfer))
{
_prm->LoadString(pdn, TEXT("failure"), szBuffer, ARRAYSIZE(szBuffer));
}
else
{
TCHAR szIntro[128] = {0};
TCHAR szLink[128 +INTERNET_MAX_URL_LENGTH] = {0};
TCHAR szConclusion[128] = {0};
// get the intro text - this is common for all success pages
_prm->LoadString(pdn, TEXT("success"), szIntro, ARRAYSIZE(szIntro));
// if we have a link then we sometimes have a intro for that also
if (fHasURL)
{
TCHAR szFmt[MAX_PATH];
if (SUCCEEDED(_prm->LoadString(pdn, TEXT("haslink"), szFmt, ARRAYSIZE(szFmt))))
{
wnsprintf(szLink, ARRAYSIZE(szLink), szFmt, fHasSiteName ? _szSiteName:_szSiteURL);
}
}
// then for some scenarios we have a postscript about creating favorites/netplaces
if (fHasFavorite && fHasNetPlace)
{
_prm->LoadString(pdn, TEXT("hasfavoriteandplace"), szConclusion, ARRAYSIZE(szConclusion));
}
else if (fHasNetPlace)
{
_prm->LoadString(pdn, TEXT("hasplace"), szConclusion, ARRAYSIZE(szConclusion));
}
else if (fHasFavorite)
{
_prm->LoadString(pdn, TEXT("hasfavorite"), szConclusion, ARRAYSIZE(szConclusion));
}
// format it all into one string that we can set into the control
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("%s%s%s"), szIntro, szLink, szConclusion);
}
// update the message based on the strings we loaded. lets move the controls accordingly
SetDlgItemText(hwnd, IDC_PUB_COMPLETEMSG, szBuffer);
UINT ctls[] = { IDC_PUB_OPENFILES };
int dy = SizeControlFromText(hwnd, IDC_PUB_COMPLETEMSG, szBuffer);
MoveControls(hwnd, ctls, ARRAYSIZE(ctls), 0, dy);
// show/hide the "open these files check" based on the URL that we might have
BOOL fShowOpen = fHasURL && SUCCEEDED(hrFromTransfer) && (_clsidWizard == CLSID_PublishDropTarget);
ShowWindow(GetDlgItem(hwnd, IDC_PUB_OPENFILES), fShowOpen ? SW_SHOW:SW_HIDE);
CheckDlgButton(hwnd, IDC_PUB_OPENFILES, fShowOpen);
pdn->Release();
}
// set the buttons to reflect what we can do in the wizard
PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH|PSWIZB_BACK);
return TRUE;
}
void CPubDropTarget::_OpenSiteURL()
{
SHELLEXECUTEINFO shexinfo = {0};
shexinfo.cbSize = sizeof(shexinfo);
shexinfo.fMask = SEE_MASK_FLAG_NO_UI;
shexinfo.nShow = SW_SHOWNORMAL;
shexinfo.lpVerb = TEXT("open");
shexinfo.lpFile =_szSiteURL;
ShellExecuteEx(&shexinfo);
}
INT_PTR CPubDropTarget::_DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
SendDlgItemMessage(hwnd, IDC_PUB_DONE, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
return TRUE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case NM_CLICK:
case NM_RETURN:
if (pnmh->idFrom == IDC_PUB_COMPLETEMSG)
{
_OpenSiteURL();
return TRUE;
}
break;
case PSN_SETACTIVE:
return _InitDonePage(hwnd);
case PSN_WIZBACK:
{
HPROPSHEETPAGE hpage;
if (SUCCEEDED(_ppw->GetLastPage(&hpage)))
{
PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
}
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
return TRUE;
}
case PSN_WIZFINISH:
{
if (IsDlgButtonChecked(hwnd, IDC_PUB_OPENFILES) == BST_CHECKED)
{
_OpenSiteURL();
}
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)FALSE);
return TRUE;
}
}
break;
}
}
return FALSE;
}
// IServiceProvider
STDMETHODIMP CPubDropTarget::QueryService(REFGUID guidService, REFIID riid, void **ppv)
{
if (guidService == SID_ResourceMap)
{
return _prm->QueryInterface(riid, ppv);
}
else if ((guidService == SID_SFolderView) && _pfv)
{
return _pfv->QueryInterface(riid, ppv);
}
*ppv = NULL;
return E_NOINTERFACE;
}
// site object helpers, these allow nagivation back and forward in the wizard
HRESULT CPubDropTarget::GetPreviousPage(HPROPSHEETPAGE *phPage)
{
int i = PropSheet_IdToIndex(_hwndFrame, IDD_PUB_WELCOME);
*phPage = PropSheet_IndexToPage(_hwndFrame, i);
return S_OK;
}
HRESULT CPubDropTarget::GetNextPage(HPROPSHEETPAGE *phPage)
{
int i = PropSheet_IdToIndex(_hwndFrame, IDD_PUB_DONE);
*phPage = PropSheet_IndexToPage(_hwndFrame, i);
return S_OK;
}
// our publishing object
void CPubDropTarget::_Publish(IDataObject *pdo)
{
// wizard implementation
struct
{
LPCTSTR idPage;
LPCTSTR pszPage;
DWORD dwFlags;
DLGPROC dlgproc;
}
_wizardpages[] =
{
{MAKEINTRESOURCE(IDD_PUB_WELCOME), TEXT("welcome"), PSP_HIDEHEADER, CPubDropTarget::s_WelcomeDlgProc},
{MAKEINTRESOURCE(IDD_PUB_DONE), TEXT("done"), PSP_HIDEHEADER, CPubDropTarget::s_DoneDlgProc},
};
// load the resource map for this instance of the wizard
HRESULT hr = CResourceMap_Initialize(L"res://netplwiz.dll/xml/resourcemap.xml", &_prm);
if (SUCCEEDED(hr))
{
// if this is the printing wizard then configure accordingly
// (eg. remove ADVANCED, FOLDERCREATEION and NETPLACES).
DWORD dwFlags = 0x0;
LPTSTR pszWizardDefn = TEXT("PublishingWizard");
if (_clsidWizard == CLSID_InternetPrintOrdering)
{
dwFlags |= SHPWHF_NONETPLACECREATE|SHPWHF_NORECOMPRESS;
pszWizardDefn = TEXT("InternetPhotoPrinting");
}
hr = _prm->LoadResourceMap(TEXT("wizard"), pszWizardDefn);
if (SUCCEEDED(hr))
{
// create the page array, we add the welcome page and the finished page
// the rest is loaded as an extension to the wizard.
HPROPSHEETPAGE hpages[10] = { 0 };
for (int cPages = 0; SUCCEEDED(hr) && (cPages < ARRAYSIZE(_wizardpages)); cPages++)
{
// find resource map for this page of the wizard
IXMLDOMNode *pdn;
hr = _prm->SelectResourceScope(TEXT("dialog"), _wizardpages[cPages].pszPage, &pdn);
if (SUCCEEDED(hr))
{
TCHAR szTitle[MAX_PATH], szHeading[MAX_PATH], szSubHeading[MAX_PATH];
_prm->LoadString(pdn, TEXT("title"), szTitle, ARRAYSIZE(szTitle));
_prm->LoadString(pdn, TEXT("heading"), szHeading, ARRAYSIZE(szHeading));
_prm->LoadString(pdn, TEXT("subheading"), szSubHeading, ARRAYSIZE(szSubHeading));
PROPSHEETPAGE psp = { 0 };
psp.dwSize = sizeof(PROPSHEETPAGE);
psp.hInstance = g_hinst;
psp.lParam = (LPARAM)this;
psp.dwFlags = PSP_USETITLE | PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | _wizardpages[cPages].dwFlags;
psp.pszTemplate = _wizardpages[cPages].idPage;
psp.pfnDlgProc = _wizardpages[cPages].dlgproc;
psp.pszTitle = szTitle;
psp.pszHeaderTitle = szHeading;
psp.pszHeaderSubTitle = szSubHeading;
hpages[cPages] = CreatePropertySheetPage(&psp);
hr = ((hpages[cPages]) != NULL) ? S_OK:E_FAIL;
pdn->Release();
}
}
// lets create the web publishing wizard, this will handle the transfer
// and destination selection for the upload.
hr = CoCreateInstance(CLSID_PublishingWizard, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPublishingWizard, &_ppw));
if (SUCCEEDED(hr))
{
IUnknown_SetSite(_ppw, SAFECAST(this, IWizardSite*));
hr = _ppw->Initialize(pdo, dwFlags, pszWizardDefn);
if (SUCCEEDED(hr))
{
UINT cExtnPages;
hr = _ppw->AddPages(&hpages[cPages], ARRAYSIZE(hpages)-cPages, &cExtnPages);
if (SUCCEEDED(hr))
{
cPages += cExtnPages;
}
}
}
// ... that all worked so lets show the wizard. on our way our remember
// to clear up the objects
if (SUCCEEDED(hr))
{
PROPSHEETHEADER psh = { 0 };
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.hInstance = g_hinst;
psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | (PSH_WATERMARK|PSH_USEHBMWATERMARK) | (PSH_HEADER|PSH_USEHBMHEADER);
psh.phpage = hpages;
psh.nPages = cPages;
_prm->LoadBitmap(NULL, TEXT("header"), &psh.hbmHeader);
_prm->LoadBitmap(NULL, TEXT("watermark"), &psh.hbmWatermark);
if (psh.hbmHeader && psh.hbmWatermark)
PropertySheet(&psh);
if (psh.hbmHeader)
DeleteObject(psh.hbmHeader);
if (psh.hbmWatermark)
DeleteObject(psh.hbmWatermark);
}
IUnknown_SetSite(_ppw, NULL); // discard the publishing wizard
IUnknown_Set((IUnknown**)&_ppw, NULL);
}
IUnknown_Set((IUnknown**)&_prm, NULL); // no more resource map
}
}
// handle the drop operation, as the publishing wizard can take a long time we
// marshall the IDataObject and then create a worker thread which can
// handle showing the wizard.
void CPubDropTarget::s_FreePubWizDropInfo(PUBWIZDROPINFO *ppwdi)
{
if (ppwdi->pstrmDataObj)
ppwdi->pstrmDataObj->Release();
if (ppwdi->pstrmView)
ppwdi->pstrmView->Release();
LocalFree(ppwdi);
}
DWORD CPubDropTarget::s_PublishThreadProc(void *pv)
{
PUBWIZDROPINFO *ppwdi = (PUBWIZDROPINFO*)pv;
if (ppwdi)
{
// ICW must have run before we go too far down this path
LaunchICW();
// get the IDataObject, we need this to handle th drop
IDataObject *pdo;
HRESULT hr = CoGetInterfaceAndReleaseStream(ppwdi->pstrmDataObj, IID_PPV_ARG(IDataObject, &pdo));
ppwdi->pstrmDataObj = NULL; // CoGetInterfaceAndReleaseStream always releases; NULL out.
if (SUCCEEDED(hr))
{
// try to unmarshall the IFolderView object we will use.
IFolderView *pfv = NULL;
if (ppwdi->pstrmView)
{
CoGetInterfaceAndReleaseStream(ppwdi->pstrmView, IID_PPV_ARG(IFolderView, &pfv));
ppwdi->pstrmView = NULL; // CoGetInterfaceAndReleaseStream always releases; NULL out.
}
CPubDropTarget *ppw = new CPubDropTarget(ppwdi->clsidWizard, pfv);
if (ppw)
{
ppw->_Publish(pdo);
ppw->Release();
}
if (pfv)
pfv->Release();
pdo->Release();
}
s_FreePubWizDropInfo(ppwdi);
}
return 0;
}
STDMETHODIMP CPubDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
HRESULT hr = E_OUTOFMEMORY;
// create an instance of the wizard on another thread, package up any parameters
// into a structure for the thread to handle (eg. the drop target)
PUBWIZDROPINFO *ppwdi = (PUBWIZDROPINFO*)LocalAlloc(LPTR, sizeof(PUBWIZDROPINFO));
if (ppwdi)
{
ppwdi->clsidWizard = _clsidWizard;
// lets get the IFolderView object and marshall it for the bg thread
IFolderView *pfv;
if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IFolderView, &pfv))))
{
CoMarshalInterThreadInterfaceInStream(IID_IFolderView, pfv, &ppwdi->pstrmView);
pfv->Release();
}
hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pdtobj, &ppwdi->pstrmDataObj);
if (SUCCEEDED(hr))
{
hr = SHCreateThread(s_PublishThreadProc, ppwdi, CTF_THREAD_REF|CTF_COINIT, NULL) ? S_OK:E_FAIL;
}
if (FAILED(hr))
{
s_FreePubWizDropInfo(ppwdi);
}
}
return hr;
}
// create instance
STDAPI CPublishDropTarget_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CPubDropTarget *pwiz = new CPubDropTarget(*poi->pclsid, NULL);
if (!pwiz)
{
*ppunk = NULL; // incase of failure
return E_OUTOFMEMORY;
}
HRESULT hr = pwiz->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
pwiz->Release();
return hr;
}
// invoke the publishing wizard to point at a particular directory
void APIENTRY PublishRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
{
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
CLSID clsid = CLSID_PublishDropTarget;
UINT csidl = CSIDL_PERSONAL;
if (0 == StrCmpIA(pszCmdLine, "/print"))
{
clsid = CLSID_InternetPrintOrdering;
csidl = CSIDL_MYPICTURES;
}
LPITEMIDLIST pidl;
hr = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
if (SUCCEEDED(hr))
{
LPCITEMIDLIST pidlChild;
IShellFolder *psf;
hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
if (SUCCEEDED(hr))
{
IDataObject *pdo;
hr = psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_X_PPV_ARG(IDataObject, NULL, &pdo));
if (SUCCEEDED(hr))
{
CPubDropTarget *pdt = new CPubDropTarget(clsid, NULL);
if (pdt)
{
pdt->_Publish(pdo);
pdt->Release();
}
pdo->Release();
}
psf->Release();
}
ILFree(pidl);
}
CoUninitialize();
}
}