Mercurial > hg > xemacs-beta
annotate src/win32.c @ 5139:a48ef26d87ee
Clean up prototypes for Lisp variables/symbols. Put decls for them with
the other stuff related to the file they're in. In the process, fix a few
places with incorrect initialization of symbols and variables.
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-03-12 Ben Wing <ben@xemacs.org>
* lisp.h:
* lisp.h (redo-symbols): Removed.
Put the Lisp variables and symbols where they belong, with other
stuff related to the file they're in.
* event-Xt.c (THIS_IS_X):
* event-Xt.c (syms_of_event_Xt):
* event-Xt.c (reinit_vars_of_event_Xt):
* event-gtk.c:
* event-gtk.c (syms_of_event_gtk):
* event-gtk.c (reinit_vars_of_event_gtk):
* event-stream.c:
* event-stream.c (syms_of_event_stream):
* event-stream.c (reinit_vars_of_event_stream):
* events.c (reinit_vars_of_events):
* events.c (vars_of_events):
`sans-modifiers' was defsymbol'ed more than once. Move it to
events-stream.c. `self-insert-command' was defsymbol'ed more than once.
Vevent_resource should be staticpro_nodump()ed as it's declared in
a reinit_*() method.
* lread.c (vars_of_lread):
Vfile_domain wasn't staticpro'ed.
* minibuf.c:
* minibuf.c (reinit_complex_vars_of_minibuf):
Vminibuffer_zero and Vecho_area_buffer weren't staticpro'ed.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 12 Mar 2010 20:23:50 -0600 |
parents | 3c3c1d139863 |
children | 308d34e9f07d |
rev | line source |
---|---|
442 | 1 /* Utility routines for XEmacs on Windows 9x, NT and Cygwin. |
2367 | 2 Copyright (C) 2000, 2001, 2002, 2004 Ben Wing. |
442 | 3 |
4 This file is part of XEmacs. | |
5 | |
6 XEmacs is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with XEmacs; see the file COPYING. If not, write to the Free | |
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 02111-1307, USA. */ | |
20 | |
21 #include <config.h> | |
22 #include "lisp.h" | |
23 | |
24 #include "buffer.h" | |
771 | 25 #include "console-msw.h" |
2526 | 26 #include "hash.h" |
27 #include "profile.h" | |
611 | 28 |
771 | 29 #include "sysfile.h" |
30 #include "sysproc.h" | |
859 | 31 #include "syssignal.h" |
611 | 32 #include "systime.h" |
442 | 33 |
2367 | 34 |
35 | |
36 /* | |
37 | |
38 Info on Windows issues: | |
39 | |
40 (Info-goto-node "(internals)Interface to MS Windows") | |
41 | |
42 ------- @file{src/config.h}.in vs. @file{nt/xemacs.mak} ------- | |
43 | |
44 See @file{src/config.h.in} more more info. | |
45 */ | |
46 | |
771 | 47 /* Control conversion of upper case file names to lower case. |
48 nil means no, t means yes. */ | |
49 Lisp_Object Vmswindows_downcase_file_names; | |
50 | |
2526 | 51 struct hash_table *mswindows_read_link_hash; |
52 | |
771 | 53 int mswindows_windows9x_p; |
2526 | 54 Boolint mswindows_shortcuts_are_symlinks; |
771 | 55 |
442 | 56 pfSwitchToThread_t xSwitchToThread; |
57 | |
771 | 58 pfNetUserEnum_t xNetUserEnum; |
59 pfNetApiBufferFree_t xNetApiBufferFree; | |
60 | |
61 /* Convert a filename in standard Win32 format into our internal format | |
62 (which may be significantly different if we're running on Cygwin), and | |
63 turn it into a file: URL. Return a newly malloc()ed string. | |
442 | 64 |
771 | 65 #### This comes from code that just prepended `file:', which is not |
66 good. See comment in mswindows_dde_callback(), case XTYP_EXECUTE. | |
67 */ | |
867 | 68 Ibyte * |
69 urlify_filename (Ibyte *filename) | |
771 | 70 { |
867 | 71 Ibyte *pseudo_url; |
771 | 72 |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
73 INTERNAL_MSWIN_TO_LOCAL_FILE_FORMAT (filename, filename); |
867 | 74 pseudo_url = xnew_array (Ibyte, 5 + qxestrlen (filename) + 1); |
2367 | 75 qxestrcpy_ascii (pseudo_url, "file:"); |
771 | 76 qxestrcat (pseudo_url, filename); |
77 /* URL's only have /, no backslash */ | |
78 for (filename = pseudo_url; *filename; filename++) | |
79 { | |
80 if (*filename == '\\') | |
81 *filename = '/'; | |
82 } | |
442 | 83 |
771 | 84 return pseudo_url; |
85 } | |
531 | 86 |
826 | 87 /* Convert a Win32 file name in tstr format into a local-format file name |
88 in internal format. */ | |
89 | |
442 | 90 Lisp_Object |
826 | 91 tstr_to_local_file_format (Extbyte *path) |
442 | 92 { |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
93 Ibyte *pathint = TSTR_TO_ITEXT (path); |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
94 INTERNAL_MSWIN_TO_LOCAL_FILE_FORMAT (pathint, pathint); |
771 | 95 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
96 return build_istring (pathint); |
771 | 97 } |
98 | |
99 /* Normalize filename by converting all path separators to the specified | |
100 separator. Also conditionally convert all-upper-case path name | |
101 components to lower case. Return a newly malloc()ed string. | |
102 */ | |
103 | |
867 | 104 Ibyte * |
105 mswindows_canonicalize_filename (Ibyte *name) | |
771 | 106 { |
867 | 107 Ibyte *fp = name; |
771 | 108 DECLARE_EISTRING (newname); |
109 DECLARE_EISTRING (component); | |
110 int do_casefrob = 1; | |
442 | 111 |
771 | 112 /* Always lower-case drive letters a-z, even if the filesystem |
113 preserves case in filenames. | |
114 This is so filenames can be compared by string comparison | |
115 functions that are case-sensitive. Even case-preserving filesystems | |
116 do not distinguish case in drive letters. */ | |
117 if (name[0] >= 'A' && name[0] <= 'Z' && name[1] == ':') | |
118 { | |
119 eicat_ch (newname, name[0] + 'a' - 'A'); | |
120 eicat_ch (newname, ':'); | |
121 fp += 2; | |
122 } | |
123 | |
124 while (1) | |
125 { | |
867 | 126 Ichar ch = itext_ichar (fp); |
771 | 127 if (LOWERCASEP (0, ch)) |
128 do_casefrob = 0; /* don't convert this element */ | |
442 | 129 |
771 | 130 if (ch == 0 || IS_ANY_SEP (ch)) |
131 { | |
132 if (do_casefrob && !NILP (Vmswindows_downcase_file_names)) | |
133 eilwr (component); | |
134 do_casefrob = 1; | |
135 eicat_ei (newname, component); | |
136 eireset (component); | |
137 if (IS_DIRECTORY_SEP (ch)) | |
138 eicat_ch (newname, DIRECTORY_SEP); | |
139 else if (ch) | |
140 eicat_ch (newname, ch); | |
141 else | |
142 break; | |
143 } | |
144 else | |
145 eicat_ch (component, ch); | |
146 | |
867 | 147 INC_IBYTEPTR (fp); |
771 | 148 } |
149 | |
150 return eicpyout_malloc (newname, 0); | |
442 | 151 } |
152 | |
814 | 153 Extbyte * |
154 mswindows_get_module_file_name (void) | |
155 { | |
156 Extbyte *path = NULL; | |
157 int bufsize = 4096; | |
158 int cchpathsize; | |
159 | |
160 while (1) | |
161 { | |
162 path = (Extbyte *) xrealloc (path, bufsize * XETCHAR_SIZE); | |
163 cchpathsize = qxeGetModuleFileName (NULL, path, bufsize); | |
164 if (!cchpathsize) | |
165 return 0; | |
166 if (cchpathsize + 1 <= bufsize) | |
167 break; | |
168 bufsize *= 2; | |
169 } | |
170 | |
171 return path; | |
172 } | |
173 | |
442 | 174 static void |
175 init_potentially_nonexistent_functions (void) | |
176 { | |
771 | 177 HMODULE h_kernel = qxeGetModuleHandle (XETEXT ("kernel32")); |
531 | 178 /* the following does not seem to get mapped in automatically */ |
771 | 179 HMODULE h_netapi = qxeLoadLibrary (XETEXT ("netapi32.dll")); |
442 | 180 |
181 if (h_kernel) | |
182 { | |
183 xSwitchToThread = | |
184 (pfSwitchToThread_t) GetProcAddress (h_kernel, "SwitchToThread"); | |
185 } | |
186 | |
531 | 187 if (h_netapi) |
188 { | |
189 xNetUserEnum = | |
190 (pfNetUserEnum_t) GetProcAddress (h_netapi, "NetUserEnum"); | |
191 xNetApiBufferFree = | |
192 (pfNetApiBufferFree_t) GetProcAddress (h_netapi, "NetApiBufferFree"); | |
193 } | |
442 | 194 } |
195 | |
771 | 196 static Lisp_Object |
197 mswindows_lisp_error_1 (int errnum, int no_recurse) | |
198 { | |
199 LPTSTR lpMsgBuf; | |
200 Lisp_Object result; | |
867 | 201 Ibyte *inres; |
771 | 202 Bytecount len; |
203 int i; | |
204 | |
205 /* The docs for FormatMessage say: | |
206 | |
207 If you pass a specific LANGID in this parameter, FormatMessage | |
208 will return a message for that LANGID only. If the function | |
209 cannot find a message for that LANGID, it returns | |
210 ERROR_RESOURCE_LANG_NOT_FOUND. If you pass in zero, FormatMessage | |
211 looks for a message for LANGIDs in the following order: | |
212 | |
213 Language neutral | |
214 Thread LANGID, based on the thread's locale value | |
215 User default LANGID, based on the user's default locale value | |
216 System default LANGID, based on the system default locale value | |
217 US English | |
218 | |
219 If FormatMessage doesn't find a message for any of the preceding | |
220 LANGIDs, it returns any language message string that is present. If | |
221 that fails, it returns ERROR_RESOURCE_LANG_NOT_FOUND. (Note, this is | |
222 returned through GetLastError(), not the return value.) | |
223 | |
224 #### what the hell is "language neutral"? i can find no info on this. | |
225 so let's do our own language first. | |
226 */ | |
227 | |
228 for (i = 0; ; i++) | |
229 { | |
230 int lang = 0; | |
231 int retval; | |
232 | |
233 switch (i) | |
234 { | |
235 #ifdef MULE | |
236 /* Urk! Windows 95 doesn't let you set the thread locale! | |
237 so we have to maintain our own. */ | |
238 case 0: lang = LANGIDFROMLCID (mswindows_current_locale ()); break; | |
239 case 1: lang = 0; break; | |
240 #else | |
241 case 0: lang = 0; break; | |
242 #endif | |
2500 | 243 default: ABORT (); |
771 | 244 } |
245 | |
246 retval = qxeFormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | |
247 | FORMAT_MESSAGE_FROM_SYSTEM, | |
248 NULL, errnum, lang, | |
249 /* yeah, i'm casting a char ** to a char *. | |
250 ya gotta problem widdat? */ | |
251 (Extbyte *) &lpMsgBuf, 0, NULL); | |
252 | |
253 if (!retval) | |
254 { | |
255 if (lang != 0) | |
256 continue; | |
257 | |
258 if (no_recurse) | |
259 return emacs_sprintf_string | |
260 ("Unknown error code %d (error return %ld from FormatMessage())", | |
261 errnum, GetLastError ()); | |
262 else | |
263 return emacs_sprintf_string | |
264 ("Unknown error code %d (error return %s from FormatMessage())", | |
265 /* It's OK, emacs_sprintf_string disables GC explicitly */ | |
266 errnum, XSTRING_DATA (mswindows_lisp_error_1 (errnum, 1))); | |
267 } | |
268 else | |
269 break; | |
270 } | |
271 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
272 inres = TSTR_TO_ITEXT (lpMsgBuf); |
771 | 273 len = qxestrlen (inres); |
274 /* Messages tend to end with a period and newline */ | |
2367 | 275 if (len >= 3 && !qxestrcmp_ascii (inres + len - 3, ".\r\n")) |
771 | 276 len -= 3; |
277 result = make_string (inres, len); | |
278 | |
279 LocalFree (lpMsgBuf); | |
280 return result; | |
281 } | |
282 | |
283 Lisp_Object | |
284 mswindows_lisp_error (int errnum) | |
285 { | |
286 return mswindows_lisp_error_1 (errnum, 0); | |
287 } | |
288 | |
289 void | |
4932 | 290 mswindows_output_last_error (const Ascbyte *frob) |
771 | 291 { |
292 int errval = GetLastError (); | |
293 Lisp_Object errmess = mswindows_lisp_error (errval); | |
294 | |
295 stderr_out ("last error during %s is %d: %s\n", | |
296 frob, errval, XSTRING_DATA (errmess)); | |
297 } | |
298 | |
299 DOESNT_RETURN | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
300 mswindows_report_process_error (const Ascbyte *reason, Lisp_Object data, |
771 | 301 int errnum) |
302 { | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
303 signal_error_2 (Qprocess_error, reason, mswindows_lisp_error (errnum), data); |
771 | 304 } |
305 | |
442 | 306 DEFUN ("mswindows-shell-execute", Fmswindows_shell_execute, 2, 4, 0, /* |
307 Get Windows to perform OPERATION on DOCUMENT. | |
308 This is a wrapper around the ShellExecute system function, which | |
309 invokes the application registered to handle OPERATION for DOCUMENT. | |
310 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be | |
311 nil for the default action), and DOCUMENT is typically the name of a | |
312 document file or URL, but can also be a program executable to run or | |
313 a directory to open in the Windows Explorer. | |
314 | |
315 If DOCUMENT is a program executable, PARAMETERS can be a string | |
316 containing command line parameters, but otherwise should be nil. | |
317 | |
318 SHOW-FLAG can be used to control whether the invoked application is hidden | |
319 or minimized. If SHOW-FLAG is nil, the application is displayed normally, | |
320 otherwise it is an integer representing a ShowWindow flag: | |
321 | |
322 0 - start hidden | |
323 1 - start normally | |
324 3 - start maximized | |
325 6 - start minimized | |
326 */ | |
327 (operation, document, parameters, show_flag)) | |
328 { | |
329 /* Encode filename and current directory. */ | |
330 Lisp_Object current_dir = Ffile_name_directory (document); | |
331 int ret; | |
332 | |
333 CHECK_STRING (document); | |
334 | |
335 if (NILP (current_dir)) | |
336 current_dir = current_buffer->directory; | |
337 | |
771 | 338 { |
339 Extbyte *opext = NULL; | |
340 Extbyte *parmext = NULL; | |
341 Extbyte *path = NULL; | |
342 Extbyte *doc = NULL; | |
442 | 343 |
771 | 344 if (STRINGP (operation)) |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
345 opext = LISP_STRING_TO_TSTR (operation); |
2526 | 346 /* #### What about path names, which may be links? */ |
771 | 347 if (STRINGP (parameters)) |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
348 parmext = LISP_STRING_TO_TSTR (parameters); |
771 | 349 if (STRINGP (current_dir)) |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
350 LISP_LOCAL_FILE_FORMAT_TO_TSTR (current_dir, path); |
826 | 351 if (STRINGP (document)) |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
352 LISP_LOCAL_FILE_FORMAT_MAYBE_URL_TO_TSTR (document, doc); |
442 | 353 |
771 | 354 ret = (int) qxeShellExecute (NULL, opext, doc, parmext, path, |
355 (INTP (show_flag) ? | |
356 XINT (show_flag) : SW_SHOWDEFAULT)); | |
357 } | |
442 | 358 |
771 | 359 if (ret <= 32) |
360 { | |
361 /* Convert to more standard errors */ | |
362 #define FROB(a, b) if (ret == a) ret = b | |
363 FROB (SE_ERR_ACCESSDENIED, ERROR_ACCESS_DENIED); | |
364 FROB (SE_ERR_ASSOCINCOMPLETE, ERROR_NO_ASSOCIATION); | |
365 FROB (SE_ERR_DDEBUSY, ERROR_DDE_FAIL); | |
366 FROB (SE_ERR_DDEFAIL, ERROR_DDE_FAIL); | |
367 FROB (SE_ERR_DDETIMEOUT, ERROR_DDE_FAIL); | |
368 FROB (SE_ERR_DLLNOTFOUND, ERROR_DLL_NOT_FOUND); | |
369 FROB (SE_ERR_FNF, ERROR_FILE_NOT_FOUND); | |
370 FROB (SE_ERR_NOASSOC, ERROR_NO_ASSOCIATION); | |
371 FROB (SE_ERR_OOM, ERROR_NOT_ENOUGH_MEMORY); | |
372 FROB (SE_ERR_PNF, ERROR_PATH_NOT_FOUND); | |
373 FROB (SE_ERR_SHARE, ERROR_SHARING_VIOLATION); | |
374 #undef FROB | |
375 | |
376 mswindows_report_process_error ("Running ShellExecute", | |
377 ret == ERROR_PATH_NOT_FOUND ? | |
378 list4 (Qunbound, operation, document, | |
379 current_dir) : | |
380 list3 (Qunbound, operation, document), | |
381 ret); | |
382 } | |
442 | 383 |
771 | 384 return Qt; |
442 | 385 } |
386 | |
673 | 387 #ifdef CYGWIN |
388 DEFUN ("mswindows-cygwin-to-win32-path", Fmswindows_cygwin_to_win32_path, 1, 1, 0, /* | |
389 Get the cygwin environment to convert the Unix PATH to win32 format. | |
390 No expansion is performed, all conversion is done by the cygwin runtime. | |
391 */ | |
392 (path)) | |
393 { | |
867 | 394 Ibyte *p; |
673 | 395 CHECK_STRING (path); |
396 | |
397 /* There appears to be a bug in the cygwin conversion routines in | |
398 that they are not idempotent. */ | |
399 p = XSTRING_DATA (path); | |
400 if (isalpha (p[0]) && (IS_DEVICE_SEP (p[1]))) | |
401 return path; | |
402 | |
403 /* Use mule and cygwin-safe APIs top get at file data. */ | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
404 LOCAL_FILE_FORMAT_TO_INTERNAL_MSWIN (p, p); |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
405 return build_istring (p); |
673 | 406 } |
407 #endif | |
408 | |
2526 | 409 struct read_link_hash |
410 { | |
411 Ibyte *resolved; | |
412 DWORD ticks; | |
413 }; | |
414 | |
415 static Ibyte * | |
416 mswindows_read_link_1 (const Ibyte *fname) | |
417 { | |
4879
c356806cc933
fix compile errors when --with-msw=no
Ben Wing <ben@xemacs.org>
parents:
4854
diff
changeset
|
418 #if defined (NO_CYGWIN_COM_SUPPORT) || !defined (HAVE_MS_WINDOWS) |
2526 | 419 return NULL; |
420 #else | |
421 Ibyte *retval = NULL; | |
422 Extbyte *fnameext; | |
423 HANDLE fh; | |
424 struct read_link_hash *rlh; | |
425 DWORD ticks; | |
426 | |
427 /* The call below to resolve a link is rather time-consuming. | |
428 I tried implementing a simple cache based on creation and write time | |
429 of the file, but that didn't help enough -- maybe 30% faster but still | |
430 a lot of time spent here. So just do something cheesy and don't | |
431 check again if we've recently (< a second) done so. */ | |
432 | |
433 if (!mswindows_read_link_hash) | |
434 mswindows_read_link_hash = make_string_hash_table (1000); | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
435 fnameext = ITEXT_TO_TSTR (fname); |
2526 | 436 |
437 /* See if we can find a cached value. */ | |
438 | |
439 /* The intermediate cast fools gcc into not outputting strict-aliasing | |
440 complaints */ | |
441 ticks = GetTickCount (); | |
442 if (!gethash (fname, mswindows_read_link_hash, | |
443 (const void **) (void *) &rlh)) | |
444 { | |
445 rlh = xnew_and_zero (struct read_link_hash); | |
446 puthash (qxestrdup (fname), rlh, mswindows_read_link_hash); | |
447 } | |
448 else if (ticks - rlh->ticks < 1000) | |
449 { | |
450 return rlh->resolved ? qxestrdup (rlh->resolved) : NULL; | |
451 } | |
452 | |
453 rlh->ticks = ticks; | |
454 | |
455 /* Retrieve creation/write time of link file. */ | |
456 | |
457 /* No access rights required to get info. */ | |
458 if ((fh = qxeCreateFile (fnameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) | |
459 == INVALID_HANDLE_VALUE) | |
460 { | |
461 CloseHandle (fh); | |
462 return NULL; | |
463 } | |
464 | |
465 CloseHandle (fh); | |
466 | |
467 /* #### | |
468 | |
469 Note the following in the docs: | |
470 | |
471 Note: The IShellLink interface has an ANSI version | |
472 (IShellLinkA) and a Unicode version (IShellLinkW). The | |
473 version that will be used depends on whether you compile | |
474 for ANSI or Unicode. However, Microsoft® Windows 95 and | |
475 Microsoft® Windows 98 only support IShellLinkA. | |
476 | |
477 We haven't yet implemented COM support in the | |
478 Unicode-splitting library. I don't quite understand how | |
479 COM works yet, but it looks like what's happening is | |
480 that the ShellLink class implements both the IShellLinkA | |
481 and IShellLinkW interfaces. To make this work at | |
482 run-time, we have to do something like this: | |
483 | |
484 -- define a new interface qxeIShellLink that uses | |
485 Extbyte * instead of LPSTR or LPWSTR. (not totally | |
486 necessary since Extbyte * == LPSTR). | |
487 | |
488 -- define a new class qxeShellLink that implements | |
489 qxeIShellLink. the methods on this class need to create | |
490 a shadow ShellLink object to do all the real work, and | |
491 call the corresponding function from either the | |
492 IShellLinkA or IShellLinkW interfaces on this object, | |
493 depending on whether XEUNICODE_P is defined. | |
494 | |
495 -- with appropriate preprocessor magic, of course, we | |
496 could make things appear transparent; but we've decided | |
497 not to do preprocessor magic for the moment. | |
498 */ | |
499 | |
500 /* #### Not Unicode-split for the moment; we have to do it | |
501 ourselves. */ | |
502 if (XEUNICODE_P) | |
503 { | |
504 IShellLinkW *psl; | |
505 | |
506 if (CoCreateInstance ( | |
507 XECOMID (CLSID_ShellLink), | |
508 NULL, | |
509 CLSCTX_INPROC_SERVER, | |
510 XECOMID (IID_IShellLinkW), | |
511 &VOIDP_CAST (psl)) == S_OK) | |
512 { | |
513 IPersistFile *ppf; | |
514 | |
515 if (XECOMCALL2 (psl, QueryInterface, | |
516 XECOMID (IID_IPersistFile), | |
517 &VOIDP_CAST (ppf)) == S_OK) | |
518 { | |
519 Extbyte *fname_unicode; | |
520 WIN32_FIND_DATAW wfd; | |
4854 | 521 LPWSTR resolved = alloca_array (WCHAR, PATH_MAX_TCHAR + 1); |
2526 | 522 |
523 /* Always Unicode. Not obvious from the | |
524 IPersistFile documentation, but look under | |
525 "Shell Link" for example code. */ | |
526 fname_unicode = fnameext; | |
527 | |
528 if (XECOMCALL2 (ppf, Load, | |
529 (LPWSTR) fname_unicode, | |
530 STGM_READ) == S_OK && | |
531 /* #### YUCK! Docs read | |
532 | |
533 cchMaxPath | |
534 | |
535 Maximum number of bytes to copy to the buffer pointed | |
536 to by the pszFile parameter. | |
537 | |
538 But "cch" means "count of characters", not bytes. | |
539 I'll assume the doc writers messed up and the | |
540 programmer was correct. Also, this approach is safe | |
541 even if it's actually the other way around. */ | |
542 #if defined (CYGWIN_HEADERS) && W32API_INSTALLED_VER < W32API_VER(2,2) | |
543 /* Another Cygwin prototype error, | |
544 fixed in v2.2 of w32api */ | |
545 XECOMCALL4 (psl, GetPath, (LPSTR) resolved, | |
4854 | 546 PATH_MAX_TCHAR, &wfd, 0) |
2526 | 547 #else |
548 XECOMCALL4 (psl, GetPath, resolved, | |
4854 | 549 PATH_MAX_TCHAR, &wfd, 0) |
2526 | 550 #endif |
551 == S_OK) | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
552 retval = TSTR_TO_ITEXT_MALLOC (resolved); |
2526 | 553 |
554 XECOMCALL0 (ppf, Release); | |
555 } | |
556 | |
557 XECOMCALL0 (psl, Release); | |
558 } | |
559 } | |
560 else | |
561 { | |
562 IShellLinkA *psl; | |
563 | |
564 if (CoCreateInstance ( | |
565 XECOMID (CLSID_ShellLink), | |
566 NULL, | |
567 CLSCTX_INPROC_SERVER, | |
568 XECOMID (IID_IShellLinkA), | |
569 &VOIDP_CAST (psl)) == S_OK) | |
570 { | |
571 IPersistFile *ppf; | |
572 | |
573 if (XECOMCALL2 (psl, QueryInterface, | |
574 XECOMID (IID_IPersistFile), | |
575 &VOIDP_CAST (ppf)) == S_OK) | |
576 { | |
577 Extbyte *fname_unicode; | |
578 WIN32_FIND_DATAA wfd; | |
4854 | 579 LPSTR resolved = alloca_array (CHAR, PATH_MAX_TCHAR + 1); |
2526 | 580 |
581 /* Always Unicode. Not obvious from the | |
582 IPersistFile documentation, but look under | |
583 "Shell Link" for example code. */ | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
584 fname_unicode = ITEXT_TO_EXTERNAL (fname, Qmswindows_unicode); |
2526 | 585 |
586 if (XECOMCALL2 (ppf, Load, | |
587 (LPWSTR) fname_unicode, | |
588 STGM_READ) == S_OK | |
589 && XECOMCALL4 (psl, GetPath, resolved, | |
4854 | 590 PATH_MAX_TCHAR, &wfd, 0) == S_OK) |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
591 retval = TSTR_TO_ITEXT_MALLOC (resolved); |
2526 | 592 |
593 XECOMCALL0 (ppf, Release); | |
594 } | |
595 | |
596 XECOMCALL0 (psl, Release); | |
597 } | |
598 } | |
599 | |
600 /* Cache newly found value */ | |
601 if (rlh->resolved) | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
602 xfree (rlh->resolved); |
2526 | 603 rlh->resolved = retval ? qxestrdup (retval) : NULL; |
604 | |
605 return retval; | |
606 #endif /* NO_CYGWIN_COM_SUPPORT */ | |
607 } | |
608 | |
609 /* Resolve a file that may be a shortcut. Accepts either a file ending | |
610 with .LNK or without the ending. If a shortcut is found, returns | |
611 a value that you must xfree(); otherwise NULL. */ | |
612 | |
613 Ibyte * | |
614 mswindows_read_link (const Ibyte *fname) | |
615 { | |
616 int len = qxestrlen (fname); | |
617 if (len > 4 && !qxestrcasecmp_ascii (fname + len - 4, ".LNK")) | |
618 return mswindows_read_link_1 (fname); | |
619 else | |
620 { | |
621 DECLARE_EISTRING (name2); | |
622 | |
623 eicpy_rawz (name2, fname); | |
624 eicat_ascii (name2, ".LNK"); | |
625 return mswindows_read_link_1 (eidata (name2)); | |
626 } | |
627 } | |
628 | |
629 | |
613 | 630 #if defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) |
631 | |
632 /* setitimer() does not exist on native MS Windows, and appears broken | |
633 on Cygwin (random lockups when BROKEN_SIGIO is defined), so we | |
634 emulate in both cases by using multimedia timers. Furthermore, | |
635 the lockups still occur on Cygwin even when we do nothing but | |
636 use the standard signalling mechanism -- so we have to emulate | |
637 that, too. (But only for timeouts -- we have to use the standard | |
638 mechanism for SIGCHLD. Yuck.) | |
639 */ | |
640 | |
641 /*--------------------------------------------------------------------*/ | |
642 /* Signal support */ | |
643 /*--------------------------------------------------------------------*/ | |
644 | |
645 #define sigmask(nsig) (1U << nsig) | |
646 | |
647 /* We can support as many signals as fit into word */ | |
648 #define SIG_MAX 32 | |
649 | |
650 /* Signal handlers. Initial value = 0 = SIG_DFL */ | |
651 static mswindows_sighandler signal_handlers[SIG_MAX] = {0}; | |
652 | |
653 /* Signal block mask: bit set to 1 means blocked */ | |
654 unsigned signal_block_mask = 0; | |
655 | |
656 /* Signal pending mask: bit set to 1 means sig is pending */ | |
657 unsigned signal_pending_mask = 0; | |
658 | |
659 mswindows_sighandler | |
660 mswindows_sigset (int nsig, mswindows_sighandler handler) | |
661 { | |
662 /* We delegate some signals to the system function */ | |
663 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT) | |
664 return signal (nsig, handler); | |
665 | |
666 if (nsig < 0 || nsig > SIG_MAX) | |
667 { | |
668 errno = EINVAL; | |
669 return NULL; | |
670 } | |
671 | |
672 /* Store handler ptr */ | |
673 { | |
674 mswindows_sighandler old_handler = signal_handlers[nsig]; | |
675 signal_handlers[nsig] = handler; | |
676 return old_handler; | |
677 } | |
678 } | |
679 | |
680 int | |
681 mswindows_sighold (int nsig) | |
682 { | |
683 if (nsig < 0 || nsig > SIG_MAX) | |
684 return errno = EINVAL; | |
685 | |
686 signal_block_mask |= sigmask (nsig); | |
687 return 0; | |
688 } | |
689 | |
690 int | |
691 mswindows_sigrelse (int nsig) | |
692 { | |
693 if (nsig < 0 || nsig > SIG_MAX) | |
694 return errno = EINVAL; | |
695 | |
696 signal_block_mask &= ~sigmask (nsig); | |
697 | |
698 if (signal_pending_mask & sigmask (nsig)) | |
699 mswindows_raise (nsig); | |
700 | |
701 return 0; | |
702 } | |
703 | |
704 int | |
2286 | 705 mswindows_sigpause (int UNUSED (nsig)) |
613 | 706 { |
707 /* This is currently not called, because the only call to sigpause | |
708 inside XEmacs is with SIGCHLD parameter. Just in case, we put an | |
2286 | 709 assert here, so anyone who adds a call to sigpause will be surprised |
613 | 710 (or surprise someone else...) */ |
711 assert (0); | |
712 return 0; | |
713 } | |
714 | |
715 int | |
716 mswindows_raise (int nsig) | |
717 { | |
718 /* We delegate some raises to the system routine */ | |
719 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT) | |
720 return raise (nsig); | |
721 | |
722 if (nsig < 0 || nsig > SIG_MAX) | |
723 return errno = EINVAL; | |
724 | |
725 /* If the signal is blocked, remember to issue later */ | |
726 if (signal_block_mask & sigmask (nsig)) | |
727 { | |
728 signal_pending_mask |= sigmask (nsig); | |
729 return 0; | |
730 } | |
731 | |
732 if (signal_handlers[nsig] == SIG_IGN) | |
733 return 0; | |
734 | |
735 if (signal_handlers[nsig] != SIG_DFL) | |
736 { | |
737 (*signal_handlers[nsig]) (nsig); | |
738 return 0; | |
739 } | |
740 | |
741 /* Default signal actions */ | |
742 if (nsig == SIGALRM || nsig == SIGPROF) | |
743 exit (3); | |
744 | |
745 /* Other signals are ignored by default */ | |
746 return 0; | |
747 } | |
748 | |
611 | 749 |
750 /*--------------------------------------------------------------------*/ | |
751 /* Async timers */ | |
752 /*--------------------------------------------------------------------*/ | |
753 | |
754 /* We emulate two timers, one for SIGALRM, another for SIGPROF. | |
755 | |
756 itimerproc() function has an implementation limitation: it does | |
757 not allow to set *both* interval and period. If an attempt is | |
758 made to set both, and then they are unequal, the function | |
759 asserts. | |
760 | |
761 Minimum timer resolution on Win32 systems varies, and is greater | |
762 than or equal than 1 ms. The resolution is always wrapped not to | |
763 attempt to get below the system defined limit. | |
764 */ | |
765 | |
766 /* Timer precision, denominator of one fraction: for 100 ms | |
767 interval, request 10 ms precision | |
768 */ | |
769 const int setitimer_helper_timer_prec = 10; | |
770 | |
771 /* Last itimervals, as set by calls to setitimer */ | |
772 static struct itimerval it_alarm; | |
773 static struct itimerval it_prof; | |
774 | |
775 /* Timer IDs as returned by MM */ | |
776 MMRESULT tid_alarm = 0; | |
777 MMRESULT tid_prof = 0; | |
778 | |
779 static void CALLBACK | |
2286 | 780 setitimer_helper_proc (UINT UNUSED (uID), UINT UNUSED (uMsg), DWORD dwUser, |
781 DWORD UNUSED (dw1), DWORD UNUSED (dw2)) | |
611 | 782 { |
783 /* Just raise the signal indicated by the dwUser parameter */ | |
784 mswindows_raise (dwUser); | |
785 } | |
786 | |
787 /* Divide time in ms specified by IT by DENOM. Return 1 ms | |
788 if division results in zero */ | |
789 static UINT | |
853 | 790 setitimer_helper_period (const struct itimerval *it, UINT denom) |
611 | 791 { |
792 static TIMECAPS time_caps; | |
793 | |
794 UINT res; | |
853 | 795 const struct timeval *tv = |
611 | 796 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0) |
797 ? &it->it_interval : &it->it_value; | |
798 | |
799 /* Zero means stop timer */ | |
800 if (tv->tv_sec == 0 && tv->tv_usec == 0) | |
801 return 0; | |
802 | |
803 /* Convert to ms and divide by denom */ | |
804 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom; | |
805 | |
806 /* Converge to minimum timer resolution */ | |
807 if (time_caps.wPeriodMin == 0) | |
808 timeGetDevCaps (&time_caps, sizeof(time_caps)); | |
809 | |
810 if (res < time_caps.wPeriodMin) | |
811 res = time_caps.wPeriodMin; | |
812 | |
813 return res; | |
814 } | |
815 | |
816 static int | |
853 | 817 setitimer_helper (const struct itimerval *itnew, |
818 struct itimerval *itold, struct itimerval *itcurrent, | |
819 MMRESULT *tid, DWORD sigkind) | |
611 | 820 { |
821 UINT delay, resolution, event_type; | |
822 | |
823 /* First stop the old timer */ | |
824 if (*tid) | |
825 { | |
826 timeKillEvent (*tid); | |
827 timeEndPeriod (setitimer_helper_period (itcurrent, | |
828 setitimer_helper_timer_prec)); | |
829 *tid = 0; | |
830 } | |
831 | |
832 /* Return old itimerval if requested */ | |
833 if (itold) | |
834 *itold = *itcurrent; | |
835 | |
836 *itcurrent = *itnew; | |
837 | |
838 /* Determine if to start new timer */ | |
839 delay = setitimer_helper_period (itnew, 1); | |
840 if (delay) | |
841 { | |
842 resolution = setitimer_helper_period (itnew, | |
843 setitimer_helper_timer_prec); | |
844 event_type = (itnew->it_value.tv_sec == 0 && | |
845 itnew->it_value.tv_usec == 0) | |
846 ? TIME_ONESHOT : TIME_PERIODIC; | |
847 timeBeginPeriod (resolution); | |
848 *tid = timeSetEvent (delay, resolution, setitimer_helper_proc, sigkind, | |
849 event_type); | |
850 } | |
851 | |
852 return !delay || *tid; | |
853 } | |
854 | |
855 int | |
856 mswindows_setitimer (int kind, const struct itimerval *itnew, | |
857 struct itimerval *itold) | |
858 { | |
859 /* In this version, both interval and value are allowed | |
860 only if they are equal. */ | |
861 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0) | |
862 || (itnew->it_interval.tv_sec == 0 && | |
863 itnew->it_interval.tv_usec == 0) | |
864 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec && | |
865 itnew->it_value.tv_usec == itnew->it_interval.tv_usec)); | |
866 | |
867 if (kind == ITIMER_REAL) | |
868 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM); | |
869 else if (kind == ITIMER_PROF) | |
870 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF); | |
871 else | |
872 return errno = EINVAL; | |
873 } | |
874 | |
613 | 875 #endif /* defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) */ |
876 | |
611 | 877 |
442 | 878 void |
879 syms_of_win32 (void) | |
880 { | |
881 DEFSUBR (Fmswindows_shell_execute); | |
673 | 882 #ifdef CYGWIN |
883 DEFSUBR (Fmswindows_cygwin_to_win32_path); | |
884 #endif | |
442 | 885 } |
886 | |
887 void | |
771 | 888 vars_of_win32 (void) |
889 { | |
2526 | 890 DEFVAR_LISP ("mswindows-downcase-file-names", |
891 &Vmswindows_downcase_file_names /* | |
771 | 892 Non-nil means convert all-upper case file names to lower case. |
893 This applies when performing completions and file name expansion. | |
894 */ ); | |
895 Vmswindows_downcase_file_names = Qnil; | |
2526 | 896 |
897 DEFVAR_BOOL ("mswindows-shortcuts-are-symlinks", | |
898 &mswindows_shortcuts_are_symlinks /* | |
899 Non-nil means shortcuts (.LNK files) are treated as symbolic links. | |
900 This works also for symlinks created under Cygwin, because they use .LNK | |
901 files to implement symbolic links. | |
902 */ ); | |
903 mswindows_shortcuts_are_symlinks = 1; | |
771 | 904 } |
905 | |
906 void | |
442 | 907 init_win32 (void) |
908 { | |
909 init_potentially_nonexistent_functions (); | |
910 } | |
771 | 911 |
912 void | |
2367 | 913 init_win32_very_very_early (void) |
771 | 914 { |
915 mswindows_windows9x_p = GetVersion () & 0x80000000; | |
916 } |