685 lines
19 KiB
C++
685 lines
19 KiB
C++
/**************************************************************\
|
|
FILE: addrlist.cpp
|
|
|
|
DESCRIPTION:
|
|
This is a class that all Address Lists can inherite
|
|
from. This will give them the IAddressList interface
|
|
so they can work in the AddressBand/Bar.
|
|
\**************************************************************/
|
|
|
|
#include "priv.h"
|
|
#include "util.h"
|
|
#include "itbdrop.h"
|
|
#include "autocomp.h"
|
|
#include "addrlist.h"
|
|
#include "apithk.h"
|
|
#include "shui.h"
|
|
#include "shlguid.h"
|
|
|
|
CAddressList::CAddressList() : _cRef(1)
|
|
{
|
|
// This needs to be allocated in Zero Inited Memory.
|
|
// Assert that all Member Variables are inited to Zero.
|
|
ASSERT(!_pbp);
|
|
}
|
|
|
|
CAddressList::~CAddressList()
|
|
{
|
|
if (_pbp)
|
|
_pbp->Release();
|
|
if (_pbs)
|
|
_pbs->Release();
|
|
if (_pshuUrl)
|
|
delete _pshuUrl;
|
|
}
|
|
|
|
ULONG CAddressList::AddRef()
|
|
{
|
|
_cRef++;
|
|
return _cRef;
|
|
}
|
|
|
|
ULONG CAddressList::Release()
|
|
{
|
|
ASSERT(_cRef > 0);
|
|
_cRef--;
|
|
|
|
if (_cRef > 0)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CAddressList::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IWinEventHandler) ||
|
|
IsEqualIID(riid, IID_IAddressList))
|
|
{
|
|
*ppvObj = SAFECAST(this, IAddressList*);
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//================================
|
|
// ** IWinEventHandler Interface ***
|
|
|
|
/****************************************************\
|
|
FUNCTION: OnWinEvent
|
|
|
|
DESCRIPTION:
|
|
This function will give receive events from
|
|
the parent ShellToolbar.
|
|
\****************************************************/
|
|
HRESULT CAddressList::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
|
|
{
|
|
LRESULT lres = 0;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
lres = _OnCommand(wParam, lParam);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
lres = _OnNotify((LPNMHDR)lParam);
|
|
break;
|
|
}
|
|
|
|
if (plres)
|
|
*plres = lres;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//================================
|
|
// *** IAddressList Interface ***
|
|
|
|
/****************************************************\
|
|
FUNCTION: Connect
|
|
|
|
DESCRIPTION:
|
|
We are either becoming the selected list for
|
|
the AddressBand's combobox, or lossing this status.
|
|
We need to populate or unpopulate the combobox
|
|
as appropriate.
|
|
\****************************************************/
|
|
HRESULT CAddressList::Connect(BOOL fConnect, HWND hwnd, IBrowserService * pbs, IBandProxy * pbp, IAutoComplete * pac)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(hwnd);
|
|
_fVisible = fConnect;
|
|
_hwnd = hwnd;
|
|
|
|
// Copy the (IBandProxy *) parameter
|
|
if (_pbp)
|
|
_pbp->Release();
|
|
_pbp = pbp;
|
|
if (_pbp)
|
|
_pbp->AddRef();
|
|
|
|
if (_pbs)
|
|
_pbs->Release();
|
|
_pbs = pbs;
|
|
if (_pbs)
|
|
_pbs->AddRef();
|
|
|
|
if (fConnect)
|
|
{
|
|
//
|
|
// Initial combobox parameters.
|
|
//
|
|
_InitCombobox();
|
|
}
|
|
else
|
|
{
|
|
// Remove contents of the List
|
|
_PurgeComboBox();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
FUNCTION: _InitCombobox
|
|
|
|
DESCRIPTION:
|
|
Prepare the combo box for this list. This normally
|
|
means that the indenting and icon are either turned
|
|
on or off.
|
|
\****************************************************/
|
|
void CAddressList::_InitCombobox()
|
|
{
|
|
SendMessage(_hwnd, CB_SETDROPPEDWIDTH, 200, 0L);
|
|
SendMessage(_hwnd, CB_SETEXTENDEDUI, TRUE, 0L);
|
|
SendMessage(_hwnd, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOSIZELIMIT, CBES_EX_NOSIZELIMIT);
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
FUNCTION: _PurgeComboBox
|
|
|
|
DESCRIPTION:
|
|
Removes all items from the combobox.
|
|
\****************************************************/
|
|
void CAddressList::_PurgeComboBox()
|
|
{
|
|
if (_hwnd)
|
|
{
|
|
SendMessage(_hwnd, CB_RESETCONTENT, 0, 0L);
|
|
}
|
|
}
|
|
|
|
/****************************************************\
|
|
FUNCTION: _OnCommand
|
|
|
|
DESCRIPTION:
|
|
This function will handle WM_COMMAND messages.
|
|
\****************************************************/
|
|
LRESULT CAddressList::_OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT uCmd = GET_WM_COMMAND_CMD(wParam, lParam);
|
|
|
|
switch (uCmd)
|
|
{
|
|
case CBN_DROPDOWN:
|
|
{
|
|
HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
//
|
|
// DOH! The user wants to see the full combo contents.
|
|
// Better go fill it in now.
|
|
//
|
|
_Populate();
|
|
SetCursor(hCursorOld);
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void ChangeUrl(LPCTSTR pszUrl, LPTSTR pszDisplayName, DWORD cchSize)
|
|
{
|
|
TCHAR szTemp[MAX_URL_STRING];
|
|
|
|
StrCpyN(szTemp, pszUrl, ARRAYSIZE(szTemp)); // This is necessary because pszUrl points into the buffer of pszDisplayName
|
|
StrCpyN(pszDisplayName, szTemp, cchSize);
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
FUNCTION: NavigationComplete
|
|
|
|
DESCRIPTION:
|
|
Update the URL in the Top of the list.
|
|
\****************************************************/
|
|
HRESULT CAddressList::NavigationComplete(LPVOID pvCShellUrl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szDisplayName[MAX_URL_STRING];
|
|
CShellUrl * psu = (CShellUrl *) pvCShellUrl;
|
|
LPITEMIDLIST pidl;
|
|
ASSERT(pvCShellUrl);
|
|
hr = psu->GetDisplayName(szDisplayName, SIZECHARS(szDisplayName));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Don't display the url to internal error pages. The url that should get
|
|
// displayed is appended after the #.
|
|
//
|
|
// All error urls start with res:// so do a quick check first.
|
|
//
|
|
BOOL fChangeURL = TRUE;
|
|
if (TEXT('r') == szDisplayName[0] && TEXT('e') == szDisplayName[1])
|
|
{
|
|
if (IsErrorUrl(szDisplayName))
|
|
{
|
|
TCHAR* pszUrl = StrChr(szDisplayName, TEXT('#'));
|
|
if (pszUrl)
|
|
{
|
|
pszUrl += 1;
|
|
|
|
DWORD dwScheme = GetUrlScheme(pszUrl);
|
|
fChangeURL = ((URL_SCHEME_HTTP == dwScheme) ||
|
|
(URL_SCHEME_HTTPS == dwScheme) ||
|
|
(URL_SCHEME_FTP == dwScheme) ||
|
|
(URL_SCHEME_GOPHER == dwScheme));
|
|
|
|
// Don't blast in the stuff after the # into address bar
|
|
// unless it is a 'safe' url. If it's not safe leave the
|
|
// addressbar alone to preserve what the user typed in.
|
|
//
|
|
// The issue here is that a web page could navigate to our internal
|
|
// error page with "format c:" after the '#'. The error page
|
|
// suggests that the user refreshed the page which would be very bad!
|
|
if (fChangeURL)
|
|
{
|
|
ChangeUrl(pszUrl, szDisplayName, ARRAYSIZE(szDisplayName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fChangeURL)
|
|
{
|
|
SHRemoveURLTurd(szDisplayName);
|
|
SHCleanupUrlForDisplay(szDisplayName);
|
|
|
|
hr = psu->GetPidl(&pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
COMBOBOXEXITEM cbexItem = {0};
|
|
cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
|
|
cbexItem.iItem = -1;
|
|
cbexItem.pszText = szDisplayName;
|
|
cbexItem.cchTextMax = ARRAYSIZE(szDisplayName);
|
|
|
|
hr = _GetPidlIcon(pidl, &(cbexItem.iImage), &(cbexItem.iSelectedImage));
|
|
SendMessage(_hwnd, CBEM_SETITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
|
|
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceMsg(TF_BAND|TF_GENERAL, "CAddressList: NavigationComplete(), URL=%s", szDisplayName);
|
|
return hr;
|
|
}
|
|
|
|
/*******************************************************************
|
|
FUNCTION: _MoveAddressToTopOfList
|
|
|
|
PARAMETERS:
|
|
iSel - index of item in combo box to move
|
|
|
|
DESCRIPTION:
|
|
Moves the specified selection in the combo box
|
|
to be the first item in the combo box
|
|
********************************************************************/
|
|
BOOL CAddressList::_MoveAddressToTopOfList(int iSel)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
ASSERT(iSel >= 0); // must have valid index
|
|
|
|
COMBOBOXEXITEM cbexItem = {0};
|
|
TCHAR szAddress[MAX_URL_STRING+1];
|
|
|
|
cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
|
|
cbexItem.pszText = szAddress;
|
|
cbexItem.cchTextMax = ARRAYSIZE(szAddress);
|
|
cbexItem.iItem = iSel;
|
|
|
|
|
|
// get the specified item from combo box
|
|
if (SendMessage(_hwnd,CBEM_GETITEM,0,(LPARAM) &cbexItem)) {
|
|
|
|
SendMessage(_hwnd, CBEM_DELETEITEM, (WPARAM)iSel, (LPARAM)0);
|
|
|
|
// re-insert it at index 0 to put it at the top
|
|
cbexItem.iItem = 0;
|
|
|
|
// sending CBEM_INSERTITEM should return the index we specified
|
|
// (0) if successful
|
|
fRet = (SendMessage(_hwnd, CBEM_INSERTITEM, (WPARAM)0,
|
|
(LPARAM)(LPVOID)&cbexItem) == 0);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
FUNCTION: _ComboBoxInsertURL
|
|
|
|
DESCRIPTION:
|
|
Adds the specified URL to the top of the address bar
|
|
combo box. Limits the number of URLs in combo box to
|
|
nMaxComboBoxSize.
|
|
********************************************************************/
|
|
void CAddressList::_ComboBoxInsertURL(LPCTSTR pszURL, int cchStrSize, int nMaxComboBoxSize)
|
|
{
|
|
// Since we own it and it's populated,
|
|
// we will add it directly to the ComboBox.
|
|
int iPrevInstance;
|
|
|
|
int iImage, iSelectedImage ;
|
|
|
|
COMBOBOXEXITEM cbexItem = {0};
|
|
cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
|
|
cbexItem.iItem = 0;
|
|
|
|
cbexItem.cchTextMax = cchStrSize;
|
|
cbexItem.pszText = (LPTSTR)pszURL;
|
|
|
|
_GetUrlUI(NULL, (LPTSTR)pszURL, &iImage, &iSelectedImage);
|
|
|
|
cbexItem.iImage = iImage;
|
|
cbexItem.iSelectedImage = iSelectedImage;
|
|
|
|
|
|
iPrevInstance = (int)SendMessage(_hwnd, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pszURL);
|
|
if (iPrevInstance != CB_ERR) {
|
|
_MoveAddressToTopOfList(iPrevInstance);
|
|
return;
|
|
}
|
|
|
|
// insert the URL as the first item in combo box
|
|
SendMessage(_hwnd, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
|
|
|
|
// limit number of items in combo box to nMaxComboBoxSize
|
|
if (ComboBox_GetCount(_hwnd) > nMaxComboBoxSize)
|
|
{
|
|
// if we're ever over the limit, we should only be over the limit
|
|
// by exactly one item
|
|
ASSERT(ComboBox_GetCount(_hwnd) == nMaxComboBoxSize+1);
|
|
|
|
// if over the limit, delete the least recently used
|
|
// (the one with the highest index)
|
|
|
|
SendMessage(_hwnd, CBEM_DELETEITEM, (WPARAM)nMaxComboBoxSize, (LPARAM)0);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
FUNCTION: SetToListIndex
|
|
|
|
DESCRIPTION:
|
|
This function will set the CShellUrl parameter to the item
|
|
in the Drop Down list that is indexed by nIndex.
|
|
********************************************************************/
|
|
HRESULT CAddressList::SetToListIndex(int nIndex, LPVOID pvShelLUrl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szBuffer[MAX_URL_STRING];
|
|
CShellUrl * psuURL = (CShellUrl *) pvShelLUrl;
|
|
|
|
if (SUCCEEDED(GetCBListIndex(_hwnd, nIndex, szBuffer, SIZECHARS(szBuffer))))
|
|
{
|
|
hr = psuURL->ParseFromOutsideSource(szBuffer, SHURL_FLAGS_NOUI);
|
|
ASSERT(SUCCEEDED(hr)); // We should not have added it to the Drop Down list if it's invalid.
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAddressList::FileSysChangeAL(DWORD dw, LPCITEMIDLIST *ppidl)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
FUNCTION: GetCBListIndex
|
|
|
|
DESCRIPTION:
|
|
This function will get the text of a specified
|
|
element in the combobox.
|
|
\****************************************************/
|
|
HRESULT GetCBListIndex(HWND hwnd, int iItem, LPTSTR szAddress, int cchAddressSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
COMBOBOXEXITEM cbexItem = {0};
|
|
|
|
cbexItem.mask = CBEIF_TEXT;
|
|
cbexItem.pszText = szAddress;
|
|
cbexItem.cchTextMax = cchAddressSize;
|
|
cbexItem.iItem = iItem;
|
|
|
|
if (SendMessage(hwnd, CBEM_GETITEM, 0, (LPARAM) &cbexItem))
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Helper Function
|
|
// We need to really becareful of perf in this function.
|
|
HRESULT CAddressList::_GetUrlUI(CShellUrl *psu, LPCTSTR szUrl, int *piImage, int *piSelectedImage)
|
|
{
|
|
CShellUrl * psuUrl;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (psu)
|
|
psuUrl = psu;
|
|
else
|
|
{
|
|
psuUrl = new CShellUrl();
|
|
if (psuUrl)
|
|
{
|
|
// Set the parent for error messageboxes. Note that this could end up disabing the taskbar.
|
|
// If this is deemed to be a problem we can first check to see where the addressbar is hosted.
|
|
psuUrl->SetMessageBoxParent(_hwnd);
|
|
|
|
SetDefaultShellPath(psuUrl);
|
|
}
|
|
}
|
|
|
|
//Initialize the values to 0
|
|
*piImage = 0;
|
|
*piSelectedImage = 0;
|
|
|
|
//if object is not created return with default value
|
|
if (!psuUrl)
|
|
return E_OUTOFMEMORY;
|
|
|
|
#ifdef DISABLED // Why not show the correct icon for removable drives?
|
|
int iDrive;
|
|
|
|
// See if we have a drive specified in the path
|
|
if ((iDrive = PathGetDriveNumber(szUrl)) >= 0)
|
|
{
|
|
// See if the drive is removable ?
|
|
if(DriveType(iDrive) == DRIVE_REMOVABLE)
|
|
hr = S_OK; //Drive is removable so pass the default icons
|
|
}
|
|
#endif
|
|
|
|
// Do we still need to get the icons?
|
|
if (FAILED(hr))
|
|
{
|
|
// Yes, so try the fast way first.
|
|
hr = _GetFastPathIcons(szUrl, piImage, piSelectedImage);
|
|
if (FAILED(hr))
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
// If that failed because it the string probably uses advanced parsing,
|
|
// let CShellUrl do it the slower but more thurough way.
|
|
hr = psuUrl->ParseFromOutsideSource(szUrl, SHURL_FLAGS_NOUI);
|
|
if(SUCCEEDED(hr))
|
|
hr = psuUrl->GetPidl(&pidl);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = _GetPidlIcon(pidl, piImage, piSelectedImage);
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psu != psuUrl)
|
|
delete psuUrl;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IECreateFromPath() and CShellUrl::ParseFromOutsideSource() both
|
|
// touch the disk which causes unconnected network cases to be really
|
|
// slow. This will create icons for file system paths w/o hitting
|
|
// the disk.
|
|
HRESULT CAddressList::_GetFastPathIcons(LPCTSTR pszPath, int *piImage, int *piSelectedImage)
|
|
{
|
|
SHFILEINFO shFileInfo = {0};
|
|
|
|
// SHGetFileInfo() with those flags will be fast because it's won't filter out
|
|
// garbage passed to it. So it will think URLs are actually relative paths
|
|
// and accept them. We will fall back to the slow advanced parser which is still
|
|
// fast with URLs.
|
|
if (PathIsRelative(pszPath))
|
|
return E_FAIL;
|
|
|
|
HIMAGELIST himl = (HIMAGELIST) SHGetFileInfo(pszPath, FILE_ATTRIBUTE_DIRECTORY, &shFileInfo, sizeof(shFileInfo), (SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES));
|
|
if (!himl || !shFileInfo.iIcon)
|
|
return E_FAIL;
|
|
|
|
*piImage = shFileInfo.iIcon;
|
|
*piSelectedImage = shFileInfo.iIcon;
|
|
// I don't need to free himl.
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CAddressList::_GetPidlIcon(LPCITEMIDLIST pidl, int *piImage, int *piSelectedImage)
|
|
{
|
|
IShellFolder *psfParent;
|
|
LPCITEMIDLIST pidlChild;
|
|
HRESULT hr = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*piImage = IEMapPIDLToSystemImageListIndex(psfParent, pidlChild, piSelectedImage);
|
|
psfParent->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
LPITEMIDLIST CAddressList::_GetDragDropPidl(LPNMCBEDRAGBEGINW pnmcbe)
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
CShellUrl *psuUrl = new CShellUrl();
|
|
if (psuUrl)
|
|
{
|
|
// Set the parent for error messageboxes. Note that this could end up disabing the taskbar.
|
|
// If this is deemed to be a problem we can first check to see where the addressbar is hosted.
|
|
psuUrl->SetMessageBoxParent(_hwnd);
|
|
|
|
HRESULT hr = SetDefaultShellPath(psuUrl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psuUrl->ParseFromOutsideSource(pnmcbe->szText, SHURL_FLAGS_NOUI, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psuUrl->GetPidl(&pidl);
|
|
}
|
|
}
|
|
|
|
delete psuUrl;
|
|
}
|
|
return pidl;
|
|
}
|
|
|
|
LRESULT CAddressList::_OnDragBeginA(LPNMCBEDRAGBEGINA pnmcbe)
|
|
{
|
|
NMCBEDRAGBEGINW nmcbew;
|
|
|
|
nmcbew.hdr = pnmcbe->hdr;
|
|
nmcbew.iItemid = pnmcbe->iItemid;
|
|
SHAnsiToUnicode(pnmcbe->szText, nmcbew.szText, SIZECHARS(nmcbew.szText));
|
|
|
|
return _OnDragBeginW(&nmcbew);
|
|
}
|
|
|
|
#ifdef UNIX
|
|
extern "C" LPITEMIDLIST UnixUrlToPidl(UINT uiCP, LPCTSTR pszUrl, LPCWSTR pszLocation);
|
|
#endif
|
|
|
|
LRESULT CAddressList::_OnDragBeginW(LPNMCBEDRAGBEGINW pnmcbe)
|
|
{
|
|
LPITEMIDLIST pidl = _GetDragDropPidl(pnmcbe);
|
|
#ifdef UNIX
|
|
// for UNIX we fake a URL pidl so we create a .url instead of a .lnk
|
|
if (!IsURLChild(pidl, TRUE))
|
|
{
|
|
LPITEMIDLIST pidl1;
|
|
TCHAR szPath[MAX_PATH];
|
|
StrCpyN(szPath, TEXT("file://"), 8);
|
|
SHGetPathFromIDList(pidl, &szPath[7]);
|
|
pidl1 = UnixUrlToPidl(CP_ACP, szPath, NULL);
|
|
if (pidl1)
|
|
{
|
|
ILFree(pidl);
|
|
pidl = pidl1;
|
|
}
|
|
}
|
|
#endif
|
|
if (pidl)
|
|
{
|
|
IOleCommandTarget *pcmdt = NULL;
|
|
|
|
IUnknown *punk;
|
|
if (_pbp && SUCCEEDED(_pbp->GetBrowserWindow(&punk)))
|
|
{
|
|
punk->QueryInterface(IID_IOleCommandTarget, (void **)&pcmdt);
|
|
punk->Release();
|
|
}
|
|
|
|
DoDragDropWithInternetShortcut(pcmdt, pidl, _hwnd);
|
|
|
|
if (pcmdt)
|
|
pcmdt->Release();
|
|
|
|
ILFree(pidl);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// handle WM_NOTIFY messages.
|
|
LRESULT CAddressList::_OnNotify(LPNMHDR pnm)
|
|
{
|
|
LRESULT lReturn = 0;
|
|
|
|
switch (pnm->code)
|
|
{
|
|
case NM_SETCURSOR:
|
|
if (!SendMessage(_hwnd, CBEM_GETEXTENDEDSTYLE, 0, 0) & CBES_EX_NOEDITIMAGE)
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
int cx, cy;
|
|
GetCursorPos(&pt);
|
|
GetClientRect(_hwnd, &rc);
|
|
MapWindowRect(_hwnd, HWND_DESKTOP, &rc);
|
|
ImageList_GetIconSize((HIMAGELIST)SendMessage(_hwnd, CBEM_GETIMAGELIST, 0, 0), &cx, &cy);
|
|
|
|
rc.right = rc.left + cx + GetSystemMetrics(SM_CXEDGE);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
// this means there's an image, which means we can drag
|
|
SetCursor(LoadHandCursor(0));
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CBEN_DRAGBEGINA:
|
|
lReturn = _OnDragBeginA((LPNMCBEDRAGBEGINA)pnm);
|
|
break;
|
|
|
|
case CBEN_DRAGBEGINW:
|
|
lReturn = _OnDragBeginW((LPNMCBEDRAGBEGINW)pnm);
|
|
break;
|
|
}
|
|
|
|
return lReturn;
|
|
}
|