- populate Open With with found entries

- see http://windowsxp.mvps.org/OpenWith.htm
- silence debug messages
- invoke shell extension's InvokeCommand on a event

svn path=/trunk/; revision=29981
This commit is contained in:
Johannes Anderwald 2007-10-30 18:35:02 +00:00
parent d4d9d8158b
commit 3b7c69f9c9
2 changed files with 416 additions and 17 deletions

View file

@ -23,7 +23,7 @@
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#define YDEBUG
//#define YDEBUG
#include "winerror.h"
#include "wine/debug.h"
@ -46,9 +46,11 @@ typedef struct
const IShellExtInitVtbl *lpvtblShellExtInit;
LONG wId;
volatile LONG ref;
WCHAR ** szArray;
UINT size;
UINT count;
} SHEOWImpl;
static const IShellExtInitVtbl eivt;
static const IContextMenu2Vtbl cmvt;
static HRESULT WINAPI SHEOWCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj);
@ -145,7 +147,8 @@ AddItems(SHEOWImpl *This, HMENU hMenu, UINT idCmdFirst)
{
UINT count = 0;
MENUITEMINFOW mii;
WCHAR szBuffer[50];
WCHAR szBuffer[MAX_PATH];
UINT index;
static const WCHAR szChoose[] = { 'C','h','o','o','s','e',' ','P','r','o','g','r','a','m','.','.','.',0 };
ZeroMemory(&mii, sizeof(mii));
@ -153,7 +156,25 @@ AddItems(SHEOWImpl *This, HMENU hMenu, UINT idCmdFirst)
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.wID = idCmdFirst;
for (index = 0; index < This->count; index++)
{
mii.wID = idCmdFirst;
mii.dwTypeData = (LPWSTR)This->szArray[index];
if (InsertMenuItemW(hMenu, -1, TRUE, &mii))
{
idCmdFirst++;
count++;
}
}
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_SEPARATOR;
mii.wID = -1;
InsertMenuItemW(hMenu, -1, TRUE, &mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
mii.fType = MFT_STRING;
if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
{
@ -161,8 +182,9 @@ AddItems(SHEOWImpl *This, HMENU hMenu, UINT idCmdFirst)
wcscpy(szBuffer, szChoose);
}
mii.wID = idCmdFirst;
mii.dwTypeData = (LPWSTR)szBuffer;
if (InsertMenuItemW(hMenu, 0, TRUE, &mii))
if (InsertMenuItemW(hMenu, -1, TRUE, &mii))
count++;
return count;
@ -180,6 +202,7 @@ static HRESULT WINAPI SHEOWCm_fnQueryContextMenu(
MENUITEMINFOW mii;
USHORT items = 0;
WCHAR szBuffer[100];
BOOL bDefault = FALSE;
HMENU hSubMenu = NULL;
SHEOWImpl *This = impl_from_IContextMenu(iface);
@ -190,14 +213,26 @@ static HRESULT WINAPI SHEOWCm_fnQueryContextMenu(
return E_FAIL;
}
hSubMenu = CreatePopupMenu();
if (hSubMenu == NULL)
if (This->count)
{
ERR("failed to create submenu");
return E_FAIL;
hSubMenu = CreatePopupMenu();
if (hSubMenu == NULL)
{
ERR("failed to create submenu");
return E_FAIL;
}
items = AddItems(This, hSubMenu, idCmdFirst + 1);
}
else
{
/* no file association found */
UINT pos = GetMenuDefaultItem(hmenu, TRUE, 0);
if (pos != -1)
{
/* replace default item with "Open With" action */
bDefault = DeleteMenu(hmenu, pos, MF_BYPOSITION);
}
}
items = AddItems(This, hSubMenu, idCmdFirst);
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
@ -209,7 +244,14 @@ static HRESULT WINAPI SHEOWCm_fnQueryContextMenu(
}
mii.dwTypeData = (LPWSTR) szBuffer;
mii.fState = MFS_ENABLED;
mii.wID = idCmdFirst + items;
if (bDefault)
{
mii.fState |= MFS_DEFAULT;
}
mii.wID = idCmdFirst;
This->wId = idCmdFirst;
mii.fType = MFT_STRING;
if (InsertMenuItemW( hmenu, 0, TRUE, &mii))
items++;
@ -222,10 +264,21 @@ static HRESULT WINAPI
SHEOWCm_fnInvokeCommand( IContextMenu2* iface, LPCMINVOKECOMMANDINFO lpici )
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
TRACE("This %p\n", This);
TRACE("This %p wId %x count %u verb %x\n", This, This->wId, This->count, LOWORD(lpici->lpVerb));
return E_FAIL;
if (This->wId > LOWORD(lpici->lpVerb) || This->count + This->wId < LOWORD(lpici->lpVerb))
return E_FAIL;
if (This->wId == LOWORD(lpici->lpVerb))
{
/* show Open As dialog */
return S_OK;
}
else
{
/* show program select dialog */
return S_OK;
}
}
static HRESULT WINAPI
@ -264,6 +317,329 @@ static const IContextMenu2Vtbl cmvt =
SHEOWCm_fnHandleMenuMsg
};
BOOL
SHEOW_ResizeArray(SHEOWImpl *This)
{
WCHAR ** new_array;
UINT ncount;
if (This->count == 0)
ncount = 10;
else
ncount = This->count * 2;
new_array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ncount * sizeof(WCHAR*));
if (!new_array)
return FALSE;
if (This->szArray)
{
memcpy(new_array, This->szArray, This->count * sizeof(WCHAR*));
HeapFree(GetProcessHeap(), 0, This->szArray);
}
This->szArray = new_array;
This->size = ncount;
return TRUE;
}
void
SHEOW_AddOWItem(SHEOWImpl *This, WCHAR * szAppName)
{
UINT index;
WCHAR * szPtr;
if (This->count + 1 >= This->size || !This->szArray)
{
if (!SHEOW_ResizeArray(This))
return;
}
szPtr = wcsrchr(szAppName, '.');
if (szPtr)
{
szPtr[0] = 0;
}
for(index = 0; index < This->count; index++)
{
if (!wcsicmp(This->szArray[index], szAppName))
return;
}
This->szArray[This->count] = wcsdup(szAppName);
if (This->szArray[This->count])
This->count++;
}
UINT
SHEW_AddOpenWithProgId(SHEOWImpl *This, HKEY hKey)
{
FIXME("implement me :)))\n");
return 0;
}
UINT
SHEW_AddOpenWithItem(SHEOWImpl *This, HKEY hKey)
{
UINT NumItems = 0;
DWORD dwIndex = 0;
DWORD dwName, dwValue;
LONG result = ERROR_SUCCESS;
WCHAR szName[10];
WCHAR szValue[MAX_PATH];
WCHAR szMRUList[MAX_PATH] = {0};
static const WCHAR szMRU[] = {'M','R','U','L','i','s','t', 0 };
while(result == ERROR_SUCCESS)
{
dwName = sizeof(szName);
dwValue = sizeof(szValue);
result = RegEnumValueW(hKey,
dwIndex,
szName,
&dwName,
NULL,
NULL,
(LPBYTE)szValue,
&dwValue);
szName[9] = 0;
szValue[MAX_PATH-1] = 0;
if (result == ERROR_SUCCESS)
{
if (wcsicmp(szValue, szMRU))
{
SHEOW_AddOWItem(This, szValue);
NumItems++;
}
else
{
wcscpy(szMRUList, szValue);
}
}
dwIndex++;
}
if (szMRUList[0])
{
FIXME("handle MRUList\n");
}
return NumItems;
}
UINT
SHEOW_LoadItemFromHKCR(SHEOWImpl *This, WCHAR * szExt)
{
HKEY hKey;
HKEY hSubKey;
LONG result;
UINT NumKeys = 0;
WCHAR szBuffer[30];
WCHAR szResult[70];
DWORD dwSize;
static const WCHAR szCROW[] = { 'O','p','e','n','W','i','t','h','L','i','s','t', 0 };
static const WCHAR szCROP[] = { 'O','p','e','n','W','i','t','h','P','r','o','g','I','D','s',0 };
static const WCHAR szPT[] = { 'P','e','r','c','e','i','v','e','d','T','y','p','e', 0 };
static const WCHAR szSys[] = { 'S','y','s','t','e','m','F','i','l','e','A','s','s','o','c','i','a','t','i','o','n','s','\\','%','s','\\','O','p','e','n','W','i','t','h','L','i','s','t', 0 };
TRACE("SHEOW_LoadItemFromHKCR entered with This %p szExt %s\n",This, debugstr_w(szExt));
result = RegOpenKeyExW(HKEY_CLASSES_ROOT,
szExt,
0,
KEY_READ | KEY_QUERY_VALUE,
&hKey);
if (result != ERROR_SUCCESS)
return NumKeys;
result = RegOpenKeyExW(hKey,
szCROW,
0,
KEY_READ | KEY_QUERY_VALUE,
&hSubKey);
if (result == ERROR_SUCCESS)
{
NumKeys = SHEW_AddOpenWithItem(This, hSubKey);
RegCloseKey(hSubKey);
}
result = RegOpenKeyExW(hKey,
szCROP,
0,
KEY_READ | KEY_QUERY_VALUE,
&hSubKey);
if (result == ERROR_SUCCESS)
{
NumKeys += SHEW_AddOpenWithProgId(This, hSubKey);
RegCloseKey(hSubKey);
}
dwSize = sizeof(szBuffer);
result = RegGetValueW(hKey,
NULL,
szPT,
RRF_RT_REG_SZ,
NULL,
szBuffer,
&dwSize);
szBuffer[29] = 0;
if (result != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return NumKeys;
}
sprintfW(szResult, szSys, szExt);
result = RegOpenKeyExW(hKey,
szCROW,
0,
KEY_READ | KEY_QUERY_VALUE,
&hSubKey);
if (result == ERROR_SUCCESS)
{
NumKeys += SHEW_AddOpenWithProgId(This, hSubKey);
RegCloseKey(hSubKey);
}
RegCloseKey(hKey);
return NumKeys;
}
UINT
SHEOW_LoadItemFromHKCU(SHEOWImpl *This, WCHAR * szExt)
{
WCHAR szBuffer[MAX_PATH];
HKEY hKey;
UINT KeyCount = 0;
LONG result;
static const WCHAR szOWPL[] = { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',
'\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','F','i','l','e','E','x','t','s',
'\\','%','s','\\','O','p','e','n','W','i','t','h','P','r','o','g','I','D','s',0 };
static const WCHAR szOpenWith[] = { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',
'\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','F','i','l','e','E','x','t','s',
'\\','%','s','\\','O','p','e','n','W','i','t','h','L','i','s','t', 0 };
TRACE("SHEOW_LoadItemFromHKCU entered with This %p szExt %s\n",This, debugstr_w(szExt));
/* process HKCU settings */
sprintfW(szBuffer, szOWPL, szExt);
TRACE("szBuffer %s\n", debugstr_w(szBuffer));
result = RegOpenKeyExW(HKEY_CURRENT_USER,
szBuffer,
0,
KEY_READ | KEY_QUERY_VALUE,
&hKey);
if (result == ERROR_SUCCESS)
{
KeyCount = SHEW_AddOpenWithProgId(This, hKey);
RegCloseKey(hKey);
}
sprintfW(szBuffer, szOpenWith, szExt);
TRACE("szBuffer %s\n", debugstr_w(szBuffer));
result = RegOpenKeyExW(HKEY_CURRENT_USER,
szBuffer,
0,
KEY_READ | KEY_QUERY_VALUE,
&hKey);
if (result == ERROR_SUCCESS)
{
KeyCount += SHEW_AddOpenWithItem(This, hKey);
RegCloseKey(hKey);
}
return KeyCount;
}
HRESULT
SHEOW_LoadOpenWithItems(SHEOWImpl *This, IDataObject *pdtobj)
{
STGMEDIUM medium;
FORMATETC fmt;
HRESULT hr;
LPIDA pida;
LPCITEMIDLIST pidl_folder;
LPCITEMIDLIST pidl_child;
LPCITEMIDLIST pidl;
WCHAR szPath[MAX_PATH];
LPWSTR szPtr;
fmt.cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
fmt.ptd = NULL;
fmt.dwAspect = DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED_HGLOBAL;
hr = IDataObject_GetData(pdtobj, &fmt, &medium);
if (FAILED(hr))
{
ERR("IDataObject_GetData failed with 0x%x\n", hr);
return hr;
}
/*assert(pida->cidl==1);*/
pida = (LPIDA)GlobalLock(medium.u.hGlobal);
pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]);
pidl = ILCombine(pidl_folder, pidl_child);
GlobalUnlock(medium.u.hGlobal);
GlobalFree(medium.u.hGlobal);
if (!pidl)
{
ERR("no mem\n");
return E_OUTOFMEMORY;
}
if (!SHGetPathFromIDListW(pidl, szPath))
{
SHFree(pidl);
ERR("SHGetPathFromIDListW failed\n");
return FALSE;
}
SHFree(pidl);
TRACE("szPath %s\n", debugstr_w(szPath));
szPtr = wcschr(szPath, '.');
if (szPtr)
{
SHEOW_LoadItemFromHKCU(This, szPtr);
SHEOW_LoadItemFromHKCR(This, szPtr);
}
TRACE("count %u\n", This->count);
return S_OK;
}
static HRESULT WINAPI
SHEOW_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
IDataObject *pdtobj, HKEY hkeyProgID )
@ -272,7 +648,7 @@ SHEOW_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
TRACE("This %p\n", This);
return S_OK;
return SHEOW_LoadOpenWithItems(This, pdtobj);
}
static ULONG WINAPI SHEOW_ExtInit_AddRef(IShellExtInit *iface)

