#include "priv.h" #include #include #include "hlframe.h" #include "shldisp.h" #include "opsprof.h" #include "resource.h" #include #include "htmlstr.h" #include "mypics.h" #include "mshtmcid.h" #include "util.h" #include "winuser.h" ////////////////////////////////////////////////////////////////////////////////// // // filename: mypics.cpp // // description: implements the my pictures exposure hoverbar thingie // // notes: lots of stuff is stolen from iforms.cpp and iformsp.h // // history: 06.15.2000 created by t-jdavis // ////////////////////////////////////////////////////////////////////////////////// extern HINSTANCE g_hinst; #define TF_MYPICS TF_CUSTOM2 // we don't actually use all of these, but we COULD, you know, if we wanted too. CMyPicsEventSinkCallback::EventSinkEntry CMyPicsEventSinkCallback::EventsToSink[] = { { EVENT_MOUSEOVER, L"onmouseover", L"mouseover" }, { EVENT_MOUSEOUT, L"onmouseout", L"mouseout" }, { EVENT_SCROLL, L"onscroll", L"scroll" }, { EVENT_RESIZE, L"onresize", L"resize" } }; // image toolbar states enum { HOVERSTATE_HIDING = 0, HOVERSTATE_SHOWING, HOVERSTATE_LOCKED, HOVERSTATE_SCROLLING, HOVERSTATE_WAITINGTOSHOW }; // // CMyPics // // set some stuff CMyPics::CMyPics() { TraceMsg(TF_MYPICS, "+CMyPics::CMyPics"); m_Hwnd = NULL; m_hWndMyPicsToolBar = NULL; m_hWndHover = NULL; m_pEleCurr = NULL; m_pSink = NULL; m_bIsOffForSession = FALSE; m_cRef = 1; m_bGalleryMeta = TRUE; TraceMsg(TF_MYPICS, "-CMyPics::CMyPics"); } // destroy whatever needs destroying.... CMyPics::~CMyPics() { TraceMsg(TF_MYPICS, "+CMyPics::~CMyPics"); DestroyHover(); ATOMICRELEASE(m_pEleCurr); if (m_hWndMyPicsToolBar) DestroyWindow(m_hWndMyPicsToolBar); if (m_hWndHover) { SetWindowPtr(m_hWndHover, GWLP_USERDATA, NULL); DestroyWindow(m_hWndHover); } TraceMsg(TF_MYPICS, "-CMyPics::~CMyPics"); } // did the user turn this feature off? BOOL CMyPics::IsOff() { return (m_bIsOffForSession); } void CMyPics::IsGalleryMeta(BOOL bFlag) { m_bGalleryMeta = bFlag; } HRESULT CMyPics::Init(IHTMLDocument2 *pDoc2) { HRESULT hr = S_OK; TraceMsg(TF_MYPICS, "+CMyPics::Init"); ASSERT(pDoc2); //sink things IHTMLElement2 *pEle2 = NULL; IHTMLElementCollection *pCollect = NULL; IHTMLElementCollection *pSubCollect = NULL; IDispatch *pDisp = NULL; VARIANT TagName; ULONG ulCount = 0; VARIANTARG va1; VARIANTARG va2; IHTMLWindow3 *pWin3 = NULL; // ...remember this... m_pDoc2 = pDoc2; pDoc2->AddRef(); // setup variant for finding all the IMG tags... TagName.vt = VT_BSTR; TagName.bstrVal = (BSTR)c_bstr_IMG; //get all tags hr = pDoc2->get_all(&pCollect); if (FAILED(hr)) goto Cleanup; //get all IMG tags hr = pCollect->tags(TagName, &pDisp); if (FAILED(hr)) goto Cleanup; if (pDisp) { hr = pDisp->QueryInterface(IID_IHTMLElementCollection,(void **)&pSubCollect); ATOMICRELEASE(pDisp); } if (FAILED(hr)) goto Cleanup; //get IMG tag count hr = pSubCollect->get_length((LONG *)&ulCount); if (FAILED(hr)) goto Cleanup; va1.vt = VT_I4; va2.vt = VT_EMPTY; //iterate through tags sinking events to elements for (int i=0; i<(LONG)ulCount; i++) { pDisp = NULL; va1.lVal = (LONG)i; pSubCollect->item(va1, va2, &pDisp); // only create a new CEventSink once if (!m_pSink && pDisp) m_pSink = new CEventSink(this); if (pDisp) { hr = pDisp->QueryInterface(IID_IHTMLElement2, (void **)&pEle2); if (FAILED(hr)) goto Cleanup; ASSERT(m_pSink); if (m_pSink && pEle2) { EVENTS events[] = { EVENT_MOUSEOVER, EVENT_MOUSEOUT, EVENT_RESIZE }; m_pSink->SinkEvents(pEle2, ARRAYSIZE(events), events); } ATOMICRELEASE(pEle2); ATOMICRELEASE(pDisp); } } // sink scroll event from the window, because it doesn't come from elements. if (m_pSink) { Win3FromDoc2(m_pDoc2, &pWin3); if (pWin3) { m_pWin3 = pWin3; m_pWin3->AddRef(); EVENTS eventScroll[] = { EVENT_SCROLL }; m_pSink->SinkEvents(pWin3, ARRAYSIZE(eventScroll), eventScroll); } } //end sinking things Cleanup: ATOMICRELEASE(pCollect); ATOMICRELEASE(pSubCollect); ATOMICRELEASE(pWin3); ATOMICRELEASE(pDisp); ATOMICRELEASE(pEle2); TraceMsg(TF_MYPICS, "-CMyPics::Init"); return hr; } HRESULT CMyPics::UnInit() { // Unhook regular event sink TraceMsg(TF_MYPICS, "+CMyPics::UnInit"); if (m_pSink) { if (m_pWin3) { EVENTS events[] = { EVENT_SCROLL }; m_pSink->UnSinkEvents(m_pWin3, ARRAYSIZE(events), events); SAFERELEASE(m_pWin3); } m_pSink->SetParent(NULL); ATOMICRELEASE(m_pSink); } SAFERELEASE(m_pEleCurr); SAFERELEASE(m_pDoc2); TraceMsg(TF_MYPICS, "-CMyPics::UnInit"); return S_OK; } ULONG CMyPics::AddRef(void) { return ++m_cRef; } ULONG CMyPics::Release(void) { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; } // has this been disabled by some administrator or something via IEAK? BOOL MP_IsEnabledInIEAK() { DWORD dwType = REG_DWORD; DWORD dwSize; DWORD dwEnabled; // dsheldon - should this var be called dwDisabled since we say (dwEnabled != 1) == enabled? DWORD dwRet; const TCHAR c_szSPMIEPS[] = TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\PhotoSupport"); const TCHAR c_szVal[] = TEXT("MyPics_Hoverbar"); dwSize = sizeof(dwEnabled); dwRet = SHGetValue(HKEY_CURRENT_USER, c_szSPMIEPS, c_szVal, &dwType, &dwEnabled, &dwSize); if ((dwType == REG_DWORD) && (dwRet == ERROR_SUCCESS)) { if (dwEnabled!=1) return TRUE; // enabled else return FALSE; // disabled } // value not found... return TRUE; } // has the user explicitly disabled this feature for now and all time via intern control panel? BOOL MP_IsEnabledInRegistry() { DWORD dwType = REG_SZ; DWORD dwSize; TCHAR szEnabled[16]; DWORD dwRet; const TCHAR c_szSMIEM[] = TEXT("Software\\Microsoft\\Internet Explorer\\Main"); const TCHAR c_szVal[] = TEXT("Enable_MyPics_Hoverbar"); dwSize = sizeof(szEnabled); dwRet = SHGetValue(HKEY_CURRENT_USER, c_szSMIEM, c_szVal, &dwType, szEnabled, &dwSize); if (dwRet == ERROR_INSUFFICIENT_BUFFER) { ASSERT(dwRet == ERROR_SUCCESS); // this is wacky... return FALSE; } if ((dwType == REG_SZ) && (dwRet == ERROR_SUCCESS)) { if (!StrCmp(szEnabled, TEXT("yes"))) return TRUE; // enabled else return FALSE; // disabled } // value not found... return TRUE; } DWORD MP_GetFilterInfoFromRegistry() { const TCHAR c_szSMIEAOMM[] = TEXT("Software\\Microsoft\\Internet Explorer\\Main"); const TCHAR c_szVal[] = TEXT("Image_Filter"); DWORD dwType, dwSize, dwFilter, dwRet; dwSize = sizeof(dwFilter); dwRet = SHGetValue(HKEY_CURRENT_USER, c_szSMIEAOMM, c_szVal, &dwType, &dwFilter, &dwSize); if ((dwRet != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwFilter = MP_MIN_SIZE; } return dwFilter; } DWORD MP_GetOffsetInfoFromRegistry() { const TCHAR c_szSMIEAOMM[] = TEXT("Software\\Microsoft\\Internet Explorer\\Main"); const TCHAR c_szVal[] = TEXT("Offset"); DWORD dwType, dwSize, dwOffset, dwRet; dwSize = sizeof(dwOffset); dwRet = SHGetValue(HKEY_CURRENT_USER, c_szSMIEAOMM, c_szVal, &dwType, &dwOffset, &dwSize); if ((dwRet != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwOffset = MP_HOVER_OFFSET; } return dwOffset; } BOOL_PTR CALLBACK DisableMPDialogProc(HWND hDlg, UINT uMsg, WPARAM wparam, LPARAM lparam) { BOOL bMsgHandled = FALSE; switch (uMsg) { case WM_INITDIALOG: { // center dialog... yay msdn... RECT rc; GetWindowRect(hDlg, &rc); SetWindowPos(hDlg, HWND_TOP, ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2), ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2), 0, 0, SWP_NOSIZE); } break; case WM_COMMAND: switch (LOWORD(wparam)) { case IDC_MP_ALWAYS: EndDialog(hDlg, IDC_MP_ALWAYS); break; case IDC_MP_THISSESSION: EndDialog(hDlg, IDC_MP_THISSESSION); break; case IDC_MP_CANCEL: EndDialog(hDlg, IDC_MP_CANCEL); break; } break; case WM_CLOSE: EndDialog(hDlg, IDC_MP_CANCEL); break; default: break; } return(bMsgHandled); } LRESULT CALLBACK CMyPics::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMyPics* pThis = (CMyPics*)GetWindowPtr(hWnd, GWLP_USERDATA); TraceMsg(TF_MYPICS, "+CMyPics::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis); HRESULT hr = S_OK; IOleCommandTarget *pOleCommandTarget = NULL; switch (uMsg) { case WM_SIZE: if (!pThis) break; SetWindowPos(pThis->m_hWndMyPicsToolBar, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); break; case WM_ERASEBKGND: if (!pThis) break; { RECT rc; HBRUSH hb = GetSysColorBrush(COLOR_3DFACE); GetClientRect(pThis->m_hWndMyPicsToolBar, &rc); FillRect((HDC)wParam, &rc, hb); return TRUE; } case WM_COMMAND: if (!pThis) break; switch(LOWORD(wParam)) { case IDM_MYPICS_SAVE: //Save As... dialogue ASSERT(pThis->m_pEleCurr); // the evil QI call... hr = pThis->m_pEleCurr->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget); if (FAILED(hr)) return(hr); // hide the hoverthing so it doesn't cause us any nasty problems pThis->HideHover(); // launch the Save As dialogue thingie... pOleCommandTarget->Exec(&CGID_MSHTML, IDM_SAVEPICTURE, 0, 0, NULL); ATOMICRELEASE(pOleCommandTarget); break; case IDM_MYPICS_PRINT: { // get the cmd target hr = pThis->m_pEleCurr->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget); if (FAILED(hr)) return(hr); pThis->HideHover(); //pThis->m_hoverState = HOVERSTATE_SHOWING; // kludge to keep hover from appearing under print dialogue pOleCommandTarget->Exec(&CGID_MSHTML, IDM_MP_PRINTPICTURE, 0, 0, NULL); ATOMICRELEASE(pOleCommandTarget); //pThis->m_hoverState = HOVERSTATE_HIDING; } break; case IDM_MYPICS_EMAIL: { // get the cmd target... hr = pThis->m_pEleCurr->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget); if (FAILED(hr)) return(hr); // ... and then hide the hover bar... pThis->HideHover(); //pThis->m_hoverState = HOVERSTATE_SHOWING; // kludge to keep hover from appearing under print dialogue // ... and pray this works... pOleCommandTarget->Exec(&CGID_MSHTML, IDM_MP_EMAILPICTURE, 0, 0, NULL); ATOMICRELEASE(pOleCommandTarget); // ... and cleanup //pThis->m_hoverState = HOVERSTATE_HIDING; } break; case IDM_MYPICS_MYPICS: // Open My Pictures folder // get the cmd target hr = pThis->m_pEleCurr->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget); if (FAILED(hr)) return(hr); pOleCommandTarget->Exec(&CGID_MSHTML, IDM_MP_MYPICS, 0, 0, NULL); ATOMICRELEASE(pOleCommandTarget); hr = S_OK; pThis->HideHover(); break; default: break; } break; case WM_NOTIFY: // tooltips... if (!pThis) break; switch (((LPNMHDR)lParam)->code) { case TTN_NEEDTEXT: { LPTOOLTIPTEXT lpToolTipText; TCHAR szBuf[MAX_PATH]; lpToolTipText = (LPTOOLTIPTEXT)lParam; hr = MLLoadString((UINT)lpToolTipText->hdr.idFrom, szBuf, ARRAYSIZE(szBuf)); lpToolTipText->lpszText = szBuf; break; } } break; case WM_SETTINGCHANGE: if (!pThis) break; { pThis->DestroyHover(); // to stop wierd window distortion break; } case WM_CONTEXTMENU: if (!pThis) break; { // load the menu HMENU hMenu0 = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(IDR_MYPICS_CONTEXT_MENU)); HMENU hMenu1 = GetSubMenu(hMenu0, 0); if(!hMenu1) break; POINT point; point.x = (LONG)GET_X_LPARAM(lParam); point.y = (LONG)GET_Y_LPARAM(lParam); ASSERT(pThis->m_hoverState=HOVERSTATE_SHOWING); // lock against mouseouts pThis->m_hoverState = HOVERSTATE_LOCKED; // display it, get choice (if any) int iPick = TrackPopupMenu(hMenu1, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, 0, hWnd, (RECT *)NULL); DestroyMenu(hMenu0); DestroyMenu(hMenu1); pThis->m_hoverState = HOVERSTATE_SHOWING; if (iPick) { switch(iPick) { case IDM_DISABLE_MYPICS: { pThis->HideHover(); // create dialog to ask user if they want to turn this stuff off... // (explicit cast to make Win64 builds happy) int iResult = (int)DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_DISABLE_MYPICS), pThis->m_Hwnd, DisableMPDialogProc, NULL); // deal with their choice... if (iResult) { switch (iResult) { case IDC_MP_ALWAYS: { pThis->m_bIsOffForSession = TRUE; DWORD dwType = REG_SZ; DWORD dwSize; TCHAR szEnabled[16] = TEXT("no"); DWORD dwRet; const TCHAR c_szSMIEM[] = TEXT("Software\\Microsoft\\Internet Explorer\\Main"); const TCHAR c_szVal[] = TEXT("Enable_MyPics_Hoverbar"); dwSize = sizeof(szEnabled); dwRet = SHSetValue(HKEY_CURRENT_USER, c_szSMIEM, c_szVal, dwType, szEnabled, dwSize); } break; case IDC_MP_THISSESSION: // twiddle member var flag // this is propagated back up to COmWindow via ReleaseMyPics() function. pThis->m_bIsOffForSession = TRUE; break; default: break; } } } break; case IDM_HELP_MYPICS: pThis->HideHover(); SHHtmlHelpOnDemandWrap(hWnd, TEXT("iexplore.chm > iedefault"), 0, (DWORD_PTR) TEXT("pic_tb_ovr.htm"), ML_CROSSCODEPAGE); break; default: // um, do nothing break; } } } break; default: return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } TraceMsg(TF_MYPICS, "-CMyPics::s_WndProc hWnd=%x, pThis=%p", hWnd, pThis); return (hr); } VOID CALLBACK CMyPics::s_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { TraceMsg(TF_MYPICS, "+CMyPics::TimerProc"); CMyPics* pThis = (CMyPics*)GetWindowPtr(hwnd, GWLP_USERDATA); switch (uMsg) { case WM_TIMER: KillTimer(hwnd, IDT_MP_TIMER); if (pThis && (pThis->m_hoverState == HOVERSTATE_WAITINGTOSHOW)) { // Our hover bar is waiting to be shown. if (pThis->m_pEleCurr) { // We still have an element. Show it. pThis->m_hoverState = HOVERSTATE_SHOWING; pThis->ShowHover(); } else { // Our timer popped, but we don't have an element. pThis->HideHover(); } } break; default: break; } TraceMsg(TF_MYPICS, "-CMyPics::TimerProc"); } BOOL CMyPics::ShouldAppearOnThisElement(IHTMLElement *pEle) { BOOL bRet = TRUE; // appear by default VARIANT varVal = {0}; BSTR bstrAttribute = NULL; // to check img tags for expando IHTMLRect *pRect = NULL; // to get screen coords IHTMLElement2 *pEle2 = NULL; IHTMLElement3 *pEle3 = NULL; // to check for contenteditable mode VARIANT_BOOL bEdit = FALSE;// becomes true if contenteditable mode is true LONG lLeft; // these are the screen coords LONG lRight; // we get right and bottom to det size of image LONG lTop; LONG lBottom; DWORD dwFilter; IOleCommandTarget *pOleCommandTarget = NULL; TraceMsg(TF_MYPICS, "+CMyPics::ShouldAppearOnThisElement"); // don't create it if it already exists. thats bad. if ((HOVERSTATE_SHOWING == m_hoverState) || (HOVERSTATE_LOCKED == m_hoverState)) { bRet = FALSE; goto Cleanup; } m_bGalleryImg = FALSE; if (!pEle) { bRet = FALSE; goto Cleanup; } // find out if the image didn't load or is unrenderable if (SUCCEEDED(pEle->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget))) { OLECMD rgCmd; rgCmd.cmdID = IDM_SAVEPICTURE; // this is the same check the context menu uses rgCmd.cmdf = 0; pOleCommandTarget->QueryStatus(&CGID_MSHTML, 1, &rgCmd, NULL); if (!(OLECMDF_ENABLED & rgCmd.cmdf)) { bRet = FALSE; goto Cleanup; } } // check for explicit enable/disable attribute in img tag... bstrAttribute=SysAllocString(L"galleryimg"); if (!bstrAttribute) goto Cleanup; if (SUCCEEDED(pEle->getAttribute(bstrAttribute, 0, &varVal))) { if (varVal.vt == VT_BSTR) { if (StrCmpIW(varVal.bstrVal, L"true") == 0 || StrCmpIW(varVal.bstrVal, L"on") == 0 || StrCmpIW(varVal.bstrVal, L"yes") == 0 ) { // Explicitly turned on. Honor it and leave. bRet = TRUE; m_bGalleryImg = TRUE; goto Cleanup; } if (StrCmpIW(varVal.bstrVal, L"false") == 0 || StrCmpIW(varVal.bstrVal, L"off") == 0 || StrCmpIW(varVal.bstrVal, L"no") == 0 ) { // Explicitly turned off. Honor it and leave. bRet = FALSE; goto Cleanup; } } else if (varVal.vt == VT_BOOL) { if (varVal.boolVal == VARIANT_TRUE) { bRet = TRUE; m_bGalleryImg = TRUE; goto Cleanup; } else { bRet = FALSE; goto Cleanup; } } } VariantClear(&varVal); SysFreeString(bstrAttribute); // After checking "galleryimg" tag, check to see if turned off by the META tag if (m_bGalleryMeta == FALSE) return FALSE; // check for mappings on the image... bstrAttribute=SysAllocString(L"usemap"); if (!bstrAttribute) return (bRet); if (SUCCEEDED(pEle->getAttribute(bstrAttribute, 0, &varVal))) { if (varVal.vt == VT_BSTR) { // What do we do here? bRet = (varVal.bstrVal == NULL); if (!bRet) goto Cleanup; } } VariantClear(&varVal); SysFreeString(bstrAttribute); // check for mappings on the image... bstrAttribute=SysAllocString(L"ismap"); if (!bstrAttribute) return (bRet); if (SUCCEEDED(pEle->getAttribute(bstrAttribute, 0, &varVal))) { // If the attribute exists, then we need to return FALSE *unless* we see a value of FALSE bRet = FALSE; if (varVal.vt == VT_BOOL && varVal.boolVal == VARIANT_FALSE) { // "ismap" is false, so we can show the hover bar over this image. bRet = TRUE; } } if (!bRet) goto Cleanup; bRet = FALSE; // If any of the calls below fail, we'll exit with "FALSE". // Now check to see if we pass the size filter. // get an IHTMLElement2 from the IHTMLElement passed in... if (FAILED(pEle->QueryInterface(IID_IHTMLElement2, (void **)&pEle2) )) goto Cleanup; // get coords... if (FAILED(pEle2->getBoundingClientRect(&pRect) )) goto Cleanup; if (FAILED(pRect->get_left(&lLeft) )) goto Cleanup; if (FAILED(pRect->get_right(&lRight) )) goto Cleanup; if (FAILED(pRect->get_top(&lTop) )) goto Cleanup; if (FAILED(pRect->get_bottom(&lBottom) )) goto Cleanup; dwFilter = MP_GetFilterInfoFromRegistry(); // see if this picture is big enough to qualify as a "Photo"... // TODO: decide if we like checking aspect ratio or not if ( (lRight - lLeft >= (LONG)dwFilter && lBottom - lTop >= (LONG)dwFilter) /*&& !(2*(min(lRight-lLeft,lBottom-lTop)) < max(lRight-lLeft,lBottom-lTop)) */) bRet = TRUE; if (FAILED(pEle2->QueryInterface(IID_IHTMLElement3, (void **)&pEle3) )) goto Cleanup; if (FAILED(pEle3->get_isContentEditable(&bEdit) )) goto Cleanup; if (bEdit) bRet = FALSE; Cleanup: VariantClear(&varVal); if (bstrAttribute) SysFreeString(bstrAttribute); SAFERELEASE(pOleCommandTarget); SAFERELEASE(pEle3); SAFERELEASE(pRect); SAFERELEASE(pEle2); TraceMsg(TF_MYPICS, "-CMyPics::ShouldAppearOnThisElement"); return bRet; } HRESULT CMyPics::CreateHover() { HRESULT hr = S_OK; SIZE size = {0,0}; WORD wImage; HBITMAP hbmp = NULL; HBITMAP hbmpHot = NULL; TraceMsg(TF_MYPICS, "+CMyPics::CreateHover, this=%p, m_hoverState=%d", this, m_hoverState); InitCommonControls(); WNDCLASS wc = {0}; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpszClassName = TEXT("MyPicturesHost"); wc.lpfnWndProc = s_WndProc; wc.hInstance = g_hinst; wc.hbrBackground = HBRUSH(COLOR_BTNFACE); RegisterClass(&wc); // create the rebar to hold the toolbar... if (!m_hWndHover) { m_hWndHover = CreateWindow(TEXT("MyPicturesHost"), TEXT(""), WS_DLGFRAME | WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, m_Hwnd, NULL, g_hinst, NULL); if (!m_hWndHover) { TraceMsg(TF_MYPICS | TF_WARNING, "CMyPics::CreateHover, unable to create m_hWndHover"); hr = E_FAIL; goto Cleanup; } ASSERT(GetWindowPtr(m_hWndHover, GWLP_USERDATA) == NULL); SetWindowPtr(m_hWndHover, GWLP_USERDATA, this); // set cc version SendMessage(m_hWndHover, CCM_SETVERSION, COMCTL32_VERSION, 0); } // create the toolbar... if (!m_hWndMyPicsToolBar) { m_hWndMyPicsToolBar = CreateWindow(TOOLBARCLASSNAME, TEXT(""), TBSTYLE_TOOLTIPS | CCS_NODIVIDER | TBSTYLE_FLAT | WS_VISIBLE | WS_CHILD, 0,0,0,0, m_hWndHover, NULL, g_hinst, NULL); if (!m_hWndMyPicsToolBar) { TraceMsg(TF_MYPICS | TF_WARNING, "CMyPics::CreateHover, unable to create m_hWndMyPicsToolBar"); hr = E_FAIL; goto Cleanup; } SetWindowPtr(m_hWndMyPicsToolBar, GWLP_USERDATA, this); // for the timer proc // set cc version for this too, and the sizeof tbbutton struct... SendMessage(m_hWndMyPicsToolBar, CCM_SETVERSION, COMCTL32_VERSION, 0); SendMessage(m_hWndMyPicsToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); } // create image lists... wImage = ((IsOS(OS_WHISTLERORGREATER)) ? IDB_MYPICS_TOOLBARGW : IDB_MYPICS_TOOLBARG); if (!m_himlHover) { m_himlHover = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(wImage), 16, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION); if (!m_himlHover) { TraceMsg(TF_MYPICS | TF_WARNING, "CMyPics::CreateHover, unable to create m_himlHover"); } } wImage = ((IsOS(OS_WHISTLERORGREATER)) ? IDB_MYPICS_TOOLBARW : IDB_MYPICS_TOOLBAR); if (!m_himlHoverHot) { m_himlHoverHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(wImage) , 16, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION); if (!m_himlHoverHot) { TraceMsg(TF_MYPICS | TF_WARNING, "CMyPics::CreateHover, unable to create m_himlHoverHot"); } } // set image list and hot image list SendMessage(m_hWndMyPicsToolBar, TB_SETIMAGELIST, 0, (LPARAM)m_himlHover ); SendMessage(m_hWndMyPicsToolBar, TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlHoverHot); TBBUTTON tbButton; // set bitmap indexes in tbbutton structure (this may not be necessary) for (int i=0;iget_offsetParent(&pEleParent))) { // get the map element hr=pEleParent->QueryInterface(IID_IHTMLMapElement, (void **)&pEleMap); if (FAILED(hr)) goto Cleanup; // next get the name of the map if (SUCCEEDED(pEleMap->get_name(&bstrName))) { //next get all tags hr = m_pDoc2->get_all(&pCollect); if (FAILED(hr)) goto Cleanup; //get all IMG tags hr = pCollect->tags(TagName, &pDisp); if (FAILED(hr)) goto Cleanup; if (pDisp) { hr = pDisp->QueryInterface(IID_IHTMLElementCollection,(void **)&pSubCollect); ATOMICRELEASE(pDisp); } if (FAILED(hr)) goto Cleanup; //get IMG tag count hr = pSubCollect->get_length((LONG *)&ulCount); if (FAILED(hr)) goto Cleanup; va1.vt = VT_I4; va2.vt = VT_EMPTY; ASSERT(pDisp==NULL); //iterate through tags looking for images that have the right usemap set for (int i=0; i<(LONG)ulCount; i++) { ATOMICRELEASE(pEleImg); ATOMICRELEASE(pDisp); pDisp = NULL; bstrUseMap = NULL; xInIMG = 0; yInIMG = 0; lOffset = 0; lOffsetLeft = 0; lOffsetTop = 0; lScrollLeft = 0; lScrollTop = 0; lOffsetW = 0; lOffsetH = 0; va1.lVal = (LONG)i; pSubCollect->item(va1, va2, &pDisp); if (pDisp) { hr = pDisp->QueryInterface(IID_IHTMLImgElement, (void **)&pEleImg); if (FAILED(hr)) goto Cleanup; hr = pEleImg->get_useMap(&bstrUseMap); if (FAILED(hr)) goto Cleanup; // this will be non-null if set for this IMG element... if (bstrUseMap){ // skip the prepended '#' and see if this is what we're looking for... if (StrCmp(bstrUseMap + 1, bstrName) == 0) { m_pWin3->get_screenLeft(&ptScr.x); m_pWin3->get_screenTop (&ptScr.y); //Ok, we found a candidate. See if the mouse is here... ptMouse.x = ptEvent.x - ptScr.x; ptMouse.y = ptEvent.y - ptScr.y; hr = pDisp->QueryInterface(IID_IHTMLElement, (void **)&pEleMisc); if (FAILED(hr)) goto Cleanup; while (pEleMisc) { hr = pEleMisc->QueryInterface(IID_IHTMLElement2, (void **)&pEle2Misc); if (FAILED(hr)) goto Cleanup; pEleMisc->get_offsetLeft(&lOffsetLeft); pEle2Misc->get_scrollLeft(&lScrollLeft); lOffset += lOffsetLeft - lScrollLeft; pEleMisc->get_offsetParent(&pEleMiscPar); ATOMICRELEASE(pEleMisc); ATOMICRELEASE(pEle2Misc); pEleMisc=pEleMiscPar; } ATOMICRELEASE(pEleMiscPar); hr = pDisp->QueryInterface(IID_IHTMLElement, (void **)&pEleMisc); if (FAILED(hr)) goto Cleanup; xInIMG = ptMouse.x - lOffset; pEleMisc->get_offsetWidth(&lOffsetW); if ((xInIMG < 0) || (xInIMG > lOffsetW)) continue; lOffset = 0; while (pEleMisc) { hr = pEleMisc->QueryInterface(IID_IHTMLElement2, (void **)&pEle2Misc); if (FAILED(hr)) goto Cleanup; pEleMisc->get_offsetTop(&lOffsetTop); pEle2Misc->get_scrollTop(&lScrollTop); lOffset += lOffsetTop - lScrollTop; pEleMisc->get_offsetParent(&pEleMiscPar); ATOMICRELEASE(pEleMisc); ATOMICRELEASE(pEle2Misc); pEleMisc=pEleMiscPar; } ATOMICRELEASE(pEleMiscPar); hr = pDisp->QueryInterface(IID_IHTMLElement, (void **)&pEleMisc); if (FAILED(hr)) goto Cleanup; yInIMG = ptMouse.y - lOffset; pEleMisc->get_offsetHeight(&lOffsetH); ATOMICRELEASE(pEleMisc); if ((yInIMG < 0) || (yInIMG > lOffsetH)) continue; // if we get to this point we found our IMG element so... // ...do the QI... pEleImg->QueryInterface(IID_IHTMLElement, (void **)&pEleOut); // ...and we're done. break; } SysFreeString(bstrUseMap); bstrUseMap = NULL; } } } } } Cleanup: ATOMICRELEASE(pCollect); ATOMICRELEASE(pSubCollect); ATOMICRELEASE(pEleMap); ATOMICRELEASE(pEleParent); ATOMICRELEASE(pDisp); ATOMICRELEASE(pEleImg); ATOMICRELEASE(pEleMisc); ATOMICRELEASE(pEle2Misc); ATOMICRELEASE(pEleMiscPar); SysFreeString(bstrUseMap); SysFreeString(bstrName); return (pEleOut); } // sometimes coordinates are relative to a parent object, like in frames, etc. so this gets their real position relative // to the browser window... HRESULT CMyPics::GetRealCoords(IHTMLElement2 *pEle2, HWND hwnd, LONG *plLeft, LONG *plTop, LONG *plRight, LONG *plBottom) { LONG lScreenLeft = 0, lScreenTop = 0; HRESULT hr = E_FAIL; IHTMLRect *pRect = NULL; *plLeft = *plTop = *plRight = *plBottom = 0; if (!pEle2) return hr; if (SUCCEEDED(pEle2->getBoundingClientRect(&pRect)) && pRect) { LONG lLeft, lRight, lTop, lBottom; pRect->get_left(&lLeft); pRect->get_right(&lRight); pRect->get_top(&lTop); pRect->get_bottom(&lBottom); // if its an iframe and it scrolls past the top of the frame, we should correct a bit. if (lTop <= 0) lTop = 0; // dito for left side if (lLeft <= 0) lLeft = 0; POINT pointTL, pointBR; // TL=Top,Left BR=Bottom,Right ASSERT(m_pWin3); m_pWin3->get_screenLeft(&lScreenLeft); m_pWin3->get_screenTop(&lScreenTop); // convert coords relative to the frame window to screen coords pointTL.x = lScreenLeft + lLeft; pointTL.y = lScreenTop + lTop; pointBR.x = lScreenLeft + lRight; pointBR.y = lScreenTop + lBottom; // now convert from screen coords to client coords and assign... if (ScreenToClient(hwnd, &pointTL) && ScreenToClient(hwnd, &pointBR)) { *plLeft = pointTL.x; *plRight = pointBR.x; *plTop = pointTL.y; *plBottom = pointBR.y; hr = S_OK; } pRect->Release(); } return hr; } HRESULT CMyPics::ShowHover() { HRESULT hr = S_OK; IHTMLElement2 *pEle2 = NULL; // cause we need an ele2 to get screen coords IHTMLRect *pRect = NULL; // to get screen coords LONG lLeft; // these are the screen coords LONG lRight; // we get right and bottom to det size of image LONG lTop; LONG lBottom; DWORD dwOffset; DWORD dw; SIZE sz; RECT rc; TraceMsg(TF_MYPICS, "+CMyPics::ShowHover, this=%p, m_hoverState=%d", this, m_hoverState); ASSERT(m_pEleCurr); ASSERT(m_Hwnd); // get an IHTMLElement2 from the IHTMLElement cached... hr = m_pEleCurr->QueryInterface(IID_IHTMLElement2, (void **)&pEle2); if (FAILED(hr)) goto Cleanup; // get correct coords... hr = GetRealCoords(pEle2, m_Hwnd, &lLeft, &lTop, &lRight, &lBottom); if (FAILED(hr)) goto Cleanup; // adjust for offset... dwOffset = MP_GetOffsetInfoFromRegistry(); lLeft += dwOffset; lTop += dwOffset; // need to do some sanity checks to make sure the hover bar appears in a visible location... RECT rcBrowserWnd; if (GetClientRect(m_Hwnd, &rcBrowserWnd)) { // check to make sure it'll appear somewhere we'll see it... if (lLeft < rcBrowserWnd.left) lLeft = rcBrowserWnd.left + dwOffset; if (lTop < rcBrowserWnd.top) lTop = rcBrowserWnd.top + dwOffset; // check to make sure the entire hoverbar is over the image (so the user // doesn't mouseout trying to get to the buttons!) // If "galleryimg" was explicitly turned on, then bypass this code, which ensures that the entire // toolbar will fit within the image. if (!m_bGalleryImg) { if (lRight - lLeft < MP_MIN_CX + 10 - (LONG)dwOffset) goto Cleanup; if (lBottom - lTop < MP_MIN_CY + 10) goto Cleanup; // now check to make sure there is enough horiz and vert room for it to appear... // if there isn't enough room, we just don't display it... if ((rcBrowserWnd.right - MP_SCROLLBAR_SIZE) - lLeft < MP_MIN_CX) goto Cleanup; if ((rcBrowserWnd.bottom - (MP_SCROLLBAR_SIZE+2)) - lTop < MP_MIN_CY) goto Cleanup; } } dw = (DWORD)SendMessage(m_hWndMyPicsToolBar, TB_GETBUTTONSIZE, 0, 0); sz.cx = LOWORD(dw); sz.cy = HIWORD(dw); rc.left = rc.top = 0; SendMessage(m_hWndMyPicsToolBar, TB_GETIDEALSIZE, FALSE, (LPARAM)&sz); rc.right = sz.cx; rc.bottom = sz.cy; AdjustWindowRectEx(&rc, GetWindowLong(m_hWndHover, GWL_STYLE), FALSE, GetWindowLong(m_hWndHover, GWL_EXSTYLE)); if (SetWindowPos(m_hWndHover, NULL, lLeft, lTop, rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER | SWP_SHOWWINDOW)) { m_hoverState = HOVERSTATE_SHOWING; } Cleanup: ATOMICRELEASE(pRect); ATOMICRELEASE(pEle2); TraceMsg(TF_MYPICS, "-CMyPics::ShowHover, this=%p, m_hoverState=%d", this, m_hoverState); return hr; } HRESULT CMyPics::HandleScroll() { TraceMsg(TF_MYPICS, "+CMyPics::HandleScroll, this=%p, m_hoverState=%d", this, m_hoverState); HRESULT hr = S_OK; switch(m_hoverState) { // I don't think we need to do anything in these cases. // case HOVERSTATE_HIDING: case HOVERSTATE_LOCKED: case HOVERSTATE_WAITINGTOSHOW: break; case HOVERSTATE_SHOWING: { IHTMLElement2 *pEle2=NULL; IHTMLRect *pRect=NULL; RECT rect; ASSERT(m_pEleCurr); ASSERT(m_Hwnd); ASSERT(m_hWndHover); // Ensure we do have a window HideHover(); ShowHover(); // Redraw client area to get rid of window droppings scrolling causes. // Try to redraw just the part where its likely to need it. if (FAILED(m_pEleCurr->QueryInterface(IID_IHTMLElement2, (void **)&pEle2))) { goto CleanUp; } if (FAILED(pEle2->getBoundingClientRect(&pRect))) { goto CleanUp; } pRect->get_left(&rect.left); pRect->get_right(&rect.right); pRect->get_top(&rect.top); pRect->get_bottom(&rect.bottom); rect.top -= 2*MP_MIN_CY; if (rect.top < 0) rect.top = 0; rect.left -= 2*MP_MIN_CX; if (rect.left <0) rect.left = 0; rect.bottom *= 2; rect.right *= 2; RedrawWindow(m_Hwnd, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); CleanUp: SAFERELEASE(pRect); SAFERELEASE(pEle2); } break; } TraceMsg(TF_MYPICS, "-CMyPics::HandleScroll, this=%p, m_hoverState=%d", this, m_hoverState); return hr; } HRESULT CMyPics::HandleMouseover(IHTMLElement *pEle) { HRESULT hr = S_OK; IOleWindow *pOleWindow; TraceMsg(TF_MYPICS, "+CMyPics::HandleMouseover"); if (m_hoverState != HOVERSTATE_HIDING) { // Ensure we really have a hover window ASSERT(m_hWndHover); return (S_OK); } else { // No bar. Release current element, if any. ATOMICRELEASE(m_pEleCurr); if (ShouldAppearOnThisElement(pEle)) { m_pEleCurr = pEle; pEle->AddRef(); // set m_Hwnd once... if (!m_Hwnd) { // Get the Hwnd for the document... hr = m_pDoc2->QueryInterface(IID_IOleWindow,(void **)&pOleWindow); if (FAILED(hr)) return hr; pOleWindow->GetWindow(&m_Hwnd); pOleWindow->Release(); } if (!m_hWndHover) { // We need a hover window now to conveniently set a timer. hr = CreateHover(); // review: do we need to pass member variables as params? } // We're all set up. Set the state and start the timer. m_hoverState=HOVERSTATE_WAITINGTOSHOW; SetTimer(m_hWndMyPicsToolBar, IDT_MP_TIMER, MP_TIMER, s_TimerProc); } } TraceMsg(TF_MYPICS, "-CMyPics::HandleMouseover"); return hr; } HRESULT CMyPics::HandleMouseout() { TraceMsg(TF_MYPICS, "+CMyPics::HandleMouseout"); switch(m_hoverState) { case HOVERSTATE_HIDING: // Nothing to do break; case HOVERSTATE_SHOWING: // Hide it HideHover(); break; case HOVERSTATE_LOCKED: // Noop break; case HOVERSTATE_WAITINGTOSHOW: m_hoverState = HOVERSTATE_HIDING; KillTimer(m_hWndMyPicsToolBar, IDT_MP_TIMER); break; } TraceMsg(TF_MYPICS, "-CMyPics::HandleMouseout"); return S_OK; } HRESULT CMyPics::HandleResize() { HRESULT hr = S_OK; if (m_pEleCurr && (HOVERSTATE_SHOWING == m_hoverState)) { HideHover(); ShowHover(); } return hr; } HRESULT CMyPics::HandleEvent(IHTMLElement *pEle, EVENTS Event, IHTMLEventObj *pEventObj) { TraceMsg(TF_MYPICS, "CMyPics::HandleEvent Event=%ws", EventsToSink[Event].pwszEventName); HRESULT hr = S_OK; BSTR bstrTagName = NULL; IHTMLElement *pEleUse = NULL; BOOL fWasArea = FALSE; // if this is an area tag we need to find the IMG tag that corresponds if (pEle && SUCCEEDED(pEle->get_tagName(&bstrTagName))) { // if its an area tag, we need to find the img tag associated with it... if (StrCmpNI(bstrTagName, TEXT("area"), 4)==0) { POINT ptEvent; if (FAILED(pEventObj->get_screenX(&ptEvent.x)) || FAILED(pEventObj->get_screenY(&ptEvent.y))) { hr = E_FAIL; goto Cleanup; } fWasArea = TRUE; pEleUse = GetIMGFromArea(pEle, ptEvent); } } // has the user turned this off? if (m_bIsOffForSession) goto Cleanup; switch(Event) { case EVENT_SCROLL: HandleScroll(); break; case EVENT_MOUSEOVER: hr = HandleMouseover(fWasArea ? pEleUse : pEle); break; case EVENT_MOUSEOUT: hr = HandleMouseout(); break; case EVENT_RESIZE: hr = HandleResize(); break; default: //do nothing? break; } Cleanup: if (pEleUse) ATOMICRELEASE(pEleUse); if (bstrTagName) SysFreeString(bstrTagName); return (hr); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // this is stolen from iforms.cpp: //========================================================================= // // Event sinking class // // We simply implement IDispatch and make a call into our parent when // we receive a sinked event. // //========================================================================= CMyPics::CEventSink::CEventSink(CMyPicsEventSinkCallback *pParent) { TraceMsg(TF_MYPICS, "CMyPics::CEventSink::CEventSink"); DllAddRef(); m_cRef = 1; m_pParent = pParent; } CMyPics::CEventSink::~CEventSink() { TraceMsg(TF_MYPICS, "CMyPics::CEventSink::~CEventSink"); ASSERT( m_cRef == 0 ); DllRelease(); } STDMETHODIMP CMyPics::CEventSink::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL; if ((IID_IDispatch == riid) || (IID_IUnknown == riid)) { *ppv = (IDispatch *)this; } if (NULL != *ppv) { ((IUnknown *)*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CMyPics::CEventSink::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CMyPics::CEventSink::Release(void) { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; } HRESULT CMyPics::CEventSink::SinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents) { VARIANT_BOOL bSuccess = VARIANT_TRUE; for (int i=0; iattachEvent(bstrEvent, (IDispatch *)this, &bSuccess); SysFreeString(bstrEvent); } else { bSuccess = VARIANT_FALSE; } if (!bSuccess) break; } return (bSuccess) ? S_OK : E_FAIL; } HRESULT CMyPics::CEventSink::SinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents) { VARIANT_BOOL bSuccess = VARIANT_TRUE; for (int i=0; iattachEvent(bstrEvent, (IDispatch *)this, &bSuccess); SysFreeString(bstrEvent); } else { bSuccess = VARIANT_FALSE; } if (!bSuccess) break; } return (bSuccess) ? S_OK : E_FAIL; } HRESULT CMyPics::CEventSink::UnSinkEvents(IHTMLElement2 *pEle2, int iNum, EVENTS *pEvents) { for (int i=0; idetachEvent(bstrEvent, (IDispatch *)this); SysFreeString(bstrEvent); } } return S_OK; } HRESULT CMyPics::CEventSink::UnSinkEvents(IHTMLWindow3 *pWin3, int iNum, EVENTS *pEvents) { for (int i=0; idetachEvent(bstrEvent, (IDispatch *)this); SysFreeString(bstrEvent); } } return S_OK; } // IDispatch STDMETHODIMP CMyPics::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/) { return E_NOTIMPL; } STDMETHODIMP CMyPics::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/, /* [in] */ LCID /*lcid*/, /* [out] */ ITypeInfo** /*ppTInfo*/) { return E_NOTIMPL; } STDMETHODIMP CMyPics::CEventSink::GetIDsOfNames( REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; } STDMETHODIMP CMyPics::CEventSink::Invoke( DISPID dispIdMember, REFIID, LCID, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO*, UINT* puArgErr) { if (m_pParent && pDispParams && pDispParams->cArgs>=1) { if (pDispParams->rgvarg[0].vt == VT_DISPATCH) { IHTMLEventObj *pObj=NULL; if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj, (void **)&pObj) && pObj)) { EVENTS Event=EVENT_BOGUS; BSTR bstrEvent=NULL; pObj->get_type(&bstrEvent); if (bstrEvent) { for (int i=0; iget_srcElement(&pEle); // EVENT_SCROLL comes from our window so we won't have an // element for it if (pEle || (Event == EVENT_SCROLL)) { // Call the event handler here m_pParent->HandleEvent(pEle, Event, pObj); if (pEle) { pEle->Release(); } } } pObj->Release(); } } } return S_OK; } ////////////////////////////////////////////////////////////////////////////// // {9E56BE60-C50F-11CF-9A2C-00A0C90A90CE} EXTERN_C const GUID MP_CLSID_MailRecipient = {0x9E56BE60L, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE}; HRESULT DropPicOnMailRecipient(IDataObject *pdtobj, DWORD grfKeyState) { IDropTarget *pdrop; HRESULT hres = CoCreateInstance(MP_CLSID_MailRecipient, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IDropTarget, &pdrop)); if (SUCCEEDED(hres)) { hres = SHSimulateDrop(pdrop, pdtobj, grfKeyState, NULL, NULL); pdrop->Release(); } return hres; } // // This function cannot return Non -NULL pointers if // it returns a FAILED(hr) // HRESULT CreateShortcutSetSiteAndGetDataObjectIfPIDLIsNetUrl( LPCITEMIDLIST pidl, IUnknown *pUnkSite, IUniformResourceLocator **ppUrlOut, IDataObject **ppdtobj ) { HRESULT hr; TCHAR szUrl[MAX_URL_STRING]; TCHAR *szTemp = NULL; ASSERT(ppUrlOut); ASSERT(ppdtobj); *ppUrlOut = NULL; *ppdtobj = NULL; szUrl[0] = TEXT('\0'); hr = IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szUrl, SIZECHARS(szUrl), NULL); if ((S_OK == hr) && (*szUrl)) { BOOL fIsHTML = FALSE; BOOL fHitsNet = UrlHitsNetW(szUrl); if (!fHitsNet) { if (URL_SCHEME_FILE == GetUrlScheme(szUrl)) { TCHAR *szExt = PathFindExtension(szUrl); if (szExt) { fIsHTML = ((0 == StrCmpNI(szExt, TEXT(".htm"),4)) || (0 == StrCmpNI(szExt, TEXT(".html"),5))); } } } if (fHitsNet || fIsHTML) { // Create a shortcut object and HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUniformResourceLocator, ppUrlOut)); if (SUCCEEDED(hr)) { hr = (*ppUrlOut)->SetURL(szUrl, 0); if (S_OK == hr) { // Get the IDataObject and send that back for the Drag Drop hr = (*ppUrlOut)->QueryInterface(IID_PPV_ARG(IDataObject, ppdtobj)); if (SUCCEEDED(hr)) { IUnknown_SetSite(*ppUrlOut, pUnkSite); // Only set the site if we're sure of // returning SUCCESS } } } } else { hr = E_FAIL; } } if (FAILED(hr)) { SAFERELEASE(*ppUrlOut); SAFERELEASE(*ppdtobj); } return hr; } HRESULT SendDocToMailRecipient(LPCITEMIDLIST pidl, UINT uiCodePage, DWORD grfKeyState, IUnknown *pUnkSite) { IDataObject *pdtobj = NULL; IUniformResourceLocator *purl = NULL; HRESULT hr = CreateShortcutSetSiteAndGetDataObjectIfPIDLIsNetUrl(pidl, pUnkSite, &purl, &pdtobj); if (FAILED(hr)) { ASSERT(NULL == pdtobj); ASSERT(NULL == purl); hr = GetDataObjectForPidl(pidl, &pdtobj); } if (SUCCEEDED(hr)) { IQueryCodePage * pQcp; if (SUCCEEDED(pdtobj->QueryInterface(IID_PPV_ARG(IQueryCodePage, &pQcp)))) { pQcp->SetCodePage(uiCodePage); pQcp->Release(); } hr = DropPicOnMailRecipient(pdtobj, grfKeyState); pdtobj->Release(); } if (purl) { IUnknown_SetSite(purl, NULL); purl->Release(); } return hr; } ////////////////////////////////////////////////////////////////////////////// #undef TF_MYPICS