docs: update documentation for recent changes
[jimtcl.git] / jim-win32.c
blob89cedd4db4958384c88980788d28221e47368b3d
1 /*
2 * WIN32 extension
4 * Copyright (C) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and documentation
31 * are those of the authors and should not be interpreted as representing
32 * official policies, either expressed or implied, of the Jim Tcl Project.
35 #include <jim.h>
37 /* Apparently windows.h and cygwin don't mix, but we seem to get
38 * away with it here. Use at your own risk under cygwin
40 #if defined(__CYGWIN__)
41 #define WIN32_LEAN_AND_MEAN
42 #include <windows.h>
43 #endif
45 #include <shellapi.h>
46 #include <lmcons.h>
47 #include <psapi.h>
48 #include <ctype.h>
50 #if _MSC_VER >= 1000
51 #pragma comment(lib, "shell32")
52 #pragma comment(lib, "user32")
53 #pragma comment(lib, "advapi32")
54 #pragma comment(lib, "psapi")
55 #endif /* _MSC_VER >= 1000 */
57 static Jim_Obj *
58 Win32ErrorObj(Jim_Interp *interp, const char * szPrefix, DWORD dwError)
60 Jim_Obj *msgObj = NULL;
61 char * lpBuffer = NULL;
62 DWORD dwLen = 0;
64 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
65 | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, LANG_NEUTRAL,
66 (char *)&lpBuffer, 0, NULL);
67 if (dwLen < 1) {
68 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
69 | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
70 "code 0x%1!08X!%n", 0, LANG_NEUTRAL,
71 (char *)&lpBuffer, 0, (va_list *)&dwError);
74 msgObj = Jim_NewStringObj(interp, szPrefix, -1);
75 if (dwLen > 0) {
76 char *p = lpBuffer + dwLen - 1; /* remove cr-lf at end */
77 for ( ; p && *p && isspace(UCHAR(*p)); p--)
79 *++p = 0;
80 Jim_AppendString(interp, msgObj, ": ", 2);
81 Jim_AppendString(interp, msgObj, lpBuffer, -1);
83 LocalFree((HLOCAL)lpBuffer);
84 return msgObj;
87 /* win32.ShellExecute verb file args */
88 static int
89 Win32_ShellExecute(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
91 int r;
92 const char *verb, *file, *parm = NULL;
93 char cwd[MAX_PATH + 1];
95 if (objc < 3 || objc > 4) {
96 Jim_WrongNumArgs(interp, 1, objv, "verb path ?parameters?");
97 return JIM_ERR;
99 verb = Jim_String(objv[1]);
100 file = Jim_String(objv[2]);
101 GetCurrentDirectoryA(MAX_PATH + 1, cwd);
102 if (objc == 4)
103 parm = Jim_String(objv[3]);
104 r = (int)ShellExecuteA(NULL, verb, file, parm, cwd, SW_SHOWNORMAL);
105 if (r < 33)
106 Jim_SetResult(interp,
107 Win32ErrorObj(interp, "ShellExecute", GetLastError()));
108 return (r < 33) ? JIM_ERR : JIM_OK;
112 /* win32.FindWindow title ?class? */
113 static int
114 Win32_FindWindow(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
116 const char *title = NULL, *class = NULL;
117 HWND hwnd = NULL;
118 int r = JIM_OK;
120 if (objc < 2 || objc > 3) {
121 Jim_WrongNumArgs(interp, 1, objv, "title ?class?");
122 return JIM_ERR;
124 title = Jim_String(objv[1]);
125 if (objc == 3)
126 class = Jim_String(objv[2]);
127 hwnd = FindWindowA(class, title);
129 if (hwnd == NULL) {
130 Jim_SetResult(interp,
131 Win32ErrorObj(interp, "FindWindow", GetLastError()));
132 r = JIM_ERR;
133 } else {
134 Jim_SetResult(interp, Jim_NewIntObj(interp, (long)hwnd));
136 return r;
139 /* win32.CloseWindow windowHandle */
140 static int
141 Win32_CloseWindow(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
143 long hwnd;
145 if (objc != 2) {
146 Jim_WrongNumArgs(interp, 1, objv, "?windowHandle?");
147 return JIM_ERR;
149 if (Jim_GetLong(interp, objv[1], &hwnd) != JIM_OK)
150 return JIM_ERR;
151 if (!CloseWindow((HWND)hwnd)) {
152 Jim_SetResult(interp,
153 Win32ErrorObj(interp, "CloseWindow", GetLastError()));
154 return JIM_ERR;
156 return JIM_OK;
159 static int
160 Win32_GetActiveWindow(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
162 Jim_SetResult(interp, Jim_NewIntObj(interp, (DWORD)GetActiveWindow()));
163 return JIM_OK;
166 static int
167 Win32_SetActiveWindow(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
169 HWND hwnd, old;
170 int r = JIM_OK;
172 if (objc != 2) {
173 Jim_WrongNumArgs(interp, 1, objv, "windowHandle");
174 return JIM_ERR;
176 r = Jim_GetLong(interp, objv[1], (long *)&hwnd);
177 if (r == JIM_OK) {
178 old = SetActiveWindow(hwnd);
179 if (old == NULL) {
180 Jim_SetResult(interp,
181 Win32ErrorObj(interp, "SetActiveWindow", GetLastError()));
182 r = JIM_ERR;
183 } else {
184 Jim_SetResult(interp, Jim_NewIntObj(interp, (long)old));
187 return r;
190 static int
191 Win32_SetForegroundWindow(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
193 HWND hwnd;
194 int r = JIM_OK;
196 if (objc != 2) {
197 Jim_WrongNumArgs(interp, 1, objv, "windowHandle");
198 return JIM_ERR;
200 r = Jim_GetLong(interp, objv[1], (long *)&hwnd);
201 if (r == JIM_OK) {
202 if (!SetForegroundWindow(hwnd)) {
203 Jim_SetResult(interp,
204 Win32ErrorObj(interp, "SetForegroundWindow", GetLastError()));
205 r = JIM_ERR;
208 return r;
211 static int
212 Win32_Beep(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
214 long freq, duration;
215 int r = JIM_OK;
217 if (objc != 3) {
218 Jim_WrongNumArgs(interp, 1, objv, "freq duration");
219 return JIM_ERR;
221 r = Jim_GetLong(interp, objv[1], &freq);
222 if (r == JIM_OK)
223 r = Jim_GetLong(interp, objv[2], &duration);
224 if (freq < 0x25) freq = 0x25;
225 if (freq > 0x7fff) freq = 0x7fff;
226 if (r == JIM_OK) {
227 if (!Beep(freq, duration)) {
228 Jim_SetResult(interp,
229 Win32ErrorObj(interp, "Beep", GetLastError()));
230 r = JIM_ERR;
233 return r;
236 static int
237 Win32_GetComputerName(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
239 char name[MAX_COMPUTERNAME_LENGTH + 1];
240 DWORD size = MAX_COMPUTERNAME_LENGTH;
241 int r = JIM_OK;
243 if (objc != 1) {
244 Jim_WrongNumArgs(interp, 1, objv, "");
245 return JIM_ERR;
248 if (GetComputerNameA(name, &size)) {
249 Jim_Obj *nameObj = Jim_NewStringObj(interp, name, size);
250 Jim_SetResult(interp, nameObj);
251 } else {
252 Jim_SetResult(interp,
253 Win32ErrorObj(interp, "GetComputerName", GetLastError()));
254 r = JIM_ERR;
257 return r;
260 static int
261 Win32_GetUserName(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
263 char name[UNLEN + 1];
264 DWORD size = UNLEN;
265 int r = JIM_OK;
267 if (objc != 1) {
268 Jim_WrongNumArgs(interp, 1, objv, "");
269 return JIM_ERR;
272 if (GetUserNameA(name, &size)) {
273 Jim_Obj *nameObj = Jim_NewStringObj(interp, name, size);
274 Jim_SetResult(interp, nameObj);
275 } else {
276 Jim_SetResult(interp,
277 Win32ErrorObj(interp, "GetUserName", GetLastError()));
278 r = JIM_ERR;
281 return r;
284 static int
285 Win32_GetModuleFileName(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
287 HMODULE hModule = NULL;
288 char path[MAX_PATH];
289 DWORD len = 0;
291 if (objc > 2) {
292 Jim_WrongNumArgs(interp, 1, objv, "?moduleid?");
293 return JIM_ERR;
296 if (objc == 2) {
297 if (Jim_GetLong(interp, objv[1], (long *)&hModule) != JIM_OK) {
298 return JIM_ERR;
302 len = GetModuleFileNameA(hModule, path, MAX_PATH);
303 if (len != 0) {
304 Jim_Obj *pathObj = Jim_NewStringObj(interp, path, len);
305 Jim_SetResult(interp, pathObj);
306 } else {
307 Jim_SetResult(interp,
308 Win32ErrorObj(interp, "GetModuleFileName", GetLastError()));
309 return JIM_ERR;
312 return JIM_OK;
315 static int
316 Win32_GetVersion(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
318 Jim_SetResult(interp, Jim_NewIntObj(interp, GetVersion()));
319 return JIM_OK;
322 static int
323 Win32_GetTickCount(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
325 Jim_SetResult(interp, Jim_NewIntObj(interp, GetTickCount()));
326 return JIM_OK;
329 static int
330 Win32_GetSystemTime(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
332 Jim_Obj *a[16];
333 size_t n = 0;
334 SYSTEMTIME t;
335 GetSystemTime(&t);
337 #define JIMADD(name) \
338 a[n++] = Jim_NewStringObj(interp, #name, -1); \
339 a[n++] = Jim_NewIntObj(interp, t.w ## name )
341 JIMADD(Year);
342 JIMADD(Month);
343 JIMADD(DayOfWeek);
344 JIMADD(Day);
345 JIMADD(Hour);
346 JIMADD(Minute);
347 JIMADD(Second);
348 JIMADD(Milliseconds);
349 #undef JIMADD
351 Jim_SetResult(interp, Jim_NewListObj(interp, a, n));
352 return JIM_OK;
355 /* function not available on mingw or cygwin */
356 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
357 // FIX ME: win2k+ so should do version checks really.
358 static int
359 Win32_GetPerformanceInfo(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
361 Jim_Obj *a[26];
362 size_t n = 0;
363 PERFORMANCE_INFORMATION pi;
365 if (!GetPerformanceInfo(&pi, sizeof(pi))) {
366 Jim_SetResult(interp,
367 Win32ErrorObj(interp, "GetPerformanceInfo", GetLastError()));
368 return JIM_ERR;
371 #define JIMADD(name) \
372 a[n++] = Jim_NewStringObj(interp, #name, -1); \
373 a[n++] = Jim_NewIntObj(interp, pi. name )
375 JIMADD(CommitTotal);
376 JIMADD(CommitLimit);
377 JIMADD(CommitPeak);
378 JIMADD(PhysicalTotal);
379 JIMADD(PhysicalAvailable);
380 JIMADD(SystemCache);
381 JIMADD(KernelTotal);
382 JIMADD(KernelPaged);
383 JIMADD(KernelNonpaged);
384 JIMADD(PageSize);
385 JIMADD(HandleCount);
386 JIMADD(ProcessCount);
387 JIMADD(ThreadCount);
388 #undef JIMADD
390 Jim_SetResult(interp, Jim_NewListObj(interp, a, n));
391 return JIM_OK;
393 #endif
395 static int
396 Win32_SetComputerName(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
398 int r = JIM_OK;
399 const char *name;
400 if (objc != 2) {
401 Jim_WrongNumArgs(interp, 1, objv, "computername");
402 return JIM_ERR;
404 name = Jim_String(objv[1]);
405 if (!SetComputerNameA(name)) {
406 Jim_SetResult(interp,
407 Win32ErrorObj(interp, "SetComputerName", GetLastError()));
408 r = JIM_ERR;
410 return r;
413 static int
414 Win32_GetModuleHandle(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
416 HMODULE hModule = NULL;
417 const char *name = NULL;
419 if (objc < 1 || objc > 2) {
420 Jim_WrongNumArgs(interp, 1, objv, "?name?");
421 return JIM_ERR;
423 if (objc == 2)
424 name = Jim_String(objv[1]);
425 hModule = GetModuleHandleA(name);
426 if (hModule == NULL) {
427 Jim_SetResult(interp,
428 Win32ErrorObj(interp, "GetModuleHandle", GetLastError()));
429 return JIM_ERR;
431 Jim_SetResult(interp, Jim_NewIntObj(interp, (unsigned long)hModule));
432 return JIM_OK;
435 static int
436 Win32_LoadLibrary(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
438 HMODULE hLib = NULL;
439 if (objc != 2) {
440 Jim_WrongNumArgs(interp, 1, objv, "path");
441 return JIM_ERR;
443 hLib = LoadLibraryA(Jim_String(objv[1]));
444 if (hLib == NULL) {
445 Jim_SetResult(interp,
446 Win32ErrorObj(interp, "LoadLibrary", GetLastError()));
447 return JIM_ERR;
449 Jim_SetResult(interp, Jim_NewIntObj(interp, (unsigned long)hLib));
450 return JIM_OK;
453 static int
454 Win32_FreeLibrary(Jim_Interp *interp, int objc, Jim_Obj * const *objv)
456 HMODULE hModule = NULL;
457 int r = JIM_OK;
459 if (objc != 2) {
460 Jim_WrongNumArgs(interp, 1, objv, "hmodule");
461 return JIM_ERR;
464 r = Jim_GetLong(interp, objv[1], (long *)&hModule);
465 if (r == JIM_OK) {
466 if (!FreeLibrary(hModule)) {
467 Jim_SetResult(interp,
468 Win32ErrorObj(interp, "FreeLibrary", GetLastError()));
469 r = JIM_ERR;
473 return r;
477 /* ---------------------------------------------------------------------- */
480 Jim_win32Init(Jim_Interp *interp)
482 if (Jim_PackageProvide(interp, "win32", "1.0", JIM_ERRMSG))
483 return JIM_ERR;
485 #define CMD(name) \
486 Jim_CreateCommand(interp, "win32." #name , Win32_ ## name , NULL, NULL)
488 CMD(ShellExecute);
489 CMD(FindWindow);
490 CMD(CloseWindow);
491 CMD(GetActiveWindow);
492 CMD(SetActiveWindow);
493 CMD(SetForegroundWindow);
494 CMD(Beep);
495 CMD(GetComputerName);
496 CMD(SetComputerName);
497 CMD(GetUserName);
498 CMD(GetModuleFileName);
499 CMD(GetVersion);
500 CMD(GetTickCount);
501 CMD(GetSystemTime);
502 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
503 CMD(GetPerformanceInfo);
504 #endif
505 CMD(GetModuleHandle);
506 CMD(LoadLibrary);
507 CMD(FreeLibrary);
509 return JIM_OK;