diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GvimExt/GvimExt.reg | 20 | ||||
-rw-r--r-- | src/GvimExt/Make_bc5.mak | 43 | ||||
-rw-r--r-- | src/GvimExt/Make_ming.mak | 63 | ||||
-rw-r--r-- | src/GvimExt/Makefile | 35 | ||||
-rw-r--r-- | src/GvimExt/README.txt | 94 | ||||
-rw-r--r-- | src/GvimExt/gvimext.cpp | 979 | ||||
-rw-r--r-- | src/GvimExt/gvimext.def | 8 | ||||
-rw-r--r-- | src/GvimExt/gvimext.h | 164 | ||||
-rw-r--r-- | src/GvimExt/gvimext.inf | 22 | ||||
-rw-r--r-- | src/GvimExt/gvimext.rc | 111 | ||||
-rw-r--r-- | src/GvimExt/gvimext_ming.def | 10 | ||||
-rw-r--r-- | src/GvimExt/gvimext_ming.rc | 45 | ||||
-rw-r--r-- | src/GvimExt/resource.h | 15 | ||||
-rw-r--r-- | src/GvimExt/uninst.bat | 1 | ||||
-rw-r--r-- | src/edit.c | 34 | ||||
-rw-r--r-- | src/eval.c | 2 | ||||
-rw-r--r-- | src/ex_cmds2.c | 20 | ||||
-rw-r--r-- | src/ex_getln.c | 4 | ||||
-rw-r--r-- | src/fileio.c | 6 | ||||
-rw-r--r-- | src/getchar.c | 25 | ||||
-rw-r--r-- | src/misc1.c | 3 | ||||
-rw-r--r-- | src/option.c | 2 | ||||
-rw-r--r-- | src/option.h | 3 | ||||
-rw-r--r-- | src/os_win32.c | 44 | ||||
-rw-r--r-- | src/po/es.po | 1698 | ||||
-rw-r--r-- | src/vim.h | 1 |
26 files changed, 2583 insertions, 869 deletions
diff --git a/src/GvimExt/GvimExt.reg b/src/GvimExt/GvimExt.reg new file mode 100644 index 0000000000..db49d24bde --- /dev/null +++ b/src/GvimExt/GvimExt.reg @@ -0,0 +1,20 @@ +REGEDIT4 + +[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}] + @="Vim Shell Extension" +[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32] + @="gvimext.dll" + "ThreadingModel"="Apartment" + +[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\gvim] + @="{51EEE242-AD87-11d3-9C1E-0090278BBD99}" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved] + "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension" + +[HKEY_LOCAL_MACHINE\Software\Vim\Gvim] + "path"="gvim.exe" + +[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 7.0aa] + "DisplayName"="Vim 7.0aa: Edit with Vim popup menu entry" + "UninstallString"="uninstal.exe" diff --git a/src/GvimExt/Make_bc5.mak b/src/GvimExt/Make_bc5.mak new file mode 100644 index 0000000000..363c6d608f --- /dev/null +++ b/src/GvimExt/Make_bc5.mak @@ -0,0 +1,43 @@ +### USEDLL no for statically linked version of run-time, yes for DLL runtime +### BOR path to root of Borland C install (c:\bc5) + +### (requires cc3250.dll be available in %PATH%) +!if ("$(USEDLL)"=="") +USEDLL = no +!endif + +### BOR: root of the BC installation +!if ("$(BOR)"=="") +BOR = c:\bc5 +!endif + +CC = $(BOR)\bin\Bcc32 +BRC = $(BOR)\bin\brc32 +LINK = $(BOR)\BIN\ILink32 +INCLUDE = $(BOR)\include;. +LIB = $(BOR)\lib + +!if ("$(USEDLL)"=="yes") +RT_DEF = -D_RTLDLL +RT_LIB = cw32i.lib +!else +RT_DEF = +RT_LIB = cw32.lib +!endif + + +all : gvimext.dll + +gvimext.obj : gvimext.cpp gvimext.h + $(CC) -tWD -I$(INCLUDE) -c -DFEAT_GETTEXT $(RT_DEF) -w- gvimext.cpp + +gvimext.res : gvimext.rc + $(BRC) -r gvimext.rc + +gvimext.dll : gvimext.obj gvimext.res + $(LINK) -L$(LIB) -aa gvimext.obj, gvimext.dll, , c0d32.obj $(RT_LIB) import32.lib, gvimext.def, gvimext.res + +clean : + -@del gvimext.obj + -@del gvimext.res + -@del gvimext.dll diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak new file mode 100644 index 0000000000..3456255248 --- /dev/null +++ b/src/GvimExt/Make_ming.mak @@ -0,0 +1,63 @@ +# Project: gvimext +# Generates gvimext.dll with gcc. +# Can be used for Cygwin and MingW (MingW ignores -mno-cygwin) +# +# Originally, the DLL base address was fixed: -Wl,--image-base=0x1C000000 +# Now it is allocated dymanically by the linker by evaluating all DLLs +# already loaded in memory. The binary image contains as well information +# for automatic pseudo-rebasing, if needed by the system. ALV 2004-02-29 + +# If cross-compiling set this to yes, else set it to no +CROSS = no +#CROSS = yes +# For the old MinGW 2.95 (the one you get e.g. with debian woody) +# set the following variable to yes and check if the executables are +# really named that way. +# If you have a newer MinGW or you are using cygwin set it to no and +# check also the executables +MINGWOLD = no + +ifeq ($(CROSS),yes) +ifeq ($(MINGWOLD),yes) +CXX = i586-mingw32msvc-g++ +CXXFLAGS := -O2 -mno-cygwin -fvtable-thunks +WINDRES = i586-mingw32msvc-windres +else +CXX = i386-mingw32msvc-g++ +CXXFLAGS := -O2 -mno-cygwin +WINDRES = i386-mingw32msvc-windres +endif +else +CXX := g++.exe +WINDRES := windres.exe +CXXFLAGS := -O2 -mno-cygwin +endif +LIBS := -luuid +RES := gvimext.res +DEFFILE = gvimext_ming.def +OBJ := gvimext.o + +DLL := gvimext.dll + +.PHONY: all all-before all-after clean clean-custom + +all: all-before $(DLL) all-after + +$(DLL): $(OBJ) $(RES) $(DEFFILE) + $(CXX) -shared $(CXXFLAGS) -s -o $@ \ + -Wl,--enable-auto-image-base \ + -Wl,--enable-auto-import \ + -Wl,--whole-archive \ + $^ \ + -Wl,--no-whole-archive \ + $(LIBS) + +gvimext.o: gvimext.cpp + $(CXX) $(CXXFLAGS) -DFEAT_GETTEXT -c $? -o $@ + +$(RES): gvimext_ming.rc + $(WINDRES) --input-format=rc --output-format=coff -DMING $? -o $@ + +clean: clean-custom + $(RM) $(OBJ) $(RES) $(DLL) + diff --git a/src/GvimExt/Makefile b/src/GvimExt/Makefile new file mode 100644 index 0000000000..d1bd2d1da7 --- /dev/null +++ b/src/GvimExt/Makefile @@ -0,0 +1,35 @@ +# Makefile for GvimExt, using MSVC +# Options: +# DEBUG=yes Build debug version (for VC7 and maybe later) +# + +TARGETOS=BOTH +APPVER=4.0 + +!if "$(DEBUG)" != "yes" +NODEBUG = 1 +!endif + +!include <win32.mak> + +all: gvimext.dll + +gvimext.dll: gvimext.obj \ + gvimext.res + $(implib) /NOLOGO -machine:$(CPU) -def:gvimext.def $** -out:gvimext.lib + $(link) $(dlllflags) -base:0x1C000000 -out:$*.dll $** $(olelibsdll) shell32.lib gvimext.lib comctl32.lib gvimext.exp + +gvimext.obj: gvimext.h + +.cpp.obj: + $(cc) $(cflags) -DFEAT_GETTEXT $(cvarsdll) $*.cpp + +gvimext.res: gvimext.rc + $(rc) $(rcflags) $(rcvars) gvimext.rc + +clean: + - if exist gvimext.dll del gvimext.dll + - if exist gvimext.lib del gvimext.lib + - if exist gvimext.exp del gvimext.exp + - if exist gvimext.obj del gvimext.obj + - if exist gvimext.res del gvimext.res diff --git a/src/GvimExt/README.txt b/src/GvimExt/README.txt new file mode 100644 index 0000000000..dd9fcba7d9 --- /dev/null +++ b/src/GvimExt/README.txt @@ -0,0 +1,94 @@ +README.txt for the gvimext DLL. + +Written by Tianmiao Hu. Edited by Bram Moolenaar. + + +INSTALLATION + +To install the "Edit with Vim" popup menu entry, it is recommended to use the +"install.exe" program. It will ask you a few questions and install the needed +registry entries. + +In special situations you might want to make changes by hand. Check these +items: +- The gvimext.dll, gvim.exe and uninstal.exe either need to be in the search + path, or you have to set the full path in the registry entries. You could + move the gvimext.dll to the "windows\system" or "windows\system32" + directory, where the other DLL files are. +- You can find the names of the used registry entries in the file + "GvimExt.reg". You can edit this file to add the paths. To install the + registry entries, right-click the gvimext.reg file and choose the "merge" + menu option. +- The registry key [HKEY_LOCAL_MACHINE\Software\Vim\Gvim] is used by the + gvimext.dll. The value "path" specifies the location of "gvim.exe". If + gvim.exe is in the search path, the path can be omitted. The value "lang" + can be used to set the language, for example "de" for German. If "lang" is + omitted, the language set for Windows will be used. + +It is the preferred method to keep gvim.exe with the runtime files, so that +Vim will find them (also the translated menu items are there). + + +UNINSTALLATION + +To uninstall the "Edit with Vim" popup menu entry, it is recommended to use +the "uninstal.exe" program. + +In special situations you might want to uninstall by hand: +- Open the registry by running regedit.exe. +- Delete all the keys listed in GvimExt.reg, except this one: + [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved] + For this key, only delete one value: + "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension" +- Delete the gvimext.dll, if you want. You might need to reboot the machine + in order to remove this file. A quick way is to log off and re-login. + +Another method is by using the uninst.bat script: + uninst gvimext.inf +This batch file will remove all the registry keys from the system. Then you +can remove the gvimext.dll file. +Note: In order for this batch file to work, you must have two system files: +rundll32.exe and setupapi.dll. I believe you will have rundll32.exe in your +system. I know windows nt 4.0 with the service pack 4 has setupapi.dll. My +windows 95 has setupapi.dll. I find that the internet explorer 4.0 comes with +the setupapi.dll in file Ie4_5.cab. + +If you do encounter problems running this script, then probably you need to +modify the uninst.bat to suit to your system. Basically, you must find out +where are the locations for your rundll32.exe and setupapi.dll files. In +windows nt, both files are under c:\winnt\system32 directory. In my windows 95 +system, I got setupapi.dll at c:\windows\system and rundll32.exe at +c:\windows. So you might want to try something like: + rundll32.exe c:\windows\system\setupapi.dll,InstallHinfSection DefaultUninstall 128 %1 +where %1 can be substitued by gvimext.inf + + +THE SOURCE CODE + +I have provided the source code here in hope that gvim users around world can +further enhance this little dll. I believe the only thing you need to change +is gvimext.cpp file. The important two functions you need to look at are +QueryContextMenu and InvokeCommand. You can modify right-click menus in the +QueryContextMenu function and invoke gvim in the InvokeCommand function. Note +the selected files can be accessed from the DragQueryFile function. I am not +familiar with the invoking options for gvim. I believe there are some +improvements that can be made on that side. + +I use MS Visual C++ 6.0's nmake to make the gvimext.dll. I don't have a +chance to try earlier versions of MSVC. The files that are required for build +are: + gvimext.cpp + gvimext.h + gvimext.def + gvimext.rc + resource.h + Makefile + +To compile the DLL from the command line: + vcvars32 + nmake -f Makefile + +If you did something interesting to this dll, please let me know +@ tianmiao@acm.org. + +Happy vimming!!! diff --git a/src/GvimExt/gvimext.cpp b/src/GvimExt/gvimext.cpp new file mode 100644 index 0000000000..57fbf81199 --- /dev/null +++ b/src/GvimExt/gvimext.cpp @@ -0,0 +1,979 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved gvimext by Tianmiao Hu + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * gvimext is a DLL which is used for the "Edit with Vim" context menu + * extension. It implements a MS defined interface with the Shell. + * + * If you have any questions or any suggestions concerning gvimext, please + * contact Tianmiao Hu: tianmiao@acm.org. + */ + +#include "gvimext.h" + +#ifdef __BORLANDC__ +# include <dir.h> +# ifndef _strnicmp +# define _strnicmp(a, b, c) strnicmp((a), (b), (c)) +# endif +#else +static char *searchpath(char *name); +#endif + +// Always get an error while putting the following stuff to the +// gvimext.h file as class protected variables, give up and +// declare them as global stuff +FORMATETC fmte = {CF_HDROP, + (DVTARGETDEVICE FAR *)NULL, + DVASPECT_CONTENT, + -1, + TYMED_HGLOBAL + }; +STGMEDIUM medium; +HRESULT hres = 0; +UINT cbFiles = 0; + +// +// Get the name of the Gvim executable to use, with the path. +// When "runtime" is non-zero, we were called to find the runtime directory. +// Returns the path in name[MAX_PATH]. It's empty when it fails. +// + static void +getGvimName(char *name, int runtime) +{ + HKEY keyhandle; + DWORD hlen; + + // Get the location of gvim from the registry. + name[0] = 0; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_READ, &keyhandle) == ERROR_SUCCESS) + { + hlen = MAX_PATH; + if (RegQueryValueEx(keyhandle, "path", 0, NULL, (BYTE *)name, &hlen) + != ERROR_SUCCESS) + name[0] = 0; + else + name[hlen] = 0; + RegCloseKey(keyhandle); + } + + // Registry didn't work, use the search path. + if (name[0] == 0) + strcpy(name, searchpath("gvim.exe")); + + if (!runtime) + { + // Only when looking for the executable, not the runtime dir, we can + // search for the batch file or a name without a path. + if (name[0] == 0) + strcpy(name, searchpath("gvim.bat")); + if (name[0] == 0) + strcpy(name, "gvim"); // finds gvim.bat or gvim.exe + + // avoid that Vim tries to expand wildcards in the file names + strcat(name, " --literal"); + } +} + +// +// Get the Vim runtime directory into buf[MAX_PATH]. +// The result is empty when it failed. +// When it works, the path ends in a slash or backslash. +// + static void +getRuntimeDir(char *buf) +{ + int idx; + + getGvimName(buf, 1); + if (buf[0] != 0) + { + // When no path found, use the search path to expand it. + if (strchr(buf, '/') == NULL && strchr(buf, '\\') == NULL) + strcpy(buf, searchpath(buf)); + + // remove "gvim.exe" from the end + for (idx = strlen(buf) - 1; idx >= 0; idx--) + if (buf[idx] == '\\' || buf[idx] == '/') + { + buf[idx + 1] = 0; + break; + } + } +} + +// +// GETTEXT: translated messages and menu entries +// +#ifndef FEAT_GETTEXT +# define _(x) x +#else +# define _(x) (*dyn_libintl_gettext)(x) +# define VIMPACKAGE "vim" +# ifndef GETTEXT_DLL +# define GETTEXT_DLL "libintl.dll" +# endif + +// Dummy functions +static char *null_libintl_gettext(const char *); +static char *null_libintl_textdomain(const char *); +static char *null_libintl_bindtextdomain(const char *, const char *); +static int dyn_libintl_init(char *dir); +static void dyn_libintl_end(void); + +static HINSTANCE hLibintlDLL = 0; +static char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext; +static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain; +static char *(*dyn_libintl_bindtextdomain)(const char *, const char *) + = null_libintl_bindtextdomain; + +// +// Attempt to load libintl.dll. If it doesn't work, use dummy functions. +// "dir" is the directory where the libintl.dll might be. +// Return 1 for success, 0 for failure. +// + static int +dyn_libintl_init(char *dir) +{ + int i; + static struct + { + char *name; + FARPROC *ptr; + } libintl_entry[] = + { + {"gettext", (FARPROC*)&dyn_libintl_gettext}, + {"textdomain", (FARPROC*)&dyn_libintl_textdomain}, + {"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain}, + {NULL, NULL} + }; + + // No need to initialize twice. + if (hLibintlDLL) + return 1; + + // Load gettext library, first try the Vim runtime directory, then search + // the path. + strcat(dir, GETTEXT_DLL); + hLibintlDLL = LoadLibrary(dir); + if (!hLibintlDLL) + { + hLibintlDLL = LoadLibrary(GETTEXT_DLL); + if (!hLibintlDLL) + return 0; + } + + // Get the addresses of the functions we need. + for (i = 0; libintl_entry[i].name != NULL + && libintl_entry[i].ptr != NULL; ++i) + { + if ((*libintl_entry[i].ptr = GetProcAddress(hLibintlDLL, + libintl_entry[i].name)) == NULL) + { + dyn_libintl_end(); + return 0; + } + } + return 1; +} + + static void +dyn_libintl_end(void) +{ + if (hLibintlDLL) + FreeLibrary(hLibintlDLL); + hLibintlDLL = NULL; + dyn_libintl_gettext = null_libintl_gettext; + dyn_libintl_textdomain = null_libintl_textdomain; + dyn_libintl_bindtextdomain = null_libintl_bindtextdomain; +} + + static char * +null_libintl_gettext(const char *msgid) +{ + return (char *)msgid; +} + + static char * +null_libintl_bindtextdomain(const char *domainname, const char *dirname) +{ + return NULL; +} + + static char * +null_libintl_textdomain(const char* domainname) +{ + return NULL; +} + +// +// Setup for translating strings. +// + static void +dyn_gettext_load(void) +{ + char szBuff[MAX_PATH]; + char szLang[MAX_PATH]; + DWORD len; + HKEY keyhandle; + int gotlang = 0; + + strcpy(szLang, "LANG="); + + // First try getting the language from the registry, this can be + // used to overrule the system language. + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_READ, &keyhandle) == ERROR_SUCCESS) + { + len = MAX_PATH; + if (RegQueryValueEx(keyhandle, "lang", 0, NULL, (BYTE*)szBuff, &len) + == ERROR_SUCCESS) + { + szBuff[len] = 0; + strcat(szLang, szBuff); + gotlang = 1; + } + RegCloseKey(keyhandle); + } + + if (!gotlang && getenv("LANG") == NULL) + { + // Get the language from the system. + // Could use LOCALE_SISO639LANGNAME, but it's not in Win95. + // LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use + // only the first two. + len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, + (LPTSTR)szBuff, MAX_PATH); + if (len >= 2 && _strnicmp(szBuff, "en", 2) != 0) + { + // There are a few exceptions (probably more) + if (_strnicmp(szBuff, "cht", 3) == 0 + || _strnicmp(szBuff, "zht", 3) == 0) + strcpy(szBuff, "zh_TW"); + else if (_strnicmp(szBuff, "chs", 3) == 0 + || _strnicmp(szBuff, "zhc", 3) == 0) + strcpy(szBuff, "zh_CN"); + else if (_strnicmp(szBuff, "jp", 2) == 0) + strcpy(szBuff, "ja"); + else + szBuff[2] = 0; // truncate to two-letter code + strcat(szLang, szBuff); + gotlang = 1; + } + } + if (gotlang) + putenv(szLang); + + // Try to locate the runtime files. The path is used to find libintl.dll + // and the vim.mo files. + getRuntimeDir(szBuff); + if (szBuff[0] != 0) + { + len = strlen(szBuff); + if (dyn_libintl_init(szBuff)) + { + strcpy(szBuff + len, "lang"); + + (*dyn_libintl_bindtextdomain)(VIMPACKAGE, szBuff); + (*dyn_libintl_textdomain)(VIMPACKAGE); + } + } +} + + static void +dyn_gettext_free(void) +{ + dyn_libintl_end(); +} +#endif // FEAT_GETTEXT + +// +// Global variables +// +UINT g_cRefThisDll = 0; // Reference count of this DLL. +HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself. + + +//--------------------------------------------------------------------------- +// DllMain +//--------------------------------------------------------------------------- +extern "C" int APIENTRY +DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + // Extension DLL one-time initialization + g_hmodThisDll = hInstance; + break; + + case DLL_PROCESS_DETACH: + break; + } + + return 1; // ok +} + + static void +inc_cRefThisDLL() +{ +#ifdef FEAT_GETTEXT + if (g_cRefThisDll == 0) + dyn_gettext_load(); +#endif + InterlockedIncrement((LPLONG)&g_cRefThisDll); +} + + static void +dec_cRefThisDLL() +{ +#ifdef FEAT_GETTEXT + if (InterlockedDecrement((LPLONG)&g_cRefThisDll) == 0) + dyn_gettext_free(); +#else + InterlockedDecrement((LPLONG)&g_cRefThisDll); +#endif +} + +//--------------------------------------------------------------------------- +// DllCanUnloadNow +//--------------------------------------------------------------------------- + +STDAPI DllCanUnloadNow(void) +{ + return (g_cRefThisDll == 0 ? S_OK : S_FALSE); +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) +{ + *ppvOut = NULL; + + if (IsEqualIID(rclsid, CLSID_ShellExtension)) + { + CShellExtClassFactory *pcf = new CShellExtClassFactory; + + return pcf->QueryInterface(riid, ppvOut); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +CShellExtClassFactory::CShellExtClassFactory() +{ + m_cRef = 0L; + + inc_cRefThisDLL(); +} + +CShellExtClassFactory::~CShellExtClassFactory() +{ + dec_cRefThisDLL(); +} + +STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, + LPVOID FAR *ppv) +{ + *ppv = NULL; + + // Any interface on this object is the object pointer + + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) + { + *ppv = (LPCLASSFACTORY)this; + + AddRef(); + + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef() +{ + return InterlockedIncrement((LPLONG)&m_cRef); +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::Release() +{ + if (InterlockedDecrement((LPLONG)&m_cRef)) + return m_cRef; + + delete this; + + return 0L; +} + +STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID *ppvObj) +{ + *ppvObj = NULL; + + // Shell extensions typically don't support aggregation (inheritance) + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + // Create the main shell extension object. The shell will then call + // QueryInterface with IID_IShellExtInit--this is how shell extensions are + // initialized. + + LPCSHELLEXT pShellExt = new CShellExt(); //Create the CShellExt object + + if (NULL == pShellExt) + return E_OUTOFMEMORY; + + return pShellExt->QueryInterface(riid, ppvObj); +} + + +STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock) +{ + return NOERROR; +} + +// *********************** CShellExt ************************* +CShellExt::CShellExt() +{ + m_cRef = 0L; + m_pDataObj = NULL; + + inc_cRefThisDLL(); +} + +CShellExt::~CShellExt() +{ + if (m_pDataObj) + m_pDataObj->Release(); + + dec_cRefThisDLL(); +} + +STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv) +{ + *ppv = NULL; + + if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) + { + *ppv = (LPSHELLEXTINIT)this; + } + else if (IsEqualIID(riid, IID_IContextMenu)) + { + *ppv = (LPCONTEXTMENU)this; + } + + if (*ppv) + { + AddRef(); + + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExt::AddRef() +{ + return InterlockedIncrement((LPLONG)&m_cRef); +} + +STDMETHODIMP_(ULONG) CShellExt::Release() +{ + + if (InterlockedDecrement((LPLONG)&m_cRef)) + return m_cRef; + + delete this; + + return 0L; +} + + +// +// FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY) +// +// PURPOSE: Called by the shell when initializing a context menu or property +// sheet extension. +// +// PARAMETERS: +// pIDFolder - Specifies the parent folder +// pDataObj - Spefifies the set of items selected in that folder. +// hRegKey - Specifies the type of the focused item in the selection. +// +// RETURN VALUE: +// +// NOERROR in all cases. +// +// COMMENTS: Note that at the time this function is called, we don't know +// (or care) what type of shell extension is being initialized. +// It could be a context menu or a property sheet. +// + +STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, + LPDATAOBJECT pDataObj, + HKEY hRegKey) +{ + // Initialize can be called more than once + if (m_pDataObj) + m_pDataObj->Release(); + + // duplicate the object pointer and registry handle + + if (pDataObj) + { + m_pDataObj = pDataObj; + pDataObj->AddRef(); + } + + return NOERROR; +} + + +// +// FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) +// +// PURPOSE: Called by the shell just before the context menu is displayed. +// This is where you add your specific menu items. +// +// PARAMETERS: +// hMenu - Handle to the context menu +// indexMenu - Index of where to begin inserting menu items +// idCmdFirst - Lowest value for new menu ID's +// idCmtLast - Highest value for new menu ID's +// uFlags - Specifies the context of the menu event +// +// RETURN VALUE: +// +// +// COMMENTS: +// + +STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + UINT idCmd = idCmdFirst; + + hres = m_pDataObj->GetData(&fmte, &medium); + if (medium.hGlobal) + cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0); + + // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); + + // Initialize m_cntOfHWnd to 0 + m_cntOfHWnd = 0; + // Retieve all the vim instances + EnumWindows(EnumWindowsProc, (LPARAM)this); + + if (cbFiles > 1) + { + InsertMenu(hMenu, + indexMenu++, + MF_STRING|MF_BYPOSITION, + idCmd++, + _("Edit with &multiple Vims")); + + InsertMenu(hMenu, + indexMenu++, + MF_STRING|MF_BYPOSITION, + idCmd++, + _("Edit with single &Vim")); + + if (cbFiles <= 4) + { + // Can edit up to 4 files in diff mode + InsertMenu(hMenu, + indexMenu++, + MF_STRING|MF_BYPOSITION, + idCmd++, + _("&Diff with Vim")); + m_edit_existing_off = 3; + } + else + m_edit_existing_off = 2; + + } + else + { + InsertMenu(hMenu, + indexMenu++, + MF_STRING|MF_BYPOSITION, + idCmd++, + _("Edit with &Vim")); + m_edit_existing_off = 1; + } + + // Now display all the vim instances + for (int i = 0; i < m_cntOfHWnd; i++) + { + char title[MAX_PATH]; + char temp[MAX_PATH]; + + // Obtain window title, continue if can not + if (GetWindowText(m_hWnd[i], title, MAX_PATH - 1) == 0) + continue; + // Truncate the title before the path, keep the file name + char *pos = strchr(title, '('); + if (pos != NULL) + { + if (pos > title && pos[-1] == ' ') + --pos; + *pos = 0; + } + // Now concatenate + strncpy(temp, _("Edit with existing Vim - &"), MAX_PATH - 1); + strncat(temp, title, MAX_PATH - 1); + InsertMenu(hMenu, + indexMenu++, + MF_STRING|MF_BYPOSITION, + idCmd++, + temp); + } + // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); + + // Must return number of menu items we added. + return ResultFromShort(idCmd-idCmdFirst); +} + +// +// FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO) +// +// PURPOSE: Called by the shell after the user has selected on of the +// menu items that was added in QueryContextMenu(). +// +// PARAMETERS: +// lpcmi - Pointer to an CMINVOKECOMMANDINFO structure +// +// RETURN VALUE: +// +// +// COMMENTS: +// + +STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + HRESULT hr = E_INVALIDARG; + + // If HIWORD(lpcmi->lpVerb) then we have been called programmatically + // and lpVerb is a command that should be invoked. Otherwise, the shell + // has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has + // selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu(). + if (!HIWORD(lpcmi->lpVerb)) + { + UINT idCmd = LOWORD(lpcmi->lpVerb); + + if (idCmd >= m_edit_existing_off) + { + // Existing with vim instance + hr = PushToWindow(lpcmi->hwnd, + lpcmi->lpDirectory, + lpcmi->lpVerb, + lpcmi->lpParameters, + lpcmi->nShow, + idCmd - m_edit_existing_off); + } + else + { + switch (idCmd) + { + case 0: + hr = InvokeGvim(lpcmi->hwnd, + lpcmi->lpDirectory, + lpcmi->lpVerb, + lpcmi->lpParameters, + lpcmi->nShow); + break; + case 1: + hr = InvokeSingleGvim(lpcmi->hwnd, + |