Windows2000/private/shell/ext/thumbvw/thextsup.cpp
2020-09-30 17:12:32 +02:00

453 lines
12 KiB
C++

#include "precomp.h"
#include "shellp.h"
#include "dllload.h"
UINT GetPidlLength( LPCITEMIDLIST pidl )
{
UINT cbSize = 0;
while ( pidl->mkid.cb != 0 )
{
cbSize += pidl->mkid.cb;
pidl = (LPCITEMIDLIST) ( (BYTE *) pidl + pidl->mkid.cb);
}
return cbSize;
}
// used the the ListView for sorting items.
int CALLBACK ListViewCompare( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
{
ListViewCompareStruct * pStruct = (ListViewCompareStruct * ) lParamSort;
Assert( pStruct->m_pFolder != NULL );
HRESULT hr = pStruct->m_pFolder->CompareIDs( pStruct->m_iCompareFlag, (LPCITEMIDLIST) lParam1, (LPCITEMIDLIST) lParam2 );
int iRes = (int) (short) SCODE_CODE( GetScode( hr ));
return iRes * pStruct->m_iAscend;
}
HRESULT GetSelectionPidlList( HWND hwnd, int cItems, LPCITEMIDLIST * apidl, int iItemHit )
{
if ( apidl == NULL )
{
return E_INVALIDARG;
}
int iItem = -1;
// assume that the get function doesn't mangle this structure too bad ...
LV_ITEMW rgItem;
ZeroMemory( &rgItem, sizeof( LV_ITEM ) );
rgItem.mask = LVIF_PARAM;
int iCtr = 0;
for ( int iIndex = 0; iIndex < (int) cItems; iIndex ++ )
{
iItem = ListView_GetNextItem( hwnd, iItem, LVNI_SELECTED );
// Assert that we were not passed a bogus view selection count...
Assert( iItem != -1 );
rgItem.iItem = iItem;
ListView_GetItemWrapW( hwnd, &rgItem);
Assert( rgItem.mask & LVIF_PARAM );
// NOTE: we must put the item that was FOCUSED as the
// NOTE: top item in the list. there are context menu extensions that depend on
// NOTE: this behaviour ....etc
// Check if the item is the focused one or not.
if ( iItem == ( int )iItemHit )
{
// Yes, put it at the top.
apidl[iCtr] = apidl[0];
apidl[0] = (LPCITEMIDLIST) rgItem.lParam;
}
else
// No, put it at the end of the list.
apidl[iCtr] = (LPCITEMIDLIST) rgItem.lParam;
iCtr++;
}
return NOERROR;
}
int FindInView( HWND hWnd, LPSHELLFOLDER pFolder, LPCITEMIDLIST pidl )
{
if ( pFolder == NULL || pidl == NULL )
{
return -1;
}
LV_ITEMW rgItem;
int iItem = -1;
memset( &rgItem, 0, sizeof( rgItem ) );
// search through the list view looking for a matching lParam
do
{
iItem = ListView_GetNextItem( hWnd, iItem, LVNI_ALL );
if ( iItem != -1 )
{
rgItem.mask = LVIF_PARAM;
rgItem.iItem = iItem;
BOOL bRes = (BOOL) SendMessageA( hWnd, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW *)(&rgItem));
Assert( bRes );
// ask the folder to kindly compare the Id's for us
if ( pFolder->CompareIDs( 0, pidl, (LPCITEMIDLIST) rgItem.lParam ) == 0 )
{
break;
}
}
} while ( iItem != -1 );
return iItem;
}
void Clear( HWND hWnd )
{
// because we cache an instance of the pidl as the LPARAM,
// it must be freed, so we must enum the vew first..
int iItem = -1;
LV_ITEMW rgItem;
ZeroMemory ( &rgItem, sizeof( rgItem ));
rgItem.mask = LVIF_PARAM;
do
{
iItem = ListView_GetNextItem( hWnd, iItem, LVNI_ALL );
if ( iItem == -1 )
break;
rgItem.iItem = iItem;
rgItem.lParam = 0;
if ( ListView_GetItemWrapW( hWnd, &rgItem))
{
Assert( rgItem.lParam != NULL );
SHFree( (LPVOID ) rgItem.lParam );
}
} while ( iItem != -1 );
ListView_DeleteAllItems( hWnd );
}
UINT MergeMenus( HMENU hOriginal, HMENU hNew, UINT idStart, UINT idPos )
{
UINT idMax = idStart;
MENUITEMINFOW rgMenuItem;
WCHAR szMenuItem[MAX_PATH];
int iMenuSize = GetMenuItemCount( hOriginal );
for (int iItem = GetMenuItemCount(hNew)-1; iItem >= 0; -- iItem)
{
rgMenuItem.cbSize = sizeof(rgMenuItem);
rgMenuItem.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
rgMenuItem.dwTypeData = szMenuItem;
rgMenuItem.cch = MAX_PATH;
rgMenuItem.dwItemData = 0;
BOOL bRes = GetMenuItemInfoWrapW(hNew, iItem, TRUE, &rgMenuItem);
if ( bRes == FALSE )
{
continue;
}
// only adjust the ID if it is not a submenu and is not a separator ...
if (( rgMenuItem.fMask & MIIM_ID ) && ( rgMenuItem.hSubMenu == NULL ) && ( rgMenuItem.fType != MFT_SEPARATOR ))
{
rgMenuItem.wID += idStart;
if ( idMax < rgMenuItem.wID )
{
idMax = rgMenuItem.wID;
}
}
if ( rgMenuItem.hSubMenu != NULL )
{
// must fix up the ID's of the cascading items ...
MENUITEMINFOW miiSub;
// assume that there is only one level of cascading menu.....
for ( int iSubItem = GetMenuItemCount(rgMenuItem.hSubMenu) -1; iSubItem >= 0; -- iSubItem )
{
miiSub.cbSize = sizeof( miiSub );
miiSub.fMask = MIIM_ID | MIIM_TYPE;
miiSub.cch = 0;
miiSub.hSubMenu = NULL;
miiSub.fType = 0;
BOOL bRes = GetMenuItemInfoWrapW( rgMenuItem.hSubMenu, iSubItem, TRUE, &miiSub );
if ( bRes == TRUE )
{
// only adjust the menu id if it really is a menu item not a submenu or
// separator...
if (( miiSub.fMask & MIIM_ID ) && ( miiSub.hSubMenu == NULL ) && ( miiSub.fType != MFT_SEPARATOR ))
{
miiSub.wID += idStart;
if ( idMax < miiSub.wID )
{
idMax = miiSub.wID;
}
// we only want to change the ID
miiSub.fMask = MIIM_ID;
SetMenuItemInfoWrapW( rgMenuItem.hSubMenu, iSubItem, TRUE, & miiSub );
}
}
}
// remove the menu from the original so that it is not destroyed later.....
// otherwise there seems to be a menu ref count lying around and the opertunity
// that when the original menu is destroyed it will destroy all the sub-menus
// with it.
RemoveMenu( hNew, iItem, MF_BYPOSITION );
}
InsertMenuItemWrapW( hOriginal, idPos, TRUE, &rgMenuItem );
}
return(idMax);
}
// add a separator to the menu in the position specified
void AddMenuSeparator( HMENU hMenu, int iIndex )
{
AddMenuSeparatorWithID( hMenu, iIndex, 0 );
}
void AddMenuSeparatorWithID( HMENU hMenu, int iIndex, UINT iID )
{
MENUITEMINFOW mii;
mii.cbSize = sizeof( mii );
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.wID = iID;
mii.fType = MFT_SEPARATOR;
mii.cch = 0;
InsertMenuItemWrapW( hMenu, iIndex, TRUE, &mii );
}
HMENU LoadPopupMenu( HINSTANCE hDllInst, int iResID )
{
HMENU hParent = LoadMenuA(hDllInst, (LPCSTR) MAKEINTRESOURCE(iResID));
if (hParent)
{
HMENU hpopup = GetSubMenu(hParent, 0);
RemoveMenu(hParent, 0, MF_BYPOSITION);
DestroyMenu(hParent);
return hpopup;
}
return NULL;
}
// get color resolution of the current display.
UINT GetCurColorRes( void )
{
HDC hdc;
UINT uColorRes;
hdc = GetDC( NULL );
uColorRes = GetDeviceCaps( hdc, PLANES ) * GetDeviceCaps( hdc, BITSPIXEL );
ReleaseDC( NULL , hdc );
return uColorRes;
}
LPCITEMIDLIST * DuplicateIDArray( LPCITEMIDLIST * apidl, UINT cidl )
{
LPCITEMIDLIST * apidlNew = (LPCITEMIDLIST *) LocalAlloc( LPTR, cidl * sizeof( LPCITEMIDLIST ));
if ( apidlNew )
{
CopyMemory( apidlNew, apidl, cidl * sizeof( LPCITEMIDLIST ));
}
return apidlNew;
}
HRESULT SHCLSIDFromStringA( LPCSTR szCLSID, CLSID * pCLSID )
{
WCHAR szWCLSID[50];
MultiByteToWideChar( CP_ACP, 0, szCLSID, -1, szWCLSID, 50);
return CLSIDFromString( szWCLSID, pCLSID );
}
HRESULT SHStringFromCLSIDA( LPSTR szCLSID, DWORD cSize, REFCLSID rCLSID )
{
if ( cSize < 39 )
{
return E_INVALIDARG;
}
WCHAR szWCLSID[40];
HRESULT hr = StringFromGUID2( rCLSID, szWCLSID, 40 );
if ( FAILED( hr ))
{
return hr;
}
WideCharToMultiByte( CP_ACP, 0, szWCLSID, -1, szCLSID, cSize, 0, 0);
return hr;
}
LPCITEMIDLIST FindLastPidl(LPCITEMIDLIST pidl)
{
LPCITEMIDLIST pidlLast = pidl;
LPCITEMIDLIST pidlNext = pidl;
if (pidl == NULL)
return NULL;
// Find the last one
while (pidlNext->mkid.cb)
{
pidlLast = pidlNext;
pidlNext = NextPIDL(pidlLast);
}
return (LPCITEMIDLIST)pidlLast;
}
HRESULT SimpleIDLISTToRealIDLIST( IShellFolder * psf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST * ppidlReal )
{
Assert( psf && pidlSimple && ppidlReal );
STRRET rgStr;
// check to make sure that we have a single level pidl
LPCITEMIDLIST pidlNext = NextPIDL( pidlSimple );
if ( pidlNext && pidlNext->mkid.cb != 0 )
{
return E_INVALIDARG;
}
HRESULT hres = psf->GetDisplayNameOf( pidlSimple, SHGDN_FORPARSING | SHGDN_INFOLDER, &rgStr );
if ( SUCCEEDED( hres ))
{
WCHAR szPath[MAX_PATH];
StrRetToBufW( &rgStr, pidlSimple, szPath, ARRAYSIZE(szPath) );
hres = psf->ParseDisplayName( NULL, NULL, szPath, NULL, ppidlReal, NULL );
}
return hres;
}
HRESULT Invoke_OnConnectionPointerContainer(IUnknown * punk, REFIID riidCP, DISPID dispidMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
{
HRESULT hr = S_OK; // Assume no errors.
IConnectionPointContainer * pcpc;
hr = punk->QueryInterface(IID_IConnectionPointContainer, (LPVOID*)&pcpc);
if (SUCCEEDED(hr))
{
IConnectionPoint * pcp;
hr = pcpc->FindConnectionPoint(riidCP, &pcp);
if (SUCCEEDED(hr))
{
IEnumConnections * pec;
hr = pcp->EnumConnections(&pec);
if (SUCCEEDED(hr))
{
CONNECTDATA cd;
ULONG cFetched;
while (S_OK == (hr = pec->Next(1, &cd, &cFetched)))
{
LPDISPATCH pdisp;
Assert(1 == cFetched);
hr = cd.pUnk->QueryInterface(IID_IDispatch, (LPVOID *) &pdisp);
if (SUCCEEDED(hr))
{
DISPPARAMS dispparams = {0};
if (!pdispparams)
pdispparams = &dispparams;
hr = pdisp->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
pdisp->Release();
}
else
Assert(FALSE);
}
pec->Release();
}
else
Assert(FALSE);
pcp->Release();
}
else
Assert(FALSE);
pcpc->Release();
}
else
Assert(FALSE);
return hr;
}
// Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
// , autoscrool, etc. . .
void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
{
RECT rc;
POINT pt;
GetWindowRect(hwndTarget, &rc);
if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
pt.x = rc.right - ptStart.x;
else
pt.x = ptStart.x - rc.left;
pt.y = ptStart.y - rc.top;
DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
}
void _DragMove(HWND hwndTarget, const POINTL ptStart)
{
RECT rc;
POINT pt;
GetWindowRect(hwndTarget, &rc);
if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
pt.x = rc.right - ptStart.x;
else
pt.x = ptStart.x - rc.left;
pt.y = ptStart.y - rc.top;
DAD_DragMove(pt);
}