/* 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
// The "Edit with Vim" shell extension provides these choices when
// a new instance of Gvim is selected:
// - use tabpages
// - enable diff mode
// - none of the above
#define EDIT_WITH_VIM_USE_TABPAGES (2)
#define EDIT_WITH_VIM_IN_DIFF_MODE (1)
#define EDIT_WITH_VIM_NO_OPTIONS (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[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;
}
}
}
WCHAR *
utf8_to_utf16(const char *s)
{
int size = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
WCHAR *buf = (WCHAR *)malloc(size * sizeof(WCHAR));
MultiByteToWideChar(CP_UTF8, 0, s, -1, buf, size);
return buf;
}
HBITMAP
IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
{
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hMemBmp = CreateCompatibleBitmap