| /* | |
| * OLEDLG library | |
| * | |
| * Copyright 1998 Patrik Stridvall | |
| * | |
| * 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 | |
| */ | |
| #define COBJMACROS | |
| #include <stdarg.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winerror.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "oledlg.h" | |
| #include "ole2.h" | |
| #include "oledlg_private.h" | |
| #include "resource.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); | |
| HINSTANCE OLEDLG_hInstance = 0; | |
| UINT cf_embed_source; | |
| UINT cf_embedded_object; | |
| UINT cf_link_source; | |
| UINT cf_object_descriptor; | |
| UINT cf_link_src_descriptor; | |
| UINT cf_ownerlink; | |
| UINT cf_filename; | |
| UINT cf_filenamew; | |
| UINT oleui_msg_help; | |
| UINT oleui_msg_enddialog; | |
| static void register_clipboard_formats(void) | |
| { | |
| /* These used to be declared in olestd.h, but that seems to have been removed from the api */ | |
| static const WCHAR CF_EMBEDSOURCEW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 }; | |
| static const WCHAR CF_EMBEDDEDOBJECTW[] = { 'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0 }; | |
| static const WCHAR CF_LINKSOURCEW[] = { 'L','i','n','k',' ','S','o','u','r','c','e',0 }; | |
| static const WCHAR CF_OBJECTDESCRIPTORW[] = { 'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0 }; | |
| static const WCHAR CF_LINKSRCDESCRIPTORW[] = { 'L','i','n','k',' ','S','o','u','r','c','e',' ','D','e','s','c','r','i','p','t','o','r',0 }; | |
| static const WCHAR CF_OWNERLINKW[] = { 'O','w','n','e','r','L','i','n','k',0 }; | |
| static const WCHAR CF_FILENAMEW[] = { 'F','i','l','e','N','a','m','e',0 }; | |
| static const WCHAR CF_FILENAMEWW[] = { 'F','i','l','e','N','a','m','e','W',0 }; | |
| /* Load in the same order as native to make debugging easier */ | |
| cf_object_descriptor = RegisterClipboardFormatW(CF_OBJECTDESCRIPTORW); | |
| cf_link_src_descriptor = RegisterClipboardFormatW(CF_LINKSRCDESCRIPTORW); | |
| cf_embed_source = RegisterClipboardFormatW(CF_EMBEDSOURCEW); | |
| cf_embedded_object = RegisterClipboardFormatW(CF_EMBEDDEDOBJECTW); | |
| cf_link_source = RegisterClipboardFormatW(CF_LINKSOURCEW); | |
| cf_ownerlink = RegisterClipboardFormatW(CF_OWNERLINKW); | |
| cf_filename = RegisterClipboardFormatW(CF_FILENAMEW); | |
| cf_filenamew = RegisterClipboardFormatW(CF_FILENAMEWW); | |
| } | |
| static void register_messages(void) | |
| { | |
| oleui_msg_help = RegisterWindowMessageW(SZOLEUI_MSG_HELPW); | |
| oleui_msg_enddialog = RegisterWindowMessageW(SZOLEUI_MSG_ENDDIALOGW); | |
| } | |
| /*********************************************************************** | |
| * DllMain | |
| */ | |
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) | |
| { | |
| TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad); | |
| switch(fdwReason) { | |
| case DLL_PROCESS_ATTACH: | |
| DisableThreadLibraryCalls(hinstDLL); | |
| OLEDLG_hInstance = hinstDLL; | |
| register_clipboard_formats(); | |
| register_messages(); | |
| break; | |
| } | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * OleUIAddVerbMenuA (OLEDLG.1) | |
| */ | |
| BOOL WINAPI OleUIAddVerbMenuA(IOleObject *object, LPCSTR shorttype, | |
| HMENU hMenu, UINT uPos, UINT uIDVerbMin, UINT uIDVerbMax, | |
| BOOL addConvert, UINT idConvert, HMENU *lphMenu) | |
| { | |
| WCHAR *shorttypeW = NULL; | |
| BOOL ret; | |
| TRACE("(%p, %s, %p, %d, %d, %d, %d, %d, %p)\n", object, debugstr_a(shorttype), | |
| hMenu, uPos, uIDVerbMin, uIDVerbMax, addConvert, idConvert, lphMenu); | |
| if (shorttype) | |
| { | |
| INT len = MultiByteToWideChar(CP_ACP, 0, shorttype, -1, NULL, 0); | |
| shorttypeW = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | |
| if (shorttypeW) | |
| MultiByteToWideChar(CP_ACP, 0, shorttype, -1, shorttypeW, len); | |
| } | |
| ret = OleUIAddVerbMenuW(object, shorttypeW, hMenu, uPos, uIDVerbMin, uIDVerbMax, | |
| addConvert, idConvert, lphMenu); | |
| HeapFree(GetProcessHeap(), 0, shorttypeW); | |
| return ret; | |
| } | |
| static inline BOOL is_verb_in_range(const OLEVERB *verb, UINT idmin, UINT idmax) | |
| { | |
| if (idmax == 0) return TRUE; | |
| return (verb->lVerb + idmin <= idmax); | |
| } | |
| static HRESULT get_next_insertable_verb(IEnumOLEVERB *enumverbs, UINT idmin, UINT idmax, OLEVERB *verb) | |
| { | |
| memset(verb, 0, sizeof(*verb)); | |
| while (IEnumOLEVERB_Next(enumverbs, 1, verb, NULL) == S_OK) { | |
| if (is_verb_in_range(verb, idmin, idmax) && (verb->grfAttribs & OLEVERBATTRIB_ONCONTAINERMENU)) | |
| return S_OK; | |
| CoTaskMemFree(verb->lpszVerbName); | |
| memset(verb, 0, sizeof(*verb)); | |
| } | |
| return S_FALSE; | |
| } | |
| static void insert_verb_to_menu(HMENU menu, UINT idmin, const OLEVERB *verb) | |
| { | |
| InsertMenuW(menu, ~0, verb->fuFlags | MF_BYPOSITION | MF_STRING, verb->lVerb + idmin, verb->lpszVerbName); | |
| } | |
| /*********************************************************************** | |
| * OleUIAddVerbMenuW (OLEDLG.14) | |
| */ | |
| BOOL WINAPI OleUIAddVerbMenuW(IOleObject *object, LPCWSTR shorttype, | |
| HMENU hMenu, UINT uPos, UINT idmin, UINT idmax, BOOL addConvert, UINT idConvert, HMENU *ret_submenu) | |
| { | |
| IEnumOLEVERB *enumverbs = NULL; | |
| LPOLESTR usertype = NULL; | |
| OLEVERB firstverb, verb; | |
| WCHAR *objecttype; | |
| WCHAR resstrW[32]; /* should be enough */ | |
| DWORD_PTR args[2]; | |
| BOOL singleverb; | |
| HMENU submenu; | |
| WCHAR *str; | |
| TRACE("(%p, %s, %p, %d, %d, %d, %d, %d, %p)\n", object, debugstr_w(shorttype), | |
| hMenu, uPos, idmin, idmax, addConvert, idConvert, ret_submenu); | |
| if (ret_submenu) | |
| *ret_submenu = NULL; | |
| if (!hMenu || !ret_submenu) | |
| return FALSE; | |
| /* check if we can get verbs at all */ | |
| if (object) | |
| IOleObject_EnumVerbs(object, &enumverbs); | |
| LoadStringW(OLEDLG_hInstance, IDS_VERBMENU_OBJECT, resstrW, sizeof(resstrW)/sizeof(WCHAR)); | |
| /* no object, or object without enumeration support */ | |
| if (!object || !enumverbs) { | |
| RemoveMenu(hMenu, uPos, MF_BYPOSITION); | |
| InsertMenuW(hMenu, uPos, MF_BYPOSITION|MF_STRING|MF_GRAYED, idmin, resstrW); | |
| return FALSE; | |
| } | |
| /* root entry string */ | |
| if (!shorttype && (IOleObject_GetUserType(object, USERCLASSTYPE_SHORT, &usertype) == S_OK)) | |
| objecttype = usertype; | |
| else | |
| objecttype = (WCHAR*)shorttype; | |
| /* iterate through verbs */ | |
| /* find first suitable verb */ | |
| get_next_insertable_verb(enumverbs, idmin, idmax, &firstverb); | |
| singleverb = get_next_insertable_verb(enumverbs, idmin, idmax, &verb) != S_OK; | |
| if (singleverb && !addConvert) { | |
| LoadStringW(OLEDLG_hInstance, IDS_VERBMENU_SINGLEVERB_OBJECT, resstrW, sizeof(resstrW)/sizeof(WCHAR)); | |
| args[0] = (DWORD_PTR)firstverb.lpszVerbName; | |
| args[1] = (DWORD_PTR)objecttype; | |
| FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY, | |
| resstrW, 0, 0, (WCHAR*)&str, 0, (__ms_va_list*)args); | |
| RemoveMenu(hMenu, uPos, MF_BYPOSITION); | |
| InsertMenuW(hMenu, uPos, MF_BYPOSITION|MF_STRING, idmin, str); | |
| CoTaskMemFree(firstverb.lpszVerbName); | |
| HeapFree(GetProcessHeap(), 0, str); | |
| IEnumOLEVERB_Release(enumverbs); | |
| CoTaskMemFree(usertype); | |
| return TRUE; | |
| } | |
| submenu = CreatePopupMenu(); | |
| insert_verb_to_menu(submenu, idmin, &firstverb); | |
| CoTaskMemFree(firstverb.lpszVerbName); | |
| if (!singleverb) { | |
| insert_verb_to_menu(submenu, idmin, &verb); | |
| CoTaskMemFree(verb.lpszVerbName); | |
| } | |
| while (get_next_insertable_verb(enumverbs, idmin, idmax, &verb) == S_OK) { | |
| insert_verb_to_menu(submenu, idmin, &verb); | |
| CoTaskMemFree(verb.lpszVerbName); | |
| } | |
| /* convert verb is at the bottom of a popup, separated from verbs */ | |
| if (addConvert) { | |
| LoadStringW(OLEDLG_hInstance, IDS_VERBMENU_CONVERT, resstrW, sizeof(resstrW)/sizeof(WCHAR)); | |
| InsertMenuW(submenu, ~0, MF_BYPOSITION|MF_SEPARATOR, 0, NULL); | |
| InsertMenuW(submenu, ~0, MF_BYPOSITION|MF_STRING, idConvert, resstrW); | |
| } | |
| if (submenu) | |
| *ret_submenu = submenu; | |
| /* now submenu is ready, add root entry to original menu, attach submenu */ | |
| LoadStringW(OLEDLG_hInstance, IDS_VERBMENU_OBJECT_WITH_NAME, resstrW, sizeof(resstrW)/sizeof(WCHAR)); | |
| args[0] = (DWORD_PTR)objecttype; | |
| FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY, | |
| resstrW, 0, 0, (WCHAR*)&str, 0, (__ms_va_list*)args); | |
| InsertMenuW(hMenu, uPos, MF_BYPOSITION|MF_POPUP|MF_STRING, (UINT_PTR)submenu, str); | |
| HeapFree(GetProcessHeap(), 0, str); | |
| IEnumOLEVERB_Release(enumverbs); | |
| CoTaskMemFree(usertype); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * OleUICanConvertOrActivateAs (OLEDLG.2) | |
| */ | |
| BOOL WINAPI OleUICanConvertOrActivateAs( | |
| REFCLSID rClsid, BOOL fIsLinkedObject, WORD wFormat) | |
| { | |
| FIXME("(%p, %d, %hd): stub\n", | |
| rClsid, fIsLinkedObject, wFormat | |
| ); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIInsertObjectW (OLEDLG.20) | |
| */ | |
| UINT WINAPI OleUIInsertObjectW(LPOLEUIINSERTOBJECTW lpOleUIInsertObject) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIInsertObject); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIEditLinksA (OLEDLG.5) | |
| */ | |
| UINT WINAPI OleUIEditLinksA(LPOLEUIEDITLINKSA lpOleUIEditLinks) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIEditLinks); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIEditLinksW (OLEDLG.19) | |
| */ | |
| UINT WINAPI OleUIEditLinksW(LPOLEUIEDITLINKSW lpOleUIEditLinks) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIEditLinks); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIChangeIconA (OLEDLG.6) | |
| */ | |
| UINT WINAPI OleUIChangeIconA( | |
| LPOLEUICHANGEICONA lpOleUIChangeIcon) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIChangeIcon); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIChangeIconW (OLEDLG.16) | |
| */ | |
| UINT WINAPI OleUIChangeIconW( | |
| LPOLEUICHANGEICONW lpOleUIChangeIcon) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIChangeIcon); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIConvertA (OLEDLG.7) | |
| */ | |
| UINT WINAPI OleUIConvertA(LPOLEUICONVERTA lpOleUIConvert) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIConvert); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIConvertW (OLEDLG.18) | |
| */ | |
| UINT WINAPI OleUIConvertW(LPOLEUICONVERTW lpOleUIConvert) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIConvert); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIBusyA (OLEDLG.8) | |
| */ | |
| UINT WINAPI OleUIBusyA(LPOLEUIBUSYA lpOleUIBusy) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIBusy); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIBusyW (OLEDLG.15) | |
| */ | |
| UINT WINAPI OleUIBusyW(LPOLEUIBUSYW lpOleUIBusy) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIBusy); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIUpdateLinksA (OLEDLG.9) | |
| */ | |
| BOOL WINAPI OleUIUpdateLinksA( | |
| LPOLEUILINKCONTAINERA lpOleUILinkCntr, | |
| HWND hwndParent, LPSTR lpszTitle, INT cLinks) | |
| { | |
| FIXME("(%p, %p, %s, %d): stub\n", | |
| lpOleUILinkCntr, hwndParent, debugstr_a(lpszTitle), cLinks | |
| ); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIUpdateLinksW (OLEDLG.23) | |
| */ | |
| BOOL WINAPI OleUIUpdateLinksW( | |
| LPOLEUILINKCONTAINERW lpOleUILinkCntr, | |
| HWND hwndParent, LPWSTR lpszTitle, INT cLinks) | |
| { | |
| FIXME("(%p, %p, %s, %d): stub\n", | |
| lpOleUILinkCntr, hwndParent, debugstr_w(lpszTitle), cLinks | |
| ); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIPromptUserA (OLEDLG.10) | |
| */ | |
| INT WINAPIV OleUIPromptUserA( | |
| INT nTemplate, HWND hwndParent, ...) | |
| { | |
| FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIPromptUserW (OLEDLG.13) | |
| */ | |
| INT WINAPIV OleUIPromptUserW( | |
| INT nTemplate, HWND hwndParent, ...) | |
| { | |
| FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIObjectPropertiesA (OLEDLG.11) | |
| */ | |
| UINT WINAPI OleUIObjectPropertiesA( | |
| LPOLEUIOBJECTPROPSA lpOleUIObjectProps) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIObjectProps); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIObjectPropertiesW (OLEDLG.21) | |
| */ | |
| UINT WINAPI OleUIObjectPropertiesW( | |
| LPOLEUIOBJECTPROPSW lpOleUIObjectProps) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIObjectProps); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIChangeSourceA (OLEDLG.12) | |
| */ | |
| UINT WINAPI OleUIChangeSourceA( | |
| LPOLEUICHANGESOURCEA lpOleUIChangeSource) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIChangeSource); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleUIChangeSourceW (OLEDLG.17) | |
| */ | |
| UINT WINAPI OleUIChangeSourceW( | |
| LPOLEUICHANGESOURCEW lpOleUIChangeSource) | |
| { | |
| FIXME("(%p): stub\n", lpOleUIChangeSource); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return OLEUI_FALSE; | |
| } |