Mercurial > vim
annotate src/GvimExt/gvimext.cpp @ 20041:3601e816a569 v8.2.0576
patch 8.2.0576: some errors are not covered by tests
Commit: https://github.com/vim/vim/commit/067297e16a516838dbc46aaa9d8b1a507afec28d
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Apr 13 19:55:50 2020 +0200
patch 8.2.0576: some errors are not covered by tests
Problem: Some errors are not covered by tests.
Solution: Add a few more tests. (Dominique Pelle, closes https://github.com/vim/vim/issues/5920)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 13 Apr 2020 20:00:05 +0200 |
parents | 7e733046db1d |
children | db65bb242582 |
rev | line source |
---|---|
10 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved gvimext by Tianmiao Hu | |
4 * | |
5 * Do ":help uganda" in Vim to read copying and usage conditions. | |
6 * Do ":help credits" in Vim to see a list of people who contributed. | |
7 */ | |
8 | |
9 /* | |
10 * gvimext is a DLL which is used for the "Edit with Vim" context menu | |
11 * extension. It implements a MS defined interface with the Shell. | |
12 * | |
13 * If you have any questions or any suggestions concerning gvimext, please | |
14 * contact Tianmiao Hu: tianmiao@acm.org. | |
15 */ | |
16 | |
17 #include "gvimext.h" | |
18 | |
19 static char *searchpath(char *name); | |
20 | |
21 // Always get an error while putting the following stuff to the | |
22 // gvimext.h file as class protected variables, give up and | |
23 // declare them as global stuff | |
24 FORMATETC fmte = {CF_HDROP, | |
25 (DVTARGETDEVICE FAR *)NULL, | |
26 DVASPECT_CONTENT, | |
27 -1, | |
28 TYMED_HGLOBAL | |
29 }; | |
30 STGMEDIUM medium; | |
31 HRESULT hres = 0; | |
32 UINT cbFiles = 0; | |
33 | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
34 /* The buffers size used to be MAX_PATH (260 bytes), but that's not always |
415 | 35 * enough */ |
36 #define BUFSIZE 1100 | |
37 | |
10 | 38 // |
39 // Get the name of the Gvim executable to use, with the path. | |
40 // When "runtime" is non-zero, we were called to find the runtime directory. | |
415 | 41 // Returns the path in name[BUFSIZE]. It's empty when it fails. |
10 | 42 // |
43 static void | |
44 getGvimName(char *name, int runtime) | |
45 { | |
46 HKEY keyhandle; | |
47 DWORD hlen; | |
48 | |
49 // Get the location of gvim from the registry. | |
50 name[0] = 0; | |
51 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, | |
52 KEY_READ, &keyhandle) == ERROR_SUCCESS) | |
53 { | |
415 | 54 hlen = BUFSIZE; |
10 | 55 if (RegQueryValueEx(keyhandle, "path", 0, NULL, (BYTE *)name, &hlen) |
56 != ERROR_SUCCESS) | |
57 name[0] = 0; | |
58 else | |
59 name[hlen] = 0; | |
60 RegCloseKey(keyhandle); | |
61 } | |
62 | |
63 // Registry didn't work, use the search path. | |
64 if (name[0] == 0) | |
1366 | 65 strcpy(name, searchpath((char *)"gvim.exe")); |
10 | 66 |
67 if (!runtime) | |
68 { | |
69 // Only when looking for the executable, not the runtime dir, we can | |
70 // search for the batch file or a name without a path. | |
71 if (name[0] == 0) | |
1366 | 72 strcpy(name, searchpath((char *)"gvim.bat")); |
10 | 73 if (name[0] == 0) |
74 strcpy(name, "gvim"); // finds gvim.bat or gvim.exe | |
75 } | |
76 } | |
77 | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
78 static void |
6805 | 79 getGvimInvocation(char *name, int runtime) |
80 { | |
81 getGvimName(name, runtime); | |
82 // avoid that Vim tries to expand wildcards in the file names | |
83 strcat(name, " --literal"); | |
84 } | |
85 | |
86 static void | |
87 getGvimInvocationW(wchar_t *nameW) | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
88 { |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
89 char *name; |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
90 |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
91 name = (char *)malloc(BUFSIZE); |
6805 | 92 getGvimInvocation(name, 0); |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
93 mbstowcs(nameW, name, BUFSIZE); |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
94 free(name); |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
95 } |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
96 |
10 | 97 // |
415 | 98 // Get the Vim runtime directory into buf[BUFSIZE]. |
10 | 99 // The result is empty when it failed. |
100 // When it works, the path ends in a slash or backslash. | |
101 // | |
102 static void | |
103 getRuntimeDir(char *buf) | |
104 { | |
105 int idx; | |
106 | |
107 getGvimName(buf, 1); | |
108 if (buf[0] != 0) | |
109 { | |
110 // When no path found, use the search path to expand it. | |
111 if (strchr(buf, '/') == NULL && strchr(buf, '\\') == NULL) | |
112 strcpy(buf, searchpath(buf)); | |
113 | |
114 // remove "gvim.exe" from the end | |
835 | 115 for (idx = (int)strlen(buf) - 1; idx >= 0; idx--) |
10 | 116 if (buf[idx] == '\\' || buf[idx] == '/') |
117 { | |
118 buf[idx + 1] = 0; | |
119 break; | |
120 } | |
121 } | |
122 } | |
123 | |
6805 | 124 HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height) |
125 { | |
126 HDC hDC = GetDC(NULL); | |
127 HDC hMemDC = CreateCompatibleDC(hDC); | |
128 HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, width, height); | |
129 HBITMAP hResultBmp = NULL; | |
130 HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp); | |
131 | |
132 DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL); | |
133 | |
134 hResultBmp = hMemBmp; | |
135 hMemBmp = NULL; | |
136 | |
137 SelectObject(hMemDC, hOrgBMP); | |
138 DeleteDC(hMemDC); | |
139 ReleaseDC(NULL, hDC); | |
140 DestroyIcon(hIcon); | |
141 return hResultBmp; | |
142 } | |
143 | |
10 | 144 // |
145 // GETTEXT: translated messages and menu entries | |
146 // | |
147 #ifndef FEAT_GETTEXT | |
148 # define _(x) x | |
149 #else | |
150 # define _(x) (*dyn_libintl_gettext)(x) | |
151 # define VIMPACKAGE "vim" | |
152 # ifndef GETTEXT_DLL | |
153 # define GETTEXT_DLL "libintl.dll" | |
8180
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
154 # define GETTEXT_DLL_ALT "libintl-8.dll" |
10 | 155 # endif |
156 | |
157 // Dummy functions | |
158 static char *null_libintl_gettext(const char *); | |
159 static char *null_libintl_textdomain(const char *); | |
160 static char *null_libintl_bindtextdomain(const char *, const char *); | |
161 static int dyn_libintl_init(char *dir); | |
162 static void dyn_libintl_end(void); | |
163 | |
3008 | 164 static wchar_t *oldenv = NULL; |
10 | 165 static HINSTANCE hLibintlDLL = 0; |
166 static char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext; | |
167 static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain; | |
168 static char *(*dyn_libintl_bindtextdomain)(const char *, const char *) | |
169 = null_libintl_bindtextdomain; | |
170 | |
171 // | |
172 // Attempt to load libintl.dll. If it doesn't work, use dummy functions. | |
173 // "dir" is the directory where the libintl.dll might be. | |
174 // Return 1 for success, 0 for failure. | |
175 // | |
176 static int | |
177 dyn_libintl_init(char *dir) | |
178 { | |
179 int i; | |
180 static struct | |
181 { | |
182 char *name; | |
183 FARPROC *ptr; | |
184 } libintl_entry[] = | |
185 { | |
1366 | 186 {(char *)"gettext", (FARPROC*)&dyn_libintl_gettext}, |
187 {(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain}, | |
188 {(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain}, | |
10 | 189 {NULL, NULL} |
190 }; | |
8180
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
191 DWORD len, len2; |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
192 LPWSTR buf = NULL; |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
193 LPWSTR buf2 = NULL; |
10 | 194 |
195 // No need to initialize twice. | |
196 if (hLibintlDLL) | |
197 return 1; | |
198 | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
199 // Load gettext library from $VIMRUNTIME\GvimExt{64,32} directory. |
8180
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
200 // Add the directory to $PATH temporarily. |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
201 len = GetEnvironmentVariableW(L"PATH", NULL, 0); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
202 len2 = MAX_PATH + 1 + len; |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
203 buf = (LPWSTR)malloc(len * sizeof(WCHAR)); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
204 buf2 = (LPWSTR)malloc(len2 * sizeof(WCHAR)); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
205 if (buf != NULL && buf2 != NULL) |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
206 { |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
207 GetEnvironmentVariableW(L"PATH", buf, len); |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
208 #ifdef _WIN64 |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
209 _snwprintf(buf2, len2, L"%S\\GvimExt64;%s", dir, buf); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
210 #else |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
211 _snwprintf(buf2, len2, L"%S\\GvimExt32;%s", dir, buf); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
212 #endif |
8180
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
213 SetEnvironmentVariableW(L"PATH", buf2); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
214 hLibintlDLL = LoadLibrary(GETTEXT_DLL); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
215 #ifdef GETTEXT_DLL_ALT |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
216 if (!hLibintlDLL) |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
217 hLibintlDLL = LoadLibrary(GETTEXT_DLL_ALT); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
218 #endif |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
219 SetEnvironmentVariableW(L"PATH", buf); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
220 } |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
221 free(buf); |
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
222 free(buf2); |
10 | 223 if (!hLibintlDLL) |
8180
1e48ffa2d697
commit https://github.com/vim/vim/commit/271273c39f2150ecdaa67fe1a2a8e9cdc63db545
Christian Brabandt <cb@256bit.org>
parents:
6805
diff
changeset
|
224 return 0; |
10 | 225 |
226 // Get the addresses of the functions we need. | |
227 for (i = 0; libintl_entry[i].name != NULL | |
228 && libintl_entry[i].ptr != NULL; ++i) | |
229 { | |
230 if ((*libintl_entry[i].ptr = GetProcAddress(hLibintlDLL, | |
231 libintl_entry[i].name)) == NULL) | |
232 { | |
233 dyn_libintl_end(); | |
234 return 0; | |
235 } | |
236 } | |
237 return 1; | |
238 } | |
239 | |
240 static void | |
241 dyn_libintl_end(void) | |
242 { | |
243 if (hLibintlDLL) | |
244 FreeLibrary(hLibintlDLL); | |
245 hLibintlDLL = NULL; | |
246 dyn_libintl_gettext = null_libintl_gettext; | |
247 dyn_libintl_textdomain = null_libintl_textdomain; | |
248 dyn_libintl_bindtextdomain = null_libintl_bindtextdomain; | |
249 } | |
250 | |
251 static char * | |
252 null_libintl_gettext(const char *msgid) | |
253 { | |
254 return (char *)msgid; | |
255 } | |
256 | |
257 static char * | |
1686 | 258 null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */) |
10 | 259 { |
260 return NULL; | |
261 } | |
262 | |
263 static char * | |
1686 | 264 null_libintl_textdomain(const char* /* domainname */) |
10 | 265 { |
266 return NULL; | |
267 } | |
268 | |
269 // | |
270 // Setup for translating strings. | |
271 // | |
272 static void | |
273 dyn_gettext_load(void) | |
274 { | |
415 | 275 char szBuff[BUFSIZE]; |
276 char szLang[BUFSIZE]; | |
10 | 277 DWORD len; |
278 HKEY keyhandle; | |
279 int gotlang = 0; | |
280 | |
281 strcpy(szLang, "LANG="); | |
282 | |
283 // First try getting the language from the registry, this can be | |
284 // used to overrule the system language. | |
285 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, | |
286 KEY_READ, &keyhandle) == ERROR_SUCCESS) | |
287 { | |
415 | 288 len = BUFSIZE; |
10 | 289 if (RegQueryValueEx(keyhandle, "lang", 0, NULL, (BYTE*)szBuff, &len) |
290 == ERROR_SUCCESS) | |
291 { | |
292 szBuff[len] = 0; | |
293 strcat(szLang, szBuff); | |
294 gotlang = 1; | |
295 } | |
296 RegCloseKey(keyhandle); | |
297 } | |
298 | |
299 if (!gotlang && getenv("LANG") == NULL) | |
300 { | |
301 // Get the language from the system. | |
302 // Could use LOCALE_SISO639LANGNAME, but it's not in Win95. | |
303 // LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use | |
304 // only the first two. | |
305 len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, | |
415 | 306 (LPTSTR)szBuff, BUFSIZE); |
10 | 307 if (len >= 2 && _strnicmp(szBuff, "en", 2) != 0) |
308 { | |
309 // There are a few exceptions (probably more) | |
310 if (_strnicmp(szBuff, "cht", 3) == 0 | |
311 || _strnicmp(szBuff, "zht", 3) == 0) | |
312 strcpy(szBuff, "zh_TW"); | |
313 else if (_strnicmp(szBuff, "chs", 3) == 0 | |
314 || _strnicmp(szBuff, "zhc", 3) == 0) | |
315 strcpy(szBuff, "zh_CN"); | |
316 else if (_strnicmp(szBuff, "jp", 2) == 0) | |
317 strcpy(szBuff, "ja"); | |
318 else | |
319 szBuff[2] = 0; // truncate to two-letter code | |
320 strcat(szLang, szBuff); | |
321 gotlang = 1; | |
322 } | |
323 } | |
324 if (gotlang) | |
325 putenv(szLang); | |
326 | |
327 // Try to locate the runtime files. The path is used to find libintl.dll | |
328 // and the vim.mo files. | |
329 getRuntimeDir(szBuff); | |
330 if (szBuff[0] != 0) | |
331 { | |
835 | 332 len = (DWORD)strlen(szBuff); |
10 | 333 if (dyn_libintl_init(szBuff)) |
334 { | |
335 strcpy(szBuff + len, "lang"); | |
336 | |
337 (*dyn_libintl_bindtextdomain)(VIMPACKAGE, szBuff); | |
338 (*dyn_libintl_textdomain)(VIMPACKAGE); | |
339 } | |
340 } | |
341 } | |
342 | |
343 static void | |
344 dyn_gettext_free(void) | |
345 { | |
346 dyn_libintl_end(); | |
347 } | |
348 #endif // FEAT_GETTEXT | |
349 | |
350 // | |
351 // Global variables | |
352 // | |
353 UINT g_cRefThisDll = 0; // Reference count of this DLL. | |
354 HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself. | |
355 | |
356 | |
357 //--------------------------------------------------------------------------- | |
358 // DllMain | |
359 //--------------------------------------------------------------------------- | |
360 extern "C" int APIENTRY | |
1686 | 361 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */) |
10 | 362 { |
363 switch (dwReason) | |
364 { | |
365 case DLL_PROCESS_ATTACH: | |
366 // Extension DLL one-time initialization | |
367 g_hmodThisDll = hInstance; | |
368 break; | |
369 | |
370 case DLL_PROCESS_DETACH: | |
371 break; | |
372 } | |
373 | |
374 return 1; // ok | |
375 } | |
376 | |
377 static void | |
378 inc_cRefThisDLL() | |
379 { | |
380 #ifdef FEAT_GETTEXT | |
3008 | 381 if (g_cRefThisDll == 0) { |
10 | 382 dyn_gettext_load(); |
3008 | 383 oldenv = GetEnvironmentStringsW(); |
384 } | |
10 | 385 #endif |
386 InterlockedIncrement((LPLONG)&g_cRefThisDll); | |
387 } | |
388 | |
389 static void | |
390 dec_cRefThisDLL() | |
391 { | |
392 #ifdef FEAT_GETTEXT | |
3008 | 393 if (InterlockedDecrement((LPLONG)&g_cRefThisDll) == 0) { |
10 | 394 dyn_gettext_free(); |
3008 | 395 if (oldenv != NULL) { |
396 FreeEnvironmentStringsW(oldenv); | |
397 oldenv = NULL; | |
398 } | |
399 } | |
10 | 400 #else |
401 InterlockedDecrement((LPLONG)&g_cRefThisDll); | |
402 #endif | |
403 } | |
404 | |
405 //--------------------------------------------------------------------------- | |
406 // DllCanUnloadNow | |
407 //--------------------------------------------------------------------------- | |
408 | |
409 STDAPI DllCanUnloadNow(void) | |
410 { | |
411 return (g_cRefThisDll == 0 ? S_OK : S_FALSE); | |
412 } | |
413 | |
414 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) | |
415 { | |
416 *ppvOut = NULL; | |
417 | |
418 if (IsEqualIID(rclsid, CLSID_ShellExtension)) | |
419 { | |
420 CShellExtClassFactory *pcf = new CShellExtClassFactory; | |
421 | |
422 return pcf->QueryInterface(riid, ppvOut); | |
423 } | |
424 | |
425 return CLASS_E_CLASSNOTAVAILABLE; | |
426 } | |
427 | |
428 CShellExtClassFactory::CShellExtClassFactory() | |
429 { | |
430 m_cRef = 0L; | |
431 | |
432 inc_cRefThisDLL(); | |
433 } | |
434 | |
435 CShellExtClassFactory::~CShellExtClassFactory() | |
436 { | |
437 dec_cRefThisDLL(); | |
438 } | |
439 | |
440 STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, | |
441 LPVOID FAR *ppv) | |
442 { | |
443 *ppv = NULL; | |
444 | |
6805 | 445 // any interface on this object is the object pointer |
10 | 446 |
447 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) | |
448 { | |
449 *ppv = (LPCLASSFACTORY)this; | |
450 | |
451 AddRef(); | |
452 | |
453 return NOERROR; | |
454 } | |
455 | |
456 return E_NOINTERFACE; | |
457 } | |
458 | |
459 STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef() | |
460 { | |
461 return InterlockedIncrement((LPLONG)&m_cRef); | |
462 } | |
463 | |
464 STDMETHODIMP_(ULONG) CShellExtClassFactory::Release() | |
465 { | |
466 if (InterlockedDecrement((LPLONG)&m_cRef)) | |
467 return m_cRef; | |
468 | |
469 delete this; | |
470 | |
471 return 0L; | |
472 } | |
473 | |
474 STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, | |
475 REFIID riid, | |
476 LPVOID *ppvObj) | |
477 { | |
478 *ppvObj = NULL; | |
479 | |
480 // Shell extensions typically don't support aggregation (inheritance) | |
481 | |
482 if (pUnkOuter) | |
483 return CLASS_E_NOAGGREGATION; | |
484 | |
485 // Create the main shell extension object. The shell will then call | |
486 // QueryInterface with IID_IShellExtInit--this is how shell extensions are | |
487 // initialized. | |
488 | |
6805 | 489 LPCSHELLEXT pShellExt = new CShellExt(); // create the CShellExt object |
10 | 490 |
491 if (NULL == pShellExt) | |
492 return E_OUTOFMEMORY; | |
493 | |
494 return pShellExt->QueryInterface(riid, ppvObj); | |
495 } | |
496 | |
497 | |
1686 | 498 STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /* fLock */) |
10 | 499 { |
500 return NOERROR; | |
501 } | |
502 | |
503 // *********************** CShellExt ************************* | |
504 CShellExt::CShellExt() | |
505 { | |
506 m_cRef = 0L; | |
507 m_pDataObj = NULL; | |
508 | |
509 inc_cRefThisDLL(); | |
6805 | 510 |
511 LoadMenuIcon(); | |
10 | 512 } |
513 | |
514 CShellExt::~CShellExt() | |
515 { | |
516 if (m_pDataObj) | |
517 m_pDataObj->Release(); | |
518 | |
519 dec_cRefThisDLL(); | |
6805 | 520 |
521 if (m_hVimIconBitmap) | |
522 DeleteObject(m_hVimIconBitmap); | |
10 | 523 } |
524 | |
525 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv) | |
526 { | |
527 *ppv = NULL; | |
528 | |
529 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) | |
530 { | |
531 *ppv = (LPSHELLEXTINIT)this; | |
532 } | |
533 else if (IsEqualIID(riid, IID_IContextMenu)) | |
534 { | |
535 *ppv = (LPCONTEXTMENU)this; | |
536 } | |
537 | |
538 if (*ppv) | |
539 { | |
540 AddRef(); | |
541 | |
542 return NOERROR; | |
543 } | |
544 | |
545 return E_NOINTERFACE; | |
546 } | |
547 | |
548 STDMETHODIMP_(ULONG) CShellExt::AddRef() | |
549 { | |
550 return InterlockedIncrement((LPLONG)&m_cRef); | |
551 } | |
552 | |
553 STDMETHODIMP_(ULONG) CShellExt::Release() | |
554 { | |
555 | |
556 if (InterlockedDecrement((LPLONG)&m_cRef)) | |
557 return m_cRef; | |
558 | |
559 delete this; | |
560 | |
561 return 0L; | |
562 } | |
563 | |
564 | |
565 // | |
566 // FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY) | |
567 // | |
568 // PURPOSE: Called by the shell when initializing a context menu or property | |
569 // sheet extension. | |
570 // | |
571 // PARAMETERS: | |
572 // pIDFolder - Specifies the parent folder | |
4352 | 573 // pDataObj - Specifies the set of items selected in that folder. |
10 | 574 // hRegKey - Specifies the type of the focused item in the selection. |
575 // | |
576 // RETURN VALUE: | |
577 // | |
578 // NOERROR in all cases. | |
579 // | |
580 // COMMENTS: Note that at the time this function is called, we don't know | |
581 // (or care) what type of shell extension is being initialized. | |
582 // It could be a context menu or a property sheet. | |
583 // | |
584 | |
1686 | 585 STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST /* pIDFolder */, |
10 | 586 LPDATAOBJECT pDataObj, |
1686 | 587 HKEY /* hRegKey */) |
10 | 588 { |
589 // Initialize can be called more than once | |
590 if (m_pDataObj) | |
591 m_pDataObj->Release(); | |
592 | |
593 // duplicate the object pointer and registry handle | |
594 | |
595 if (pDataObj) | |
596 { | |
597 m_pDataObj = pDataObj; | |
598 pDataObj->AddRef(); | |
599 } | |
600 | |
601 return NOERROR; | |
602 } | |
603 | |
604 | |
605 // | |
606 // FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) | |
607 // | |
608 // PURPOSE: Called by the shell just before the context menu is displayed. | |
609 // This is where you add your specific menu items. | |
610 // | |
611 // PARAMETERS: | |
612 // hMenu - Handle to the context menu | |
613 // indexMenu - Index of where to begin inserting menu items | |
614 // idCmdFirst - Lowest value for new menu ID's | |
615 // idCmtLast - Highest value for new menu ID's | |
616 // uFlags - Specifies the context of the menu event | |
617 // | |
618 // RETURN VALUE: | |
619 // | |
620 // | |
621 // COMMENTS: | |
622 // | |
623 | |
624 STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, | |
625 UINT indexMenu, | |
626 UINT idCmdFirst, | |
1686 | 627 UINT /* idCmdLast */, |
628 UINT /* uFlags */) | |
10 | 629 { |
630 UINT idCmd = idCmdFirst; | |
631 | |
632 hres = m_pDataObj->GetData(&fmte, &medium); | |
633 if (medium.hGlobal) | |
634 cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0); | |
635 | |
636 // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); | |
637 | |
638 // Initialize m_cntOfHWnd to 0 | |
639 m_cntOfHWnd = 0; | |
2972 | 640 |
641 HKEY keyhandle; | |
642 bool showExisting = true; | |
6805 | 643 bool showIcons = true; |
2972 | 644 |
645 // Check whether "Edit with existing Vim" entries are disabled. | |
646 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, | |
647 KEY_READ, &keyhandle) == ERROR_SUCCESS) | |
648 { | |
649 if (RegQueryValueEx(keyhandle, "DisableEditWithExisting", 0, NULL, | |
650 NULL, NULL) == ERROR_SUCCESS) | |
651 showExisting = false; | |
6805 | 652 if (RegQueryValueEx(keyhandle, "DisableContextMenuIcons", 0, NULL, |
653 NULL, NULL) == ERROR_SUCCESS) | |
654 showIcons = false; | |
2972 | 655 RegCloseKey(keyhandle); |
656 } | |
657 | |
658 // Retrieve all the vim instances, unless disabled. | |
659 if (showExisting) | |
660 EnumWindows(EnumWindowsProc, (LPARAM)this); | |
10 | 661 |
6805 | 662 MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; |
663 mii.fMask = MIIM_STRING | MIIM_ID; | |
664 if (showIcons) | |
665 { | |
666 mii.fMask |= MIIM_BITMAP; | |
667 mii.hbmpItem = m_hVimIconBitmap; | |
668 } | |
669 | |
10 | 670 if (cbFiles > 1) |
671 { | |
6805 | 672 mii.wID = idCmd++; |
673 mii.dwTypeData = _("Edit with &multiple Vims"); | |
674 mii.cch = lstrlen(mii.dwTypeData); | |
675 InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); | |
10 | 676 |
6805 | 677 mii.wID = idCmd++; |
678 mii.dwTypeData = _("Edit with single &Vim"); | |
679 mii.cch = lstrlen(mii.dwTypeData); | |
680 InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); | |
10 | 681 |
682 if (cbFiles <= 4) | |
683 { | |
684 // Can edit up to 4 files in diff mode | |
6805 | 685 mii.wID = idCmd++; |
686 mii.dwTypeData = _("Diff with Vim"); | |
687 mii.cch = lstrlen(mii.dwTypeData); | |
688 InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); | |
10 | 689 m_edit_existing_off = 3; |
690 } | |
691 else | |
692 m_edit_existing_off = 2; | |
693 | |
694 } | |
695 else | |
696 { | |
6805 | 697 mii.wID = idCmd++; |
698 mii.dwTypeData = _("Edit with &Vim"); | |
699 mii.cch = lstrlen(mii.dwTypeData); | |
700 InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); | |
10 | 701 m_edit_existing_off = 1; |
702 } | |
703 | |
14962
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
704 HMENU hSubMenu = NULL; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
705 if (m_cntOfHWnd > 1) |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
706 { |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
707 hSubMenu = CreatePopupMenu(); |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
708 mii.fMask |= MIIM_SUBMENU; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
709 mii.wID = idCmd; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
710 mii.dwTypeData = _("Edit with existing Vim"); |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
711 mii.cch = lstrlen(mii.dwTypeData); |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
712 mii.hSubMenu = hSubMenu; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
713 InsertMenuItem(hMenu, indexMenu++, TRUE, &mii); |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
714 mii.fMask = mii.fMask & ~MIIM_SUBMENU; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
715 mii.hSubMenu = NULL; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
716 } |
10 | 717 // Now display all the vim instances |
718 for (int i = 0; i < m_cntOfHWnd; i++) | |
719 { | |
415 | 720 char title[BUFSIZE]; |
721 char temp[BUFSIZE]; | |
14962
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
722 int index; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
723 HMENU hmenu; |
10 | 724 |
725 // Obtain window title, continue if can not | |
415 | 726 if (GetWindowText(m_hWnd[i], title, BUFSIZE - 1) == 0) |
10 | 727 continue; |
728 // Truncate the title before the path, keep the file name | |
729 char *pos = strchr(title, '('); | |
730 if (pos != NULL) | |
731 { | |
732 if (pos > title && pos[-1] == ' ') | |
733 --pos; | |
734 *pos = 0; | |
735 } | |
736 // Now concatenate | |
14962
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
737 if (m_cntOfHWnd > 1) |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
738 temp[0] = '\0'; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
739 else |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
740 { |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
741 strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1); |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
742 temp[BUFSIZE - 1] = '\0'; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
743 } |
1953 | 744 strncat(temp, title, BUFSIZE - 1 - strlen(temp)); |
745 temp[BUFSIZE - 1] = '\0'; | |
6805 | 746 |
747 mii.wID = idCmd++; | |
748 mii.dwTypeData = temp; | |
749 mii.cch = lstrlen(mii.dwTypeData); | |
14962
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
750 if (m_cntOfHWnd > 1) |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
751 { |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
752 hmenu = hSubMenu; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
753 index = i; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
754 } |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
755 else |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
756 { |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
757 hmenu = hMenu; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
758 index = indexMenu++; |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
759 } |
013b70517b1a
patch 8.1.0492: "Edit with existing Vim" list can get long
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
760 InsertMenuItem(hmenu, index, TRUE, &mii); |
10 | 761 } |
762 // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL); | |
763 | |
764 // Must return number of menu items we added. | |
765 return ResultFromShort(idCmd-idCmdFirst); | |
766 } | |
767 | |
768 // | |
769 // FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO) | |
770 // | |
771 // PURPOSE: Called by the shell after the user has selected on of the | |
772 // menu items that was added in QueryContextMenu(). | |
773 // | |
774 // PARAMETERS: | |
775 // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure | |
776 // | |
777 // RETURN VALUE: | |
778 // | |
779 // | |
780 // COMMENTS: | |
781 // | |
782 | |
783 STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) | |
784 { | |
785 HRESULT hr = E_INVALIDARG; | |
786 | |
787 // If HIWORD(lpcmi->lpVerb) then we have been called programmatically | |
788 // and lpVerb is a command that should be invoked. Otherwise, the shell | |
789 // has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has | |
790 // selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu(). | |
791 if (!HIWORD(lpcmi->lpVerb)) | |
792 { | |
793 UINT idCmd = LOWORD(lpcmi->lpVerb); | |
794 | |
795 if (idCmd >= m_edit_existing_off) | |
796 { | |
797 // Existing with vim instance | |
798 hr = PushToWindow(lpcmi->hwnd, | |
799 lpcmi->lpDirectory, | |
800 lpcmi->lpVerb, | |
801 lpcmi->lpParameters, | |
802 lpcmi->nShow, | |
803 idCmd - m_edit_existing_off); | |
804 } | |
805 else | |
806 { | |
807 switch (idCmd) | |
808 { | |
809 case 0: | |
810 hr = InvokeGvim(lpcmi->hwnd, | |
811 lpcmi->lpDirectory, | |
812 lpcmi->lpVerb, | |
813 lpcmi->lpParameters, | |
814 lpcmi->nShow); | |
815 break; | |
816 case 1: | |
817 hr = InvokeSingleGvim(lpcmi->hwnd, | |
818 lpcmi->lpDirectory, | |
819 lpcmi->lpVerb, | |
820 lpcmi->lpParameters, | |
821 lpcmi->nShow, | |
822 0); | |
823 break; | |
824 case 2: | |
825 hr = InvokeSingleGvim(lpcmi->hwnd, | |
826 lpcmi->lpDirectory, | |
827 lpcmi->lpVerb, | |
828 lpcmi->lpParameters, | |
829 lpcmi->nShow, | |
830 1); | |
831 break; | |
832 } | |
833 } | |
834 } | |
835 return hr; | |
836 } | |
837 | |
1686 | 838 STDMETHODIMP CShellExt::PushToWindow(HWND /* hParent */, |
839 LPCSTR /* pszWorkingDir */, | |
840 LPCSTR /* pszCmd */, | |
841 LPCSTR /* pszParam */, | |
842 int /* iShowCmd */, | |
10 | 843 int idHWnd) |
844 { | |
845 HWND hWnd = m_hWnd[idHWnd]; | |
846 | |
847 // Show and bring vim instance to foreground | |
848 if (IsIconic(hWnd) != 0) | |
849 ShowWindow(hWnd, SW_RESTORE); | |
850 else | |
851 ShowWindow(hWnd, SW_SHOW); | |
852 SetForegroundWindow(hWnd); | |
853 | |
854 // Post the selected files to the vim instance | |
855 PostMessage(hWnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0); | |
856 | |
857 return NOERROR; | |
858 } | |
859 | |
1686 | 860 STDMETHODIMP CShellExt::GetCommandString(UINT_PTR /* idCmd */, |
10 | 861 UINT uFlags, |
1686 | 862 UINT FAR * /* reserved */, |
10 | 863 LPSTR pszName, |
864 UINT cchMax) | |
865 { | |
866 if (uFlags == GCS_HELPTEXT && cchMax > 35) | |
867 lstrcpy(pszName, _("Edits the selected file(s) with Vim")); | |
868 | |
869 return NOERROR; | |
870 } | |
871 | |
872 BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam) | |
873 { | |
415 | 874 char temp[BUFSIZE]; |
10 | 875 |
876 // First do a bunch of check | |
877 // No invisible window | |
878 if (!IsWindowVisible(hWnd)) return TRUE; | |
879 // No child window ??? | |
880 // if (GetParent(hWnd)) return TRUE; | |
881 // Class name should be Vim, if failed to get class name, return | |
882 if (GetClassName(hWnd, temp, sizeof(temp)) == 0) | |
883 return TRUE; | |
884 // Compare class name to that of vim, if not, return | |
885 if (_strnicmp(temp, "vim", sizeof("vim")) != 0) | |
886 return TRUE; | |
887 // First check if the number of vim instance exceeds MAX_HWND | |
888 CShellExt *cs = (CShellExt*) lParam; | |
889 if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE; | |
890 // Now we get the vim window, put it into some kind of array | |
891 cs->m_hWnd[cs->m_cntOfHWnd] = hWnd; | |
892 cs->m_cntOfHWnd ++; | |
893 | |
894 return TRUE; // continue enumeration (otherwise this would be false) | |
895 } | |
896 | |
6805 | 897 BOOL CShellExt::LoadMenuIcon() |
898 { | |
899 char vimExeFile[BUFSIZE]; | |
900 getGvimName(vimExeFile, 1); | |
901 if (vimExeFile[0] == '\0') | |
902 return FALSE; | |
903 HICON hVimIcon; | |
904 if (ExtractIconEx(vimExeFile, 0, NULL, &hVimIcon, 1) == 0) | |
905 return FALSE; | |
906 m_hVimIconBitmap = IconToBitmap(hVimIcon, | |
907 GetSysColorBrush(COLOR_MENU), | |
908 GetSystemMetrics(SM_CXSMICON), | |
909 GetSystemMetrics(SM_CYSMICON)); | |
910 return TRUE; | |
911 } | |
912 | |
10 | 913 static char * |
914 searchpath(char *name) | |
915 { | |
415 | 916 static char widename[2 * BUFSIZE]; |
917 static char location[2 * BUFSIZE + 2]; | |
10 | 918 |
919 // There appears to be a bug in FindExecutableA() on Windows NT. | |
920 // Use FindExecutableW() instead... | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
921 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)name, -1, |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
922 (LPWSTR)widename, BUFSIZE); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
923 if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"", |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
924 (LPWSTR)location) > (HINSTANCE)32) |
10 | 925 { |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
926 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1, |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
927 (LPSTR)widename, 2 * BUFSIZE, NULL, NULL); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
8180
diff
changeset
|
928 return widename; |
10 | 929 } |
1366 | 930 return (char *)""; |
10 | 931 } |
932 | |
933 STDMETHODIMP CShellExt::InvokeGvim(HWND hParent, | |
1686 | 934 LPCSTR /* pszWorkingDir */, |
935 LPCSTR /* pszCmd */, | |
936 LPCSTR /* pszParam */, | |
937 int /* iShowCmd */) | |
10 | 938 { |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
939 wchar_t m_szFileUserClickedOn[BUFSIZE]; |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
940 wchar_t cmdStrW[BUFSIZE]; |
10 | 941 UINT i; |
942 | |
943 for (i = 0; i < cbFiles; i++) | |
944 { | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
945 DragQueryFileW((HDROP)medium.hGlobal, |
10 | 946 i, |
947 m_szFileUserClickedOn, | |
948 sizeof(m_szFileUserClickedOn)); | |
949 | |
6805 | 950 getGvimInvocationW(cmdStrW); |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
951 wcscat(cmdStrW, L" \""); |
10 | 952 |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
953 if ((wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 2) < BUFSIZE) |
10 | 954 { |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
955 wcscat(cmdStrW, m_szFileUserClickedOn); |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
956 wcscat(cmdStrW, L"\""); |
10 | 957 |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
958 STARTUPINFOW si; |
10 | 959 PROCESS_INFORMATION pi; |
960 | |
961 ZeroMemory(&si, sizeof(si)); | |
962 si.cb = sizeof(si); | |
963 | |
964 // Start the child process. | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
965 if (!CreateProcessW(NULL, // No module name (use command line). |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
966 cmdStrW, // Command line. |
10 | 967 NULL, // Process handle not inheritable. |
968 NULL, // Thread handle not inheritable. | |
969 FALSE, // Set handle inheritance to FALSE. | |
3008 | 970 oldenv == NULL ? 0 : CREATE_UNICODE_ENVIRONMENT, |
971 oldenv, // Use unmodified environment block. | |
10 | 972 NULL, // Use parent's starting directory. |
973 &si, // Pointer to STARTUPINFO structure. | |
974 &pi) // Pointer to PROCESS_INFORMATION structure. | |
975 ) | |
976 { | |
977 MessageBox( | |
978 hParent, | |
979 _("Error creating process: Check if gvim is in your path!"), | |
980 _("gvimext.dll error"), | |
981 MB_OK); | |
982 } | |
983 else | |
984 { | |
985 CloseHandle( pi.hProcess ); | |
986 CloseHandle( pi.hThread ); | |
987 } | |
988 } | |
989 else | |
990 { | |
991 MessageBox( | |
992 hParent, | |
993 _("Path length too long!"), | |
994 _("gvimext.dll error"), | |
995 MB_OK); | |
996 } | |
997 } | |
998 | |
999 return NOERROR; | |
1000 } | |
1001 | |
1002 | |
1003 STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent, | |
1686 | 1004 LPCSTR /* pszWorkingDir */, |
1005 LPCSTR /* pszCmd */, | |
1006 LPCSTR /* pszParam */, | |
1007 int /* iShowCmd */, | |
10 | 1008 int useDiff) |
1009 { | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1010 wchar_t m_szFileUserClickedOn[BUFSIZE]; |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1011 wchar_t *cmdStrW; |
10 | 1012 size_t cmdlen; |
1013 size_t len; | |
1014 UINT i; | |
1015 | |
415 | 1016 cmdlen = BUFSIZE; |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1017 cmdStrW = (wchar_t *) malloc(cmdlen * sizeof(wchar_t)); |
15154
eb0d8065d3f8
patch 8.1.0587: GvimExt: realloc() failing is not handled properly
Bram Moolenaar <Bram@vim.org>
parents:
14962
diff
changeset
|
1018 if (cmdStrW == NULL) |
15158
a9340baa872f
patch 8.1.0589: compilation error in gvimext.cpp
Bram Moolenaar <Bram@vim.org>
parents:
15154
diff
changeset
|
1019 return E_FAIL; |
6805 | 1020 getGvimInvocationW(cmdStrW); |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1021 |
10 | 1022 if (useDiff) |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1023 wcscat(cmdStrW, L" -d"); |
10 | 1024 for (i = 0; i < cbFiles; i++) |
1025 { | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1026 DragQueryFileW((HDROP)medium.hGlobal, |
10 | 1027 i, |
1028 m_szFileUserClickedOn, | |
1029 sizeof(m_szFileUserClickedOn)); | |
1030 | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1031 len = wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 4; |
10 | 1032 if (len > cmdlen) |
1033 { | |
415 | 1034 cmdlen = len + BUFSIZE; |
15154
eb0d8065d3f8
patch 8.1.0587: GvimExt: realloc() failing is not handled properly
Bram Moolenaar <Bram@vim.org>
parents:
14962
diff
changeset
|
1035 wchar_t *cmdStrW_new = (wchar_t *)realloc(cmdStrW, cmdlen * sizeof(wchar_t)); |
eb0d8065d3f8
patch 8.1.0587: GvimExt: realloc() failing is not handled properly
Bram Moolenaar <Bram@vim.org>
parents:
14962
diff
changeset
|
1036 if (cmdStrW_new == NULL) |
15158
a9340baa872f
patch 8.1.0589: compilation error in gvimext.cpp
Bram Moolenaar <Bram@vim.org>
parents:
15154
diff
changeset
|
1037 { |
a9340baa872f
patch 8.1.0589: compilation error in gvimext.cpp
Bram Moolenaar <Bram@vim.org>
parents:
15154
diff
changeset
|
1038 free(cmdStrW); |
a9340baa872f
patch 8.1.0589: compilation error in gvimext.cpp
Bram Moolenaar <Bram@vim.org>
parents:
15154
diff
changeset
|
1039 return E_FAIL; |
a9340baa872f
patch 8.1.0589: compilation error in gvimext.cpp
Bram Moolenaar <Bram@vim.org>
parents:
15154
diff
changeset
|
1040 } |
15154
eb0d8065d3f8
patch 8.1.0587: GvimExt: realloc() failing is not handled properly
Bram Moolenaar <Bram@vim.org>
parents:
14962
diff
changeset
|
1041 cmdStrW = cmdStrW_new; |
10 | 1042 } |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1043 wcscat(cmdStrW, L" \""); |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1044 wcscat(cmdStrW, m_szFileUserClickedOn); |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1045 wcscat(cmdStrW, L"\""); |
10 | 1046 } |
1047 | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1048 STARTUPINFOW si; |
10 | 1049 PROCESS_INFORMATION pi; |
1050 | |
1051 ZeroMemory(&si, sizeof(si)); | |
1052 si.cb = sizeof(si); | |
1053 | |
1054 // Start the child process. | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1055 if (!CreateProcessW(NULL, // No module name (use command line). |
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1056 cmdStrW, // Command line. |
10 | 1057 NULL, // Process handle not inheritable. |
1058 NULL, // Thread handle not inheritable. | |
1059 FALSE, // Set handle inheritance to FALSE. | |
3008 | 1060 oldenv == NULL ? 0 : CREATE_UNICODE_ENVIRONMENT, |
1061 oldenv, // Use unmodified environment block. | |
10 | 1062 NULL, // Use parent's starting directory. |
1063 &si, // Pointer to STARTUPINFO structure. | |
1064 &pi) // Pointer to PROCESS_INFORMATION structure. | |
1065 ) | |
1066 { | |
1067 MessageBox( | |
1068 hParent, | |
1069 _("Error creating process: Check if gvim is in your path!"), | |
1070 _("gvimext.dll error"), | |
1071 MB_OK); | |
1072 } | |
1073 else | |
1074 { | |
1075 CloseHandle(pi.hProcess); | |
1076 CloseHandle(pi.hThread); | |
1077 } | |
2295
b9bc9c5df131
Support wide file names in gvimext. (Szabolcs Horvat)
Bram Moolenaar <bram@vim.org>
parents:
1953
diff
changeset
|
1078 free(cmdStrW); |
10 | 1079 |
1080 return NOERROR; | |
1081 } |