summaryrefslogtreecommitdiffstats
path: root/src/GvimExt
diff options
context:
space:
mode:
Diffstat (limited to 'src/GvimExt')
-rw-r--r--src/GvimExt/GvimExt.reg20
-rw-r--r--src/GvimExt/Make_ming.mak81
-rw-r--r--src/GvimExt/Makefile98
-rw-r--r--src/GvimExt/README.txt94
-rw-r--r--src/GvimExt/gvimext.cpp1024
-rw-r--r--src/GvimExt/gvimext.def8
-rw-r--r--src/GvimExt/gvimext.h180
-rw-r--r--src/GvimExt/gvimext.inf22
-rw-r--r--src/GvimExt/gvimext.rc109
-rw-r--r--src/GvimExt/gvimext_ming.def10
-rw-r--r--src/GvimExt/gvimext_ming.rc45
-rw-r--r--src/GvimExt/resource.h15
-rw-r--r--src/GvimExt/uninst.bat1
13 files changed, 1707 insertions, 0 deletions
diff --git a/src/GvimExt/GvimExt.reg b/src/GvimExt/GvimExt.reg
new file mode 100644
index 0000000..129ce6e
--- /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 8.2]
+ "DisplayName"="Vim 8.2: Edit with Vim popup menu entry"
+ "UninstallString"="uninstall.exe"
diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak
new file mode 100644
index 0000000..8d17142
--- /dev/null
+++ b/src/GvimExt/Make_ming.mak
@@ -0,0 +1,81 @@
+# Project: gvimext
+# Generates gvimext.dll with gcc.
+# To be used with MingW and 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
+
+# Link against the shared versions of libgcc/libstdc++ by default. Set
+# STATIC_STDCPLUS to "yes" to link against static versions instead.
+STATIC_STDCPLUS=no
+#STATIC_STDCPLUS=yes
+
+# Note: -static-libstdc++ is not available until gcc 4.5.x.
+LDFLAGS += -shared
+ifeq (yes, $(STATIC_STDCPLUS))
+LDFLAGS += -static-libgcc -static-libstdc++
+endif
+
+ifeq ($(CROSS),yes)
+DEL = rm
+ifeq ($(MINGWOLD),yes)
+CXXFLAGS := -O2 -fvtable-thunks
+else
+CXXFLAGS := -O2
+endif
+else
+CXXFLAGS := -O2
+ifneq (sh.exe, $(SHELL))
+DEL = rm
+else
+DEL = del
+endif
+endif
+# Set the default $(WINVER) to make it work with WinXP.
+ifndef WINVER
+WINVER = 0x0501
+endif
+CXX := $(CROSS_COMPILE)g++
+WINDRES := $(CROSS_COMPILE)windres
+# this used to have --preprocessor, but it's no longer supported
+WINDRES_FLAGS =
+LIBS := -luuid -lgdi32
+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) $(LDFLAGS) $(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 -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) -c $? -o $@
+
+$(RES): gvimext_ming.rc
+ $(WINDRES) $(WINDRES_FLAGS) --input-format=rc --output-format=coff -DMING $? -o $@
+
+clean: clean-custom
+ -$(DEL) $(OBJ) $(RES) $(DLL)
diff --git a/src/GvimExt/Makefile b/src/GvimExt/Makefile
new file mode 100644
index 0000000..4b83f52
--- /dev/null
+++ b/src/GvimExt/Makefile
@@ -0,0 +1,98 @@
+# Makefile for GvimExt, using MSVC
+# Options:
+# DEBUG=yes Build debug version (for VC7 and maybe later)
+# CPUARG= /arch:IA32/AVX/etc, call from main makefile to set
+# automatically from CPUNR
+#
+
+TARGETOS = WINNT
+
+!ifndef APPVER
+APPVER = 5.01
+!endif
+!ifndef WINVER
+WINVER = 0x0501
+!endif
+
+!if "$(DEBUG)" != "yes"
+NODEBUG = 1
+!endif
+
+!ifdef PROCESSOR_ARCHITECTURE
+# On Windows NT
+! ifndef CPU
+CPU = i386
+! if !defined(PLATFORM) && defined(TARGET_CPU)
+PLATFORM = $(TARGET_CPU)
+! endif
+! ifdef PLATFORM
+! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64")
+CPU = AMD64
+! elseif ("$(PLATFORM)" == "arm64") || ("$(PLATFORM)" == "ARM64")
+CPU = ARM64
+! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86")
+! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted.
+! endif
+! endif
+! endif
+!else
+CPU = i386
+!endif
+
+!ifdef SDK_INCLUDE_DIR
+!include $(SDK_INCLUDE_DIR)\Win32.mak
+!elseif "$(USE_WIN32MAK)"=="yes"
+!include <Win32.mak>
+!else
+cc = cl
+link = link
+rc = rc
+cflags = -nologo -c
+lflags = -incremental:no -nologo
+rcflags = /r
+olelibsdll = ole32.lib uuid.lib oleaut32.lib user32.lib gdi32.lib advapi32.lib
+!endif
+
+# include CPUARG
+cflags = $(cflags) $(CPUARG)
+
+# set WINVER and _WIN32_WINNT
+cflags = $(cflags) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
+
+!if "$(CL)" == "/D_USING_V110_SDK71_"
+rcflags = $(rcflags) /D_USING_V110_SDK71_
+!endif
+
+SUBSYSTEM = console
+!if "$(SUBSYSTEM_VER)" != ""
+SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER)
+!endif
+
+!if "$(CPU)" == "AMD64" || "$(CPU)" == "ARM64"
+OFFSET = 0x11C000000
+!else
+OFFSET = 0x1C000000
+!endif
+
+all: gvimext.dll
+
+gvimext.dll: gvimext.obj \
+ gvimext.res
+ $(link) $(lflags) -dll -def:gvimext.def -base:$(OFFSET) -out:$*.dll $** $(olelibsdll) shell32.lib comctl32.lib -subsystem:$(SUBSYSTEM)
+ if exist $*.dll.manifest mt -nologo -manifest $*.dll.manifest -outputresource:$*.dll;2
+
+gvimext.obj: gvimext.h
+
+.cpp.obj:
+ $(cc) $(cflags) -DFEAT_GETTEXT $(cvarsmt) $*.cpp
+
+gvimext.res: gvimext.rc
+ $(rc) /nologo $(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
+ - if exist gvimext.dll.manifest del gvimext.dll.manifest
diff --git a/src/GvimExt/README.txt b/src/GvimExt/README.txt
new file mode 100644
index 0000000..a29200e
--- /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 uninstall.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 substituted 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 0000000..24ad941
--- /dev/null
+++ b/src/GvimExt/gvimext.cpp
@@ -0,0 +1,1024 @@
+/* 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"
+
+static char *searchpath(char *name);
+
+// 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;
+
+/* The buffers size used to be MAX_PATH (260 bytes), but that's not always
+ * enough */
+#define BUFSIZE 1100
+
+//
+// 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[BUFSIZE]. 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 = BUFSIZE;
+ 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((char *)"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((char *)"gvim.bat"));
+ if (name[0] == 0)
+ strcpy(name, "gvim"); // finds gvim.bat or gvim.exe
+ }
+}
+
+ static void
+getGvimInvocation(char *name, int runtime)
+{
+ getGvimName(name, runtime);
+ // avoid that Vim tries to expand wildcards in the file names
+ strcat(name, " --literal");
+}
+
+ static void
+getGvimInvocationW(wchar_t *nameW)
+{
+ char *name;
+
+ name = (char *)malloc(BUFSIZE);
+ getGvimInvocation(name, 0);
+ mbstowcs(nameW, name, BUFSIZE);
+ free(name);
+}
+
+//
+// Get the Vim runtime directory into buf[BUFSIZE].
+// 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 = (int)strlen(buf) - 1; idx >= 0; idx--)
+ if (buf[idx] == '\\' || buf[idx] == '/')
+ {
+ buf[idx + 1] = 0;
+ break;
+ }
+ }
+}
+
+HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
+{
+ HDC hDC = GetDC(NULL);
+ HDC hMemDC = CreateCompatibleDC(hDC);
+ HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, width, height);
+ HBITMAP hResultBmp = NULL;
+ HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
+
+ DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL);
+
+ hResultBmp = hMemBmp;
+ hMemBmp = NULL;
+
+ SelectObject(hMemDC, hOrgBMP);
+ DeleteDC(hMemDC);
+ ReleaseDC(NULL, hDC);
+ DestroyIcon(hIcon);
+ return hResultBmp;
+}
+
+//
+// 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"
+# define GETTEXT_DLL_ALT "libintl-8.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[] =
+ {
+ {(char *)"gettext", (FARPROC*)&dyn_libintl_gettext},
+ {(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain},
+ {(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
+ {NULL, NULL}
+ };
+ DWORD len, len2;
+ LPWSTR buf = NULL;
+ LPWSTR buf2 = NULL;
+
+ // No need to initialize twice.
+ if (hLibintlDLL)
+ return 1;
+
+ // Load gettext library from $VIMRUNTIME\GvimExt{64,32} directory.
+ // Add the directory to $PATH temporarily.
+ len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ len2 = MAX_PATH + 1 + len;
+ buf = (LPWSTR)malloc(len * sizeof(WCHAR));
+ buf2 = (LPWSTR)malloc(len2 * sizeof(WCHAR));
+ if (buf != NULL && buf2 != NULL)
+ {
+ GetEnvironmentVariableW(L"PATH", buf, len);
+# ifdef _WIN64
+ _snwprintf(buf2, len2, L"%S\\GvimExt64;%s", dir, buf);
+# else
+ _snwprintf(buf2, len2, L"%S\\GvimExt32;%s", dir, buf);
+# endif
+ SetEnvironmentVariableW(L"PATH", buf2);
+ hLibintlDLL = LoadLibrary(GETTEXT_DLL);
+# ifdef GETTEXT_DLL_ALT
+ if (!hLibintlDLL)
+ hLibintlDLL = LoadLibrary(GETTEXT_DLL_ALT);
+# endif
+ SetEnvironmentVariableW(L"PATH", buf);
+ }
+ free(buf);
+ free(buf2);
+ 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[BUFSIZE];
+ DWORD len;
+
+ // 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 = (DWORD)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();
+
+ LoadMenuIcon();
+}
+
+CShellExt::~CShellExt()
+{
+ if (m_pDataObj)
+ m_pDataObj->Release();
+
+ dec_cRefThisDLL();
+
+ if (m_hVimIconBitmap)
+ DeleteObject(m_hVimIconBitmap);
+}
+
+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 - Specifies 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;
+
+ HKEY keyhandle;
+ bool showExisting = true;
+ bool showIcons = true;
+
+ // Check whether "Edit with existing Vim" entries are disabled.
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_READ, &keyhandle) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx(keyhandle, "DisableEditWithExisting", 0, NULL,
+ NULL, NULL) == ERROR_SUCCESS)
+ showExisting = false;
+ if (RegQueryValueEx(keyhandle, "DisableContextMenuIcons", 0, NULL,
+ NULL, NULL) == ERROR_SUCCESS)
+ showIcons = false;
+ RegCloseKey(keyhandle);
+ }
+
+ // Retrieve all the vim instances, unless disabled.
+ if (showExisting)
+ EnumWindows(EnumWindowsProc, (LPARAM)this);
+
+ MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
+ mii.fMask = MIIM_STRING | MIIM_ID;
+ if (showIcons)
+ {
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = m_hVimIconBitmap;
+ }
+
+ if (cbFiles > 1)
+ {
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with &multiple Vims");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with single &Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+
+ if (cbFiles <= 4)
+ {
+ // Can edit up to 4 files in diff mode
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Diff with Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ m_edit_existing_off = 3;
+ }
+ else
+ m_edit_existing_off = 2;
+
+ }
+ else
+ {
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with &Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ m_edit_existing_off = 1;
+ }
+
+ HMENU hSubMenu = NULL;
+ if (m_cntOfHWnd > 1)
+ {
+ hSubMenu = CreatePopupMenu();
+ mii.fMask |= MIIM_SUBMENU;
+ mii.wID = idCmd;
+ mii.dwTypeData = _("Edit with existing Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ mii.hSubMenu = hSubMenu;
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ mii.fMask = mii.fMask & ~MIIM_SUBMENU;
+ mii.hSubMenu = NULL;
+ }
+ // Now display all the vim instances
+ for (int i = 0; i < m_cntOfHWnd; i++)
+ {
+ char title[BUFSIZE];
+ char temp[BUFSIZE];
+ int index;
+ HMENU hmenu;
+
+ // Obtain window title, continue if can not
+ if (GetWindowText(m_hWnd[i], title, BUFSIZE - 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
+ if (m_cntOfHWnd > 1)
+ temp[0] = '\0';
+ else
+ {
+ strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1);
+ temp[BUFSIZE - 1] = '\0';
+ }
+ strncat(temp, title, BUFSIZE - 1 - strlen(temp));
+ temp[BUFSIZE - 1] = '\0';
+
+ mii.wID = idCmd++;
+ mii.dwTypeData = temp;
+ mii.cch = lstrlen(mii.dwTypeData);
+ if (m_cntOfHWnd > 1)
+ {
+ hmenu = hSubMenu;
+ index = i;
+ }
+ else
+ {
+ hmenu = hMenu;
+ index = indexMenu++;
+ }
+ InsertMenuItem(hmenu, index, TRUE, &mii);
+ }
+ // 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,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow,
+ 0);
+ break;
+ case 2:
+ hr = InvokeSingleGvim(lpcmi->hwnd,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow,
+ 1);
+ break;
+ }
+ }
+ }
+ return hr;
+}
+
+STDMETHODIMP CShellExt::PushToWindow(HWND /* hParent */,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */,
+ int idHWnd)
+{
+ HWND hWnd = m_hWnd[idHWnd];
+
+ // Show and bring vim instance to foreground
+ if (IsIconic(hWnd) != 0)
+ ShowWindow(hWnd, SW_RESTORE);
+ else
+ ShowWindow(hWnd, SW_SHOW);
+ SetForegroundWindow(hWnd);
+
+ // Post the selected files to the vim instance
+ PostMessage(hWnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0);
+
+ return NOERROR;
+}
+
+STDMETHODIMP CShellExt::GetCommandString(UINT_PTR /* idCmd */,
+ UINT uFlags,
+ UINT FAR * /* reserved */,
+ LPSTR pszName,
+ UINT cchMax)
+{
+ if (uFlags == GCS_HELPTEXT && cchMax > 35)
+ lstrcpy(pszName, _("Edits the selected file(s) with Vim"));
+
+ return NOERROR;
+}
+
+BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
+{
+ char temp[BUFSIZE];
+
+ // First do a bunch of check
+ // No invisible window
+ if (!IsWindowVisible(hWnd)) return TRUE;
+ // No child window ???
+ // if (GetParent(hWnd)) return TRUE;
+ // Class name should be Vim, if failed to get class name, return
+ if (GetClassName(hWnd, temp, sizeof(temp)) == 0)
+ return TRUE;
+ // Compare class name to that of vim, if not, return
+ if (_strnicmp(temp, "vim", sizeof("vim")) != 0)
+ return TRUE;
+ // First check if the number of vim instance exceeds MAX_HWND
+ CShellExt *cs = (CShellExt*) lParam;
+ if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE;
+ // Now we get the vim window, put it into some kind of array
+ cs->m_hWnd[cs->m_cntOfHWnd] = hWnd;
+ cs->m_cntOfHWnd ++;
+
+ return TRUE; // continue enumeration (otherwise this would be false)
+}
+
+BOOL CShellExt::LoadMenuIcon()
+{
+ char vimExeFile[BUFSIZE];
+ getGvimName(vimExeFile, 1);
+ if (vimExeFile[0] == '\0')
+ return FALSE;
+ HICON hVimIcon;
+ if (ExtractIconEx(vimExeFile, 0, NULL, &hVimIcon, 1) == 0)
+ return FALSE;
+ m_hVimIconBitmap = IconToBitmap(hVimIcon,
+ GetSysColorBrush(COLOR_MENU),
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON));
+ return TRUE;
+}
+
+ static char *
+searchpath(char *name)
+{
+ static char widename[2 * BUFSIZE];
+ static char location[2 * BUFSIZE + 2];
+
+ // There appears to be a bug in FindExecutableA() on Windows NT.
+ // Use FindExecutableW() instead...
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)name, -1,
+ (LPWSTR)widename, BUFSIZE);
+ if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
+ (LPWSTR)location) > (HINSTANCE)32)
+ {
+ WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
+ (LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
+ return widename;
+ }
+ return (char *)"";
+}
+
+STDMETHODIMP CShellExt::InvokeGvim(HWND hParent,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */)
+{
+ wchar_t m_szFileUserClickedOn[BUFSIZE];
+ wchar_t cmdStrW[BUFSIZE];
+ UINT i;
+
+ for (i = 0; i < cbFiles; i++)
+ {
+ DragQueryFileW((HDROP)medium.hGlobal,
+ i,
+ m_szFileUserClickedOn,
+ sizeof(m_szFileUserClickedOn));
+
+ getGvimInvocationW(cmdStrW);
+ wcscat(cmdStrW, L" \"");
+
+ if ((wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 2) < BUFSIZE)
+ {
+ wcscat(cmdStrW, m_szFileUserClickedOn);
+ wcscat(cmdStrW, L"\"");
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ // Start the child process.
+ if (!CreateProcessW(NULL, // No module name (use command line).
+ cmdStrW, // Command line.
+ NULL, // Process handle not inheritable.
+ NULL, // Thread handle not inheritable.
+ FALSE, // Set handle inheritance to FALSE.
+ 0, // No creation flags.
+ NULL, // Use parent's environment block.
+ NULL, // Use parent's starting directory.
+ &si, // Pointer to STARTUPINFO structure.
+ &pi) // Pointer to PROCESS_INFORMATION structure.
+ )
+ {
+ MessageBox(
+ hParent,
+ _("Error creating process: Check if gvim is in your path!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ else
+ {
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+ }
+ }
+ else
+ {
+ MessageBox(
+ hParent,
+ _("Path length too long!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ }
+
+ return NOERROR;
+}
+
+
+STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */,
+ int useDiff)
+{
+ wchar_t m_szFileUserClickedOn[BUFSIZE];
+ wchar_t *cmdStrW;
+ size_t cmdlen;
+ size_t len;
+ UINT i;
+
+ cmdlen = BUFSIZE;
+ cmdStrW = (wchar_t *) malloc(cmdlen * sizeof(wchar_t));
+ if (cmdStrW == NULL)
+ return E_FAIL;
+ getGvimInvocationW(cmdStrW);
+
+ if (useDiff)
+ wcscat(cmdStrW, L" -d");
+ for (i = 0; i < cbFiles; i++)
+ {
+ DragQueryFileW((HDROP)medium.hGlobal,
+ i,
+ m_szFileUserClickedOn,
+ sizeof(m_szFileUserClickedOn));
+
+ len = wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 4;
+ if (len > cmdlen)
+ {
+ cmdlen = len + BUFSIZE;
+ wchar_t *cmdStrW_new = (wchar_t *)realloc(cmdStrW, cmdlen * sizeof(wchar_t));
+ if (cmdStrW_new == NULL)
+ {
+ free(cmdStrW);
+ return E_FAIL;
+ }
+ cmdStrW = cmdStrW_new;
+ }
+ wcscat(cmdStrW, L" \"");
+ wcscat(cmdStrW, m_szFileUserClickedOn);
+ wcscat(cmdStrW, L"\"");
+ }
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ // Start the child process.
+ if (!CreateProcessW(NULL, // No module name (use command line).
+ cmdStrW, // Command line.
+ NULL, // Process handle not inheritable.
+ NULL, // Thread handle not inheritable.
+ FALSE, // Set handle inheritance to FALSE.
+ 0, // No creation flags.
+ NULL, // Use parent's environment block.
+ NULL, // Use parent's starting directory.
+ &si, // Pointer to STARTUPINFO structure.
+ &pi) // Pointer to PROCESS_INFORMATION structure.
+ )
+ {
+ MessageBox(
+ hParent,
+ _("Error creating process: Check if gvim is in your path!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ else
+ {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ free(cmdStrW);
+
+ return NOERROR;
+}
diff --git a/src/GvimExt/gvimext.def b/src/GvimExt/gvimext.def
new file mode 100644
index 0000000..e6d66f4
--- /dev/null
+++ b/src/GvimExt/gvimext.def
@@ -0,0 +1,8 @@
+;gvimdef.def : Declares the module parameters for the DLL.
+
+LIBRARY gvimext
+; DESCRIPTION 'Vim Shell Extension'
+
+EXPORTS
+ DllCanUnloadNow private
+ DllGetClassObject private
diff --git a/src/GvimExt/gvimext.h b/src/GvimExt/gvimext.h
new file mode 100644
index 0000000..e43e75f
--- /dev/null
+++ b/src/GvimExt/gvimext.h
@@ -0,0 +1,180 @@
+/* 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.
+ */
+
+/*
+ * If you have any questions or any suggestions concerning gvimext, please
+ * contact Tianmiao Hu: tianmiao@acm.org.
+ */
+
+#if !defined(AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_)
+#define AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_
+
+#if defined(_MSC_VER) && _MSC_VER > 1000
+#pragma once
+#endif
+
+// Insert your headers here
+// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+//--------------------------------------------------------------
+// common user interface routines
+//
+//
+//--------------------------------------------------------------
+
+#ifndef STRICT
+# define STRICT
+#endif
+
+#define INC_OLE2 // MS-Windows, get ole2 from windows.h
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <wchar.h>
+
+/* Accommodate old versions of VC that don't have a modern Platform SDK */
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
+# undef UINT_PTR
+# define UINT_PTR UINT
+#endif
+
+#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))
+
+// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
+//
+#pragma data_seg(".text")
+#define INITGUID
+#include <initguid.h>
+
+//
+// The class ID of this Shell extension class.
+//
+// class id: {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+//
+//
+// NOTE!!! If you use this shell extension as a starting point,
+// you MUST change the GUID below. Simply run UUIDGEN.EXE
+// to generate a new GUID.
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+// static const GUID <<name>> =
+// { 0x51eee242, 0xad87, 0x11d3, { 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99 } };
+//
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+// IMPLEMENT_OLECREATE(<<class>>, <<external_name>>,
+// 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99);
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99} -- this is the registry format
+DEFINE_GUID(CLSID_ShellExtension, 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99);
+
+// this class factory object creates context menu handlers for windows 32 shell
+class CShellExtClassFactory : public IClassFactory
+{
+protected:
+ ULONG m_cRef;
+
+public:
+ CShellExtClassFactory();
+ ~CShellExtClassFactory();
+
+ //IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //IClassFactory members
+ STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
+ STDMETHODIMP LockServer(BOOL);
+
+};
+typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
+#define MAX_HWND 100
+
+// this is the actual OLE Shell context menu handler
+class CShellExt : public IContextMenu,
+ IShellExtInit
+{
+private:
+ BOOL LoadMenuIcon();
+
+protected:
+ ULONG m_cRef;
+ LPDATAOBJECT m_pDataObj;
+ UINT m_edit_existing_off;
+ HBITMAP m_hVimIconBitmap;
+
+ // For some reason, this callback must be static
+ static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
+
+ STDMETHODIMP PushToWindow(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd,
+ int idHWnd);
+
+ STDMETHODIMP InvokeGvim(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd);
+
+ STDMETHODIMP InvokeSingleGvim(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd,
+ int useDiff);
+
+public:
+ int m_cntOfHWnd;
+ HWND m_hWnd[MAX_HWND];
+ CShellExt();
+ ~CShellExt();
+
+ //IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //IShell members
+ STDMETHODIMP QueryContextMenu(HMENU hMenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags);
+
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+
+ STDMETHODIMP GetCommandString(UINT_PTR idCmd,
+ UINT uFlags,
+ UINT FAR *reserved,
+ LPSTR pszName,
+ UINT cchMax);
+
+ //IShellExtInit methods
+ STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder,
+ LPDATAOBJECT pDataObj,
+ HKEY hKeyID);
+};
+
+typedef CShellExt *LPCSHELLEXT;
+#pragma data_seg()
+
+#endif
diff --git a/src/GvimExt/gvimext.inf b/src/GvimExt/gvimext.inf
new file mode 100644
index 0000000..8b45bb1
--- /dev/null
+++ b/src/GvimExt/gvimext.inf
@@ -0,0 +1,22 @@
+[Version]
+Signature="$Windows NT$""
+Provider="Tianmiao"
+
+[Manufacture]
+
+[DefaultInstall]
+AddReg=ThisDll.Add.Reg
+
+[DefaultUninstall]
+DelReg=ThisDLL.Add.Reg
+
+[ThisDll.Add.Reg]
+HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}
+HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32
+HKCR,*\shellex\ContextMenuHandlers\gvim
+HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved",{51EEE242-AD87-11d3-9C1E-0090278BBD99}
+HKLM,Software\Vim\Gvim
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 6.0"
+
+[Strings]
+ThisDll="gvimext.dll"
diff --git a/src/GvimExt/gvimext.rc b/src/GvimExt/gvimext.rc
new file mode 100644
index 0000000..10476da
--- /dev/null
+++ b/src/GvimExt/gvimext.rc
@@ -0,0 +1,109 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winresrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "Developed using COM architecture!\0"
+ VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0"
+ VALUE "FileDescription", "A small project for the context menu of gvim!\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "gvim right-click menu extension\0"
+ VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0"
+ VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0"
+ VALUE "OriginalFilename", "gvimext.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/GvimExt/gvimext_ming.def b/src/GvimExt/gvimext_ming.def
new file mode 100644
index 0000000..b96e1d3
--- /dev/null
+++ b/src/GvimExt/gvimext_ming.def
@@ -0,0 +1,10 @@
+;gvimdef_ming.def : Declares the module parameters for the DLL.
+;The mingw environment doesn't know anything about private declarations
+;Hence this is the same file as gvimext.def with private removed
+
+LIBRARY gvimext
+; DESCRIPTION 'Vim Shell Extension build with MinGW'
+
+EXPORTS
+ DllCanUnloadNow = DllCanUnloadNow@0
+ DllGetClassObject = DllGetClassObject@12
diff --git a/src/GvimExt/gvimext_ming.rc b/src/GvimExt/gvimext_ming.rc
new file mode 100644
index 0000000..6c69854
--- /dev/null
+++ b/src/GvimExt/gvimext_ming.rc
@@ -0,0 +1,45 @@
+#include <windows.h>
+#define xstr(x) str(x)
+#define str(x) #x
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x4L
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904b0"
+ {
+ VALUE "Comments", "Developed using COM architecture!\0"
+ VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0"
+ VALUE "FileDescription", "A small project for the context menu of gvim!\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "gvim right-click menu extension\0"
+ VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0"
+ VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0"
+ VALUE "OriginalFilename", "gvimext.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+
+#if defined(__GNUC__)
+ VALUE "SpecialBuild", "Build With " "MingW " xstr(__GNUC__) "." xstr(__GNUC_MINOR__) "." xstr(__GNUC_PATCHLEVEL__) " on " __DATE__ " " __TIME__ "\0"
+#else
+ VALUE "SpecialBuild", "Unknown compiler\0"
+
+#endif
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1200
+ }
+}
diff --git a/src/GvimExt/resource.h b/src/GvimExt/resource.h
new file mode 100644
index 0000000..8ddc823
--- /dev/null
+++ b/src/GvimExt/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by gvimext.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/GvimExt/uninst.bat b/src/GvimExt/uninst.bat
new file mode 100644
index 0000000..71d14f6
--- /dev/null
+++ b/src/GvimExt/uninst.bat
@@ -0,0 +1 @@
+rundll32.exe setupapi,InstallHinfSection DefaultUninstall 128 %1