reactos/reactos/dll/win32/shell32/she_ocmenu.c
Rafal Harabien fcd25281d9 [SHELL32]
Sync RunFileDlg to wine. It was crashing for one char input.
Add "All files (*.*)" filter to RunDlg and OpenWith dialogs. 
Improved polish translation.
Translators: please localize rest...

svn path=/trunk/; revision=51127
2011-03-23 16:22:38 +00:00

1340 lines
38 KiB
C

/*
* Open With Context Menu extension
*
* Copyright 2007 Johannes Anderwald <janderwald@reactos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <precomp.h>
WINE_DEFAULT_DEBUG_CHANNEL (shell);
///
/// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system]
/// "NoInternetOpenWith"=dword:00000001
///
// TODO
// implement duplicate checks in list box
// implement duplicate checks for MRU!
// implement owner drawn menu
typedef struct
{
const IContextMenu2Vtbl *lpVtblContextMenu;
const IShellExtInitVtbl *lpvtblShellExtInit;
LONG wId;
volatile LONG ref;
BOOL NoOpen;
UINT count;
WCHAR szPath[MAX_PATH];
HMENU hSubMenu;
} SHEOWImpl, *LPSHEOWImpl;
typedef struct
{
BOOL bMenu;
HMENU hMenu;
HWND hDlgCtrl;
UINT Count;
BOOL NoOpen;
UINT idCmdFirst;
}OPEN_WITH_CONTEXT, *POPEN_WITH_CONTEXT;
#define MANUFACTURER_NAME_SIZE 100
typedef struct
{
HICON hIcon;
WCHAR szAppName[MAX_PATH];
WCHAR szManufacturer[MANUFACTURER_NAME_SIZE];
}OPEN_ITEM_CONTEXT, *POPEN_ITEM_CONTEXT;
typedef struct _LANGANDCODEPAGE_
{
WORD lang;
WORD code;
} LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
typedef struct {
DWORD cbSize;
DWORD uMax;
DWORD fFlags;
HKEY hKey;
LPWSTR lpszSubKey;
PROC lpfnCompare;
} MRUINFO, *LPMRUINFO;
#define MRUF_STRING_LIST 0
typedef HANDLE (WINAPI *CREATEMRULISTPROCW)(
LPMRUINFO lpmi
);
typedef int (WINAPI *ENUMMRULISTW)(
HANDLE hMRU,
int nItem,
void *lpData,
UINT uLen
);
typedef int (WINAPI *ADDMRUSTRINGW)(
HANDLE hMRU,
LPCWSTR szString
);
typedef void (WINAPI *FREEMRULIST)(
HANDLE hList);
static const IShellExtInitVtbl eivt;
static const IContextMenu2Vtbl cmvt;
static HRESULT WINAPI SHEOWCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj);
static ULONG WINAPI SHEOWCm_fnRelease(IContextMenu2 *iface);
HANDLE OpenMRUList(HKEY hKey);
void LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, WCHAR * szExt);
void LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, WCHAR * szExt);
void InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, WCHAR * szAppName);
static HMODULE hModule = NULL;
static CREATEMRULISTPROCW CreateMRUListProcW = NULL;
static ENUMMRULISTW EnumMRUListW = NULL;
static FREEMRULIST FreeMRUListProc = NULL;
static ADDMRUSTRINGW AddMRUStringW = NULL;
HRESULT WINAPI SHEOW_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv)
{
SHEOWImpl * ow;
HRESULT res;
ow = LocalAlloc(LMEM_ZEROINIT, sizeof(SHEOWImpl));
if (!ow)
{
return E_OUTOFMEMORY;
}
ow->ref = 1;
ow->lpVtblContextMenu = &cmvt;
ow->lpvtblShellExtInit = &eivt;
TRACE("(%p)->()\n",ow);
res = SHEOWCm_fnQueryInterface( (IContextMenu2*)&ow->lpVtblContextMenu, riid, ppv );
SHEOWCm_fnRelease( (IContextMenu2*)&ow->lpVtblContextMenu );
return res;
}
static LPSHEOWImpl __inline impl_from_IShellExtInit( IShellExtInit *iface )
{
return (SHEOWImpl *)((char*)iface - FIELD_OFFSET(SHEOWImpl, lpvtblShellExtInit));
}
static LPSHEOWImpl __inline impl_from_IContextMenu( IContextMenu2 *iface )
{
return (SHEOWImpl *)((char*)iface - FIELD_OFFSET(SHEOWImpl, lpVtblContextMenu));
}
static HRESULT WINAPI SHEOWCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
*ppvObj = NULL;
if(IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IContextMenu) ||
IsEqualIID(riid, &IID_IContextMenu2))
{
*ppvObj = (void *)&This->lpVtblContextMenu;
}
else if(IsEqualIID(riid, &IID_IShellExtInit))
{
*ppvObj = (void *)&This->lpvtblShellExtInit;
}
if(*ppvObj)
{
IUnknown_AddRef((IUnknown*)*ppvObj);
TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
return S_OK;
}
TRACE("-- Interface: E_NOINTERFACE\n");
return E_NOINTERFACE;
}
static ULONG WINAPI SHEOWCm_fnAddRef(IContextMenu2 *iface)
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(count=%u)\n", This, refCount - 1);
return refCount;
}
static ULONG WINAPI SHEOWCm_fnRelease(IContextMenu2 *iface)
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(count=%i)\n", This, refCount + 1);
if (!refCount)
{
TRACE(" destroying IContextMenu(%p)\n",This);
HeapFree(GetProcessHeap(),0,This);
}
return refCount;
}
VOID
AddItem(HMENU hMenu, UINT idCmdFirst)
{
MENUITEMINFOW mii;
WCHAR szBuffer[MAX_PATH];
static const WCHAR szChoose[] = { 'C','h','o','o','s','e',' ','P','r','o','g','r','a','m','.','.','.',0 };
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_SEPARATOR;
mii.wID = -1;
InsertMenuItemW(hMenu, -1, TRUE, &mii);
if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
wcscpy(szBuffer, szChoose);
szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.wID = idCmdFirst;
mii.dwTypeData = (LPWSTR)szBuffer;
mii.cch = wcslen(szBuffer);
InsertMenuItemW(hMenu, -1, TRUE, &mii);
}
static
void
LoadOWItems(POPEN_WITH_CONTEXT pContext, LPCWSTR szName)
{
WCHAR * szExt;
WCHAR szPath[100];
DWORD dwPath;
szExt = wcsrchr(szName, '.');
if (!szExt)
{
/* FIXME
* show default list of available programs
*/
return;
}
/* load programs directly associated from HKCU */
LoadItemFromHKCU(pContext, szExt);
/* load programs associated from HKCR\Extension */
LoadItemFromHKCR(pContext, szExt);
/* load programs referenced from HKCR\ProgId */
dwPath = sizeof(szPath);
szPath[0] = 0;
if (RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, szPath, &dwPath) == ERROR_SUCCESS)
{
szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0';
LoadItemFromHKCR(pContext, szPath);
}
}
static HRESULT WINAPI SHEOWCm_fnQueryContextMenu(
IContextMenu2 *iface,
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
MENUITEMINFOW mii;
WCHAR szBuffer[100] = {0};
INT pos;
HMENU hSubMenu = NULL;
OPEN_WITH_CONTEXT Context;
SHEOWImpl *This = impl_from_IContextMenu(iface);
if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)) < 0)
{
TRACE("failed to load string\n");
return E_FAIL;
}
szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
hSubMenu = CreatePopupMenu();
/* set up context */
ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT));
Context.bMenu = TRUE;
Context.Count = 0;
Context.hMenu = hSubMenu;
Context.idCmdFirst = idCmdFirst;
/* load items */
LoadOWItems(&Context, This->szPath);
if (!Context.Count)
{
DestroyMenu(hSubMenu);
hSubMenu = NULL;
This->wId = 0;
This->count = 0;
}
else
{
AddItem(hSubMenu, Context.idCmdFirst++);
This->count = Context.idCmdFirst - idCmdFirst;
/* verb start at index zero */
This->wId = This->count -1;
This->hSubMenu = hSubMenu;
}
pos = GetMenuDefaultItem(hmenu, TRUE, 0) + 1;
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
if (hSubMenu)
{
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = hSubMenu;
}
mii.dwTypeData = (LPWSTR) szBuffer;
mii.fState = MFS_ENABLED;
if (!pos)
{
mii.fState |= MFS_DEFAULT;
}
mii.wID = Context.idCmdFirst;
mii.fType = MFT_STRING;
if (InsertMenuItemW( hmenu, pos, TRUE, &mii))
Context.Count++;
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Context.Count);
}
void
FreeListItems(HWND hwndDlg)
{
HWND hList;
LRESULT iIndex, iCount;
POPEN_ITEM_CONTEXT pContext;
hList = GetDlgItem(hwndDlg, 14002);
iCount = SendMessageW(hList, LB_GETCOUNT, 0, 0);
if (iCount == LB_ERR)
return;
for (iIndex = 0; iIndex < iCount; iIndex++)
{
pContext = (POPEN_ITEM_CONTEXT)SendMessageW(hList, LB_GETITEMDATA, iIndex, 0);
if (pContext)
{
DestroyIcon(pContext->hIcon);
SendMessageW(hList, LB_SETITEMDATA, iIndex, (LPARAM)0);
HeapFree(GetProcessHeap(), 0, pContext);
}
}
}
BOOL HideApplicationFromList(WCHAR * pFileName)
{
WCHAR szBuffer[100] = {'A','p','p','l','i','c','a','t','i','o','n','s','\\',0};
DWORD dwSize = 0;
LONG result;
if (wcslen(pFileName) > (sizeof(szBuffer)/sizeof(WCHAR)) - 14)
{
ERR("insufficient buffer\n");
return FALSE;
}
wcscpy(&szBuffer[13], pFileName);
result = RegGetValueW(HKEY_CLASSES_ROOT, szBuffer, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize);
TRACE("result %d szBuffer %s\n", result, debugstr_w(szBuffer));
if (result == ERROR_SUCCESS)
return TRUE;
else
return FALSE;
}
VOID
WriteStaticShellExtensionKey(HKEY hRootKey, WCHAR * pVerb, WCHAR *pFullPath)
{
HKEY hShell;
LONG result;
WCHAR szBuffer[MAX_PATH+10] = {'s','h','e','l','l','\\', 0 };
if (wcslen(pVerb) > (sizeof(szBuffer)/sizeof(WCHAR)) - 15 ||
wcslen(pFullPath) > (sizeof(szBuffer)/sizeof(WCHAR)) - 4)
{
ERR("insufficient buffer\n");
return;
}
/* construct verb reg path */
wcscpy(&szBuffer[6], pVerb);
wcscat(szBuffer, L"\\command");
/* create verb reg key */
if (RegCreateKeyExW(hRootKey, szBuffer, 0, NULL, 0, KEY_WRITE, NULL, &hShell, NULL) != ERROR_SUCCESS)
return;
/* build command buffer */
wcscpy(szBuffer, pFullPath);
wcscat(szBuffer, L" %1");
result = RegSetValueExW(hShell, NULL, 0, REG_SZ, (const BYTE*)szBuffer, (wcslen(szBuffer)+1)* sizeof(WCHAR));
RegCloseKey(hShell);
}
VOID
StoreNewSettings(LPCWSTR szFileName, WCHAR *szAppName)
{
WCHAR szBuffer[100] = { L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"};
WCHAR * pFileExt;
HKEY hKey;
LONG result;
HANDLE hList;
/* get file extension */
pFileExt = wcsrchr(szFileName, L'.');
if (wcslen(pFileExt) > (sizeof(szBuffer)/sizeof(WCHAR)) - 60)
{
ERR("insufficient buffer\n");
return;
}
wcscpy(&szBuffer[60], pFileExt);
/* open base key for this file extension */
if (RegCreateKeyExW(HKEY_CURRENT_USER, szBuffer, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS)
return;
/* open mru list */
hList = OpenMRUList(hKey);
if (!hList)
{
RegCloseKey(hKey);
return;
}
/* insert the entry */
result = (*AddMRUStringW)(hList, szAppName);
/* close mru list */
(*FreeMRUListProc)((HANDLE)hList);
/* create mru list key */
RegCloseKey(hKey);
}
VOID
SetProgrammAsDefaultHandler(LPCWSTR szFileName, WCHAR * szAppName)
{
HKEY hKey;
HKEY hAppKey;
DWORD dwDisposition;
WCHAR szBuffer[100];
DWORD dwSize;
BOOL result;
WCHAR * pFileExt;
WCHAR * pFileName;
/* extract file extension */
pFileExt = wcsrchr(szFileName, L'.');
if (!pFileExt)
return;
/* create file extension key */
if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pFileExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
return;
if (dwDisposition & REG_CREATED_NEW_KEY)
{
/* a new entry was created create the prog key id */
wcscpy(szBuffer, &pFileExt[1]);
wcscat(szBuffer, L"_auto_file");
if (RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE*)szBuffer, (wcslen(szBuffer)+1) * sizeof(WCHAR)) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return;
}
}
else
{
/* entry already exists fetch prog key id */
dwSize = sizeof(szBuffer);
if (RegGetValueW(hKey, NULL, NULL, RRF_RT_REG_SZ, NULL, szBuffer, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return;
}
}
/* close file extension key */
RegCloseKey(hKey);
/* create prog id key */
if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
return;
/* check if there already verbs existing for that app */
pFileName = wcsrchr(szAppName, L'\\');
wcscpy(szBuffer, L"Classes\\Applications\\");
wcscat(szBuffer, pFileName);
wcscat(szBuffer, L"\\shell");
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ, &hAppKey) == ERROR_SUCCESS)
{
/* copy static verbs from Classes\Applications key */
HKEY hTemp;
if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hTemp, &dwDisposition) == ERROR_SUCCESS)
{
result = RegCopyTreeW(hAppKey, NULL, hTemp);
RegCloseKey(hTemp);
if (result == ERROR_SUCCESS)
{
/* copied all subkeys, we are done */
RegCloseKey(hKey);
RegCloseKey(hAppKey);
return;
}
}
RegCloseKey(hAppKey);
}
/* write standard static shell extension */
WriteStaticShellExtensionKey(hKey, L"open", szAppName);
RegCloseKey(hKey);
}
void
BrowseForApplication(HWND hwndDlg)
{
WCHAR szBuffer[64] = {0};
WCHAR szFilter[256] = {0};
WCHAR szPath[MAX_PATH];
OPENFILENAMEW ofn;
OPEN_WITH_CONTEXT Context;
INT count;
/* load resource open with */
if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
{
szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
ofn.lpstrTitle = szBuffer;
ofn.nMaxFileTitle = wcslen(szBuffer);
}
ZeroMemory(&ofn, sizeof(OPENFILENAMEW));
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.hInstance = shell32_hInstance;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.nMaxFile = (sizeof(szPath) / sizeof(WCHAR));
ofn.lpstrFile = szPath;
/* load the filter resource string */
if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, szFilter, sizeof(szFilter) / sizeof(WCHAR)))
{
szFilter[(sizeof(szFilter)/sizeof(WCHAR))-1] = 0;
ofn.lpstrFilter = szFilter;
}
ZeroMemory(szPath, sizeof(szPath));
/* call openfilename */
if (!GetOpenFileNameW(&ofn))
return;
/* setup context for insert proc */
ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT));
Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002);
count = SendMessage(Context.hDlgCtrl, LB_GETCOUNT, 0, 0);
InsertOpenWithItem(&Context, szPath);
/* select new item */
SendMessage(Context.hDlgCtrl, LB_SETCURSEL, count, 0);
}
POPEN_ITEM_CONTEXT
GetCurrentOpenItemContext(HWND hwndDlg)
{
LRESULT result;
/* get current item */
result = SendDlgItemMessage(hwndDlg, 14002, LB_GETCURSEL, 0, 0);
if(result == LB_ERR)
return NULL;
/* get item context */
result = SendDlgItemMessage(hwndDlg, 14002, LB_GETITEMDATA, result, 0);
if (result == LB_ERR)
return NULL;
return (POPEN_ITEM_CONTEXT)result;
}
void
ExecuteOpenItem(POPEN_ITEM_CONTEXT pItemContext, LPCWSTR FileName)
{
STARTUPINFOW si;
PROCESS_INFORMATION pi;
WCHAR szPath[(MAX_PATH * 2)];
/* setup path with argument */
ZeroMemory(&si, sizeof(STARTUPINFOW));
si.cb = sizeof(STARTUPINFOW);
wcscpy(szPath, pItemContext->szAppName);
wcscat(szPath, L" ");
wcscat(szPath, FileName);
ERR("path %s\n", debugstr_w(szPath));
if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
SHAddToRecentDocs(SHARD_PATHW, FileName);
}
}
static INT_PTR CALLBACK OpenWithProgrammDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPMEASUREITEMSTRUCT lpmis;
LPDRAWITEMSTRUCT lpdis;
INT index;
WCHAR szBuffer[MAX_PATH + 30] = { 0 };
OPENASINFO *poainfo;
TEXTMETRIC mt;
COLORREF preColor, preBkColor;
POPEN_ITEM_CONTEXT pItemContext;
LONG YOffset;
OPEN_WITH_CONTEXT Context;
poainfo = (OPENASINFO*) GetWindowLongPtr(hwndDlg, DWLP_USER);
switch(uMsg)
{
case WM_INITDIALOG:
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)lParam);
poainfo = (OPENASINFO*)lParam;
if (!(poainfo->oaifInFlags & OAIF_ALLOW_REGISTRATION))
EnableWindow(GetDlgItem(hwndDlg, 14003), FALSE);
if (poainfo->oaifInFlags & OAIF_FORCE_REGISTRATION)
SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0);
if (poainfo->oaifInFlags & OAIF_HIDE_REGISTRATION)
ShowWindow(GetDlgItem(hwndDlg, 14003), SW_HIDE);
if (poainfo->pcszFile)
{
szBuffer[0] = L'\0';
SendDlgItemMessageW(hwndDlg, 14001, WM_GETTEXT, sizeof(szBuffer), (LPARAM)szBuffer);
index = wcslen(szBuffer);
if (index + wcslen(poainfo->pcszFile) + 1 < sizeof(szBuffer)/sizeof(szBuffer[0]))
wcscat(szBuffer, poainfo->pcszFile);
szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, 0, (LPARAM)szBuffer);
ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT));
Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002);
LoadOWItems(&Context, poainfo->pcszFile);
SendMessage(Context.hDlgCtrl, LB_SETCURSEL, 0, 0);
}
return TRUE;
case WM_MEASUREITEM:
lpmis = (LPMEASUREITEMSTRUCT) lParam;
lpmis->itemHeight = 64;
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 14004: /* browse */
BrowseForApplication(hwndDlg);
return TRUE;
case 14002:
if (HIWORD(wParam) == LBN_SELCHANGE)
InvalidateRect((HWND)lParam, NULL, TRUE); // FIXME USE UPDATE RECT
break;
case 14005: /* ok */
pItemContext = GetCurrentOpenItemContext(hwndDlg);
if (pItemContext)
{
/* store settings in HKCU path */
StoreNewSettings(poainfo->pcszFile, pItemContext->szAppName);
if (SendDlgItemMessage(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
{
/* set programm as default handler */
SetProgrammAsDefaultHandler(poainfo->pcszFile, pItemContext->szAppName);
}
if (poainfo->oaifInFlags & OAIF_EXEC)
ExecuteOpenItem(pItemContext, poainfo->pcszFile);
}
FreeListItems(hwndDlg);
EndDialog(hwndDlg, 1);
return TRUE;
case 14006: /* cancel */
FreeListItems(hwndDlg);
EndDialog(hwndDlg, 0);
return TRUE;
default:
break;
}
break;
case WM_DRAWITEM:
lpdis = (LPDRAWITEMSTRUCT) lParam;
if (lpdis->itemID == -1)
break;
switch (lpdis->itemAction)
{
case ODA_SELECT:
case ODA_DRAWENTIRE:
index = SendMessageW(lpdis->hwndItem, LB_GETCURSEL, 0, 0);
pItemContext =(POPEN_ITEM_CONTEXT)SendMessage(lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0);
if (lpdis->itemID == index)
{
/* paint focused item with standard background colour */
HBRUSH hBrush;
hBrush = CreateSolidBrush(RGB(46, 104, 160));
FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
DeleteObject(hBrush);
preBkColor = SetBkColor(lpdis->hDC, RGB(46, 104, 160));
}
else
{
/* paint non focused item with white background */
HBRUSH hBrush;
hBrush = CreateSolidBrush(RGB(255, 255, 255));
FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
DeleteObject(hBrush);
preBkColor = SetBkColor(lpdis->hDC, RGB(255, 255, 255));
}
SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM) szBuffer);
/* paint the icon */
DrawIconEx(lpdis->hDC, lpdis->rcItem.left,lpdis->rcItem.top, pItemContext->hIcon, 0, 0, 0, NULL, DI_NORMAL);
/* get text size */
GetTextMetrics(lpdis->hDC, &mt);
/* paint app name */
YOffset = lpdis->rcItem.top + mt.tmHeight/2;
TextOutW(lpdis->hDC, 45, YOffset, szBuffer, wcslen(szBuffer));
/* paint manufacturer description */
YOffset += mt.tmHeight + 2;
preColor = SetTextColor(lpdis->hDC, RGB(192, 192, 192));
if (pItemContext->szManufacturer[0])
TextOutW(lpdis->hDC, 45, YOffset, pItemContext->szManufacturer, wcslen(pItemContext->szManufacturer));
else
TextOutW(lpdis->hDC, 45, YOffset, pItemContext->szAppName, wcslen(pItemContext->szAppName));
SetTextColor(lpdis->hDC, preColor);
SetBkColor(lpdis->hDC, preBkColor);
break;
}
break;
case WM_CLOSE:
FreeListItems(hwndDlg);
EndDialog(hwndDlg, 0);
return TRUE;
default:
break;
}
return FALSE;
}
void
FreeMenuItemContext(HMENU hMenu)
{
INT Count;
INT Index;
MENUITEMINFOW mii;
/* get item count */
Count = GetMenuItemCount(hMenu);
if (Count == -1)
return;
/* setup menuitem info */
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA | MIIM_FTYPE;
for(Index = 0; Index < Count; Index++)
{
if (GetMenuItemInfoW(hMenu, Index, TRUE, &mii))
{
if ((mii.fType & MFT_SEPARATOR) || mii.dwItemData == 0)
continue;
HeapFree(GetProcessHeap(), 0, (LPVOID)mii.dwItemData);
}
}
}
static HRESULT WINAPI
SHEOWCm_fnInvokeCommand( IContextMenu2* iface, LPCMINVOKECOMMANDINFO lpici )
{
MENUITEMINFOW mii;
SHEOWImpl *This = impl_from_IContextMenu(iface);
ERR("This %p wId %x count %u verb %x\n", This, This->wId, This->count, LOWORD(lpici->lpVerb));
if (This->wId < LOWORD(lpici->lpVerb))
return E_FAIL;
if (This->wId == LOWORD(lpici->lpVerb))
{
OPENASINFO info;
info.pcszFile = This->szPath;
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
info.pcszClass = NULL;
FreeMenuItemContext(This->hSubMenu);
return SHOpenWithDialog(lpici->hwnd, &info);
}
/* retrieve menu item info */
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA | MIIM_FTYPE;
if (GetMenuItemInfoW(This->hSubMenu, LOWORD(lpici->lpVerb), TRUE, &mii))
{
POPEN_ITEM_CONTEXT pItemContext = (POPEN_ITEM_CONTEXT)mii.dwItemData;
if (pItemContext)
{
/* launch item with specified app */
ExecuteOpenItem(pItemContext, This->szPath);
}
}
/* free menu item context */
FreeMenuItemContext(This->hSubMenu);
return S_OK;
}
static HRESULT WINAPI
SHEOWCm_fnGetCommandString( IContextMenu2* iface, UINT_PTR idCmd, UINT uType,
UINT* pwReserved, LPSTR pszName, UINT cchMax )
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
FIXME("%p %lu %u %p %p %u\n", This,
idCmd, uType, pwReserved, pszName, cchMax );
return E_NOTIMPL;
}
static HRESULT WINAPI SHEOWCm_fnHandleMenuMsg(
IContextMenu2 *iface,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
SHEOWImpl *This = impl_from_IContextMenu(iface);
TRACE("This %p uMsg %x\n",This, uMsg);
return E_NOTIMPL;
}
static const IContextMenu2Vtbl cmvt =
{
SHEOWCm_fnQueryInterface,
SHEOWCm_fnAddRef,
SHEOWCm_fnRelease,
SHEOWCm_fnQueryContextMenu,
SHEOWCm_fnInvokeCommand,
SHEOWCm_fnGetCommandString,
SHEOWCm_fnHandleMenuMsg
};
VOID
GetManufacturer(WCHAR * szAppName, POPEN_ITEM_CONTEXT pContext)
{
UINT VerSize;
DWORD DummyHandle;
LPVOID pBuf;
WORD lang = 0;
WORD code = 0;
LPLANGANDCODEPAGE lplangcode;
WCHAR szBuffer[100];
WCHAR * pResult;
BOOL bResult;
static const WCHAR wFormat[] = L"\\StringFileInfo\\%04x%04x\\CompanyName";
static const WCHAR wTranslation[] = L"VarFileInfo\\Translation";
/* query version info size */
VerSize = GetFileVersionInfoSizeW(szAppName, &DummyHandle);
if (!VerSize)
{
pContext->szManufacturer[0] = 0;
return;
}
/* allocate buffer */
pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, VerSize);
if (!pBuf)
{
pContext->szManufacturer[0] = 0;
return;
}
/* query version info */
if(!GetFileVersionInfoW(szAppName, 0, VerSize, pBuf))
{
pContext->szManufacturer[0] = 0;
HeapFree(GetProcessHeap(), 0, pBuf);
return;
}
/* query lang code */
if(VerQueryValueW(pBuf, wTranslation, (LPVOID *)&lplangcode, &VerSize))
{
/* FIXME find language from current locale / if not available,
* default to english
* for now default to first available language
*/
lang = lplangcode->lang;
code = lplangcode->code;
}
/* set up format */
swprintf(szBuffer, wFormat, lang, code);
/* query manufacturer */
pResult = NULL;
bResult = VerQueryValueW(pBuf, szBuffer, (LPVOID *)&pResult, &VerSize);
if (VerSize && bResult && pResult)
wcscpy(pContext->szManufacturer, pResult);
else
pContext->szManufacturer[0] = 0;
HeapFree(GetProcessHeap(), 0, pBuf);
}
void
InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, WCHAR * szAppName)
{
MENUITEMINFOW mii;
POPEN_ITEM_CONTEXT pItemContext;
LRESULT index;
WCHAR * Offset;
WCHAR Buffer[_MAX_FNAME];
pItemContext = HeapAlloc(GetProcessHeap(), 0, sizeof(OPEN_ITEM_CONTEXT));
if (!pItemContext)
return;
/* store app path */
wcscpy(pItemContext->szAppName, szAppName);
/* null terminate it */
pItemContext->szAppName[MAX_PATH-1] = 0;
/* extract path name */
_wsplitpath(szAppName, NULL, NULL, Buffer, NULL);
Offset = wcsrchr(Buffer, '.');
if (Offset)
Offset[0] = L'\0';
Buffer[0] = towupper(Buffer[0]);
if (pContext->bMenu)
{
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
mii.fType = MFT_STRING; //MFT_OWNERDRAW;
mii.fState = MFS_ENABLED;
mii.wID = pContext->idCmdFirst;
mii.dwTypeData = Buffer;
mii.cch = wcslen(Buffer);
mii.dwItemData = (ULONG_PTR)pItemContext;
wcscpy(pItemContext->szManufacturer, Buffer);
if (InsertMenuItemW(pContext->hMenu, -1, TRUE, &mii))
{
pContext->idCmdFirst++;
pContext->Count++;
}
}
else
{
/* get default icon */
pItemContext->hIcon = ExtractIconW(shell32_hInstance, szAppName, 0);
/* get manufacturer */
GetManufacturer(pItemContext->szAppName, pItemContext);
index = SendMessageW(pContext->hDlgCtrl, LB_ADDSTRING, 0, (LPARAM)Buffer);
if (index != LB_ERR)
SendMessageW(pContext->hDlgCtrl, LB_SETITEMDATA, index, (LPARAM)pItemContext);
}
}
void
AddItemFromProgIDList(POPEN_WITH_CONTEXT pContext, HKEY hKey)
{
FIXME("implement me :)))\n");
}
HANDLE
OpenMRUList(HKEY hKey)
{
MRUINFO info;
if (!hModule)
{
WCHAR szPath[MAX_PATH];
if (!GetSystemDirectoryW(szPath, MAX_PATH))
return 0;
PathAddBackslashW(szPath);
wcscat(szPath, L"comctl32.dll");
hModule = LoadLibraryExW(szPath, NULL, 0);
}
CreateMRUListProcW = (CREATEMRULISTPROCW)GetProcAddress(hModule, MAKEINTRESOURCEA(400));
EnumMRUListW = (ENUMMRULISTW)GetProcAddress(hModule, MAKEINTRESOURCEA(403));
FreeMRUListProc = (FREEMRULIST)GetProcAddress(hModule, MAKEINTRESOURCEA(152));
AddMRUStringW = (ADDMRUSTRINGW)GetProcAddress(hModule, MAKEINTRESOURCEA(401));
if (!CreateMRUListProcW || !EnumMRUListW || !FreeMRUListProc || !AddMRUStringW)
return 0;
/* initialize mru list info */
info.cbSize = sizeof(MRUINFO);
info.uMax = 32;
info.fFlags = MRUF_STRING_LIST;
info.hKey = hKey;
info.lpszSubKey = L"OpenWithList";
info.lpfnCompare = NULL;
/* load list */
return (*CreateMRUListProcW)(&info);
}
void
AddItemFromMRUList(POPEN_WITH_CONTEXT pContext, HKEY hKey)
{
HANDLE hList;
int nItem, nCount, nResult;
WCHAR szBuffer[MAX_PATH];
/* open mru list */
hList = OpenMRUList(hKey);
if (!hList)
return;
/* get list count */
nCount = (*EnumMRUListW)((HANDLE)hList, -1, NULL, 0);
for(nItem = 0; nItem < nCount; nItem++)
{
nResult = (*EnumMRUListW)((HANDLE)hList, nItem, szBuffer, MAX_PATH);
if (nResult <= 0)
continue;
/* make sure its zero terminated */
szBuffer[min(MAX_PATH-1, nResult)] = '\0';
/* insert item */
if (!HideApplicationFromList(szBuffer))
InsertOpenWithItem(pContext, szBuffer);
}
/* free the mru list */
(*FreeMRUList)((HANDLE)hList);
}
void
LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, WCHAR * szExt)
{
HKEY hKey;
HKEY hSubKey;
WCHAR szBuffer[MAX_PATH+10];
WCHAR szResult[100];
DWORD dwSize;
static const WCHAR szOpenWithList[] = L"OpenWithList";
static const WCHAR szOpenWithProgIds[] = L"OpenWithProgIDs";
static const WCHAR szPerceivedType[] = L"PerceivedType";
static const WCHAR szSysFileAssoc[] = L"SystemFileAssociations\\%s";
/* check if extension exists */
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szExt, 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS)
return;
if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS)
{
/* display warning dialog */
pContext->NoOpen = TRUE;
}
/* check if there is a directly available execute key */
if (RegOpenKeyExW(hKey, L"shell\\open\\command", 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
{
DWORD dwBuffer = sizeof(szBuffer);
if (RegGetValueW(hSubKey, NULL, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szBuffer, &dwBuffer) == ERROR_SUCCESS)
{
WCHAR * Ext = wcsrchr(szBuffer, ' ');
if (Ext)
{
/* erase %1 or extra arguments */
Ext[0] = 0;
}
if(!HideApplicationFromList(szBuffer))
InsertOpenWithItem(pContext, szBuffer);
}
RegCloseKey(hSubKey);
}
/* load items from HKCR\Ext\OpenWithList */
if (RegOpenKeyExW(hKey, szOpenWithList, 0, KEY_READ | KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
{
AddItemFromMRUList(pContext, hKey);
RegCloseKey(hSubKey);
}
/* load items from HKCR\Ext\OpenWithProgIDs */
if (RegOpenKeyExW(hKey, szOpenWithProgIds, 0, KEY_READ | KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
{
AddItemFromProgIDList(pContext, hSubKey);
RegCloseKey(hSubKey);
}
/* load items from SystemFileAssociations\Ext key */
swprintf(szResult, szSysFileAssoc, szExt);
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szResult, 0, KEY_READ | KEY_WRITE, &hSubKey) == ERROR_SUCCESS)
{
AddItemFromMRUList(pContext, hSubKey);
RegCloseKey(hSubKey);
}
/* load additional items from referenced PerceivedType*/
dwSize = sizeof(szBuffer);
if (RegGetValueW(hKey, NULL, szPerceivedType, RRF_RT_REG_SZ, NULL, szBuffer, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return;
}
RegCloseKey(hKey);
/* terminate it explictely */
szBuffer[29] = 0;
swprintf(szResult, szSysFileAssoc, szBuffer);
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szResult, 0, KEY_READ | KEY_WRITE, &hSubKey) == ERROR_SUCCESS)
{
AddItemFromMRUList(pContext, hSubKey);
RegCloseKey(hSubKey);
}
}
void
LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, WCHAR * szExt)
{
WCHAR szBuffer[MAX_PATH];
HKEY hKey;
static const WCHAR szOpenWithProgIDs[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s\\OpenWithProgIDs";
static const WCHAR szOpenWithList[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s";
/* handle first progid lists */
swprintf(szBuffer, szOpenWithProgIDs, szExt);
if (RegOpenKeyExW(HKEY_CURRENT_USER, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
AddItemFromProgIDList(pContext, hKey);
RegCloseKey(hKey);
}
/* now handle mru lists */
swprintf(szBuffer, szOpenWithList, szExt);
if (RegOpenKeyExW(HKEY_CURRENT_USER, szBuffer, 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
AddItemFromMRUList(pContext, hKey);
RegCloseKey(hKey);
}
}
HRESULT
SHEOW_LoadOpenWithItems(SHEOWImpl *This, IDataObject *pdtobj)
{
STGMEDIUM medium;
FORMATETC fmt;
HRESULT hr;
LPIDA pida;
LPCITEMIDLIST pidl_folder;
LPCITEMIDLIST pidl_child;
LPCITEMIDLIST pidl;
DWORD dwPath;
LPWSTR szPtr;
static const WCHAR szShortCut[] = { '.','l','n','k', 0 };
fmt.cfFormat = RegisterClipboardFormatW(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 (_ILIsDesktop(pidl) || _ILIsMyDocuments(pidl) || _ILIsControlPanel(pidl) || _ILIsNetHood(pidl) ||
_ILIsBitBucket(pidl) || _ILIsDrive(pidl) || _ILIsCPanelStruct(pidl) || _ILIsFolder(pidl) || _ILIsControlPanel(pidl))
{
TRACE("pidl is a folder\n");
SHFree((void*)pidl);
return E_FAIL;
}
if (!SHGetPathFromIDListW(pidl, This->szPath))
{
SHFree((void*)pidl);
ERR("SHGetPathFromIDListW failed\n");
return E_FAIL;
}
SHFree((void*)pidl);
TRACE("szPath %s\n", debugstr_w(This->szPath));
if (GetBinaryTypeW(This->szPath, &dwPath))
{
TRACE("path is a executable %x\n", dwPath);
return E_FAIL;
}
szPtr = wcsrchr(This->szPath, '.');
if (szPtr)
{
if (!_wcsicmp(szPtr, szShortCut))
{
FIXME("pidl is a shortcut\n");
return E_FAIL;
}
}
return S_OK;
}
static HRESULT WINAPI
SHEOW_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
IDataObject *pdtobj, HKEY hkeyProgID )
{
SHEOWImpl *This = impl_from_IShellExtInit(iface);
TRACE("This %p\n", This);
return SHEOW_LoadOpenWithItems(This, pdtobj);
}
static ULONG WINAPI SHEOW_ExtInit_AddRef(IShellExtInit *iface)
{
SHEOWImpl *This = impl_from_IShellExtInit(iface);
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(count=%u)\n", This, refCount - 1);
return refCount;
}
static ULONG WINAPI SHEOW_ExtInit_Release(IShellExtInit *iface)
{
SHEOWImpl *This = impl_from_IShellExtInit(iface);
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(count=%i)\n", This, refCount + 1);
if (!refCount)
{
HeapFree(GetProcessHeap(),0,This);
}
return refCount;
}
static HRESULT WINAPI
SHEOW_ExtInit_QueryInterface( IShellExtInit* iface, REFIID riid, void** ppvObject )
{
SHEOWImpl *This = impl_from_IShellExtInit(iface);
return SHEOWCm_fnQueryInterface((IContextMenu2*)This, riid, ppvObject);
}
static const IShellExtInitVtbl eivt =
{
SHEOW_ExtInit_QueryInterface,
SHEOW_ExtInit_AddRef,
SHEOW_ExtInit_Release,
SHEOW_ExtInit_Initialize
};
HRESULT WINAPI SHOpenWithDialog(
HWND hwndParent,
const OPENASINFO *poainfo
)
{
MSG msg;
BOOL bRet;
HWND hwnd;
if (poainfo->pcszClass == NULL && poainfo->pcszFile == NULL)
return E_FAIL;
hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG), hwndParent, OpenWithProgrammDlg, (LPARAM)poainfo);
if (hwnd == NULL)
{
ERR("Failed to create dialog\n");
return E_FAIL;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (!IsWindow(hwnd) || !IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return S_OK;
}