View file

@ -23,7 +23,7 @@
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#define YDEBUG
//#define YDEBUG
#include "winerror.h"
#include "wine/debug.h"
@ -45,6 +45,7 @@ BOOL fileMoving = FALSE;
/**************************************************************************
* IContextMenu Implementation
*/
typedef struct
{ const IContextMenu2Vtbl *lpVtbl;
LONG ref;
@ -615,6 +616,24 @@ static void DoProperties(
SHFree(pidlFQ);
}
}
HRESULT
DoShellExtensions(ItemCmImpl *This, LPCMINVOKECOMMANDINFO lpcmi)
{
HRESULT hResult;
UINT i;
TRACE("DoShellExtensions %p verb %x count %u\n",This, LOWORD(lpcmi->lpVerb), This->ecount);
for(i = 0; i < This->ecount; i++)
{
IContextMenu * cmenu = This->ecmenu[i];
hResult = cmenu->lpVtbl->InvokeCommand(cmenu, lpcmi);
if (SUCCEEDED(hResult))
return hResult;
}
return NOERROR;
}
/**************************************************************************
* ISvItemCm_fnInvokeCommand()
@ -669,6 +688,10 @@ static HRESULT WINAPI ISvItemCm_fnInvokeCommand(
DoProperties(iface, lpcmi->hwnd);
break;
default:
if (LOWORD(lpcmi->lpVerb) >= This->iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSHELast)
{
return DoShellExtensions(iface, lpcmi);
}
FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
}
}