forked from Ixiko/AHK-libs-and-classes-collection
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConsoleApp v1.2.ahk
529 lines (499 loc) · 21.8 KB
/
ConsoleApp v1.2.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
;
; ConsoleApps v1.2 (converted to StdLib by OceanMachine)
;
; AutoHotkey Version: 1.x
; Language: English
; Platform: Win9x/NT
; Author: Marcus Cortes <[email protected]>
;
; Script Function:
; Provides a set of functions to redirect and capture
; the standard input and output of other programs.
;
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
;;; <summary>
;;; Runs an application and retrieves its standard output.
;;; </summary>
;;; <param="CmdLine">
;;; The executable file to run including any path information and arguments.
;;; </param>
;;; <param="WorkingDir">
;;; The startup directory for the program.
;;; </param>
;;; <param="PID">
;;; Specifies a variable to receive the ProcessID of the program. This parameter is optional.
;;; </param>
;;; <param="ExitCode">
;;; When the function returns, this parameter is set to the exit code of the program.
;;; </param>
;;; <returns>
;;; Returns the StdOut of the program.
;;; </returns>
;;; <remarks>
;;; The output of programs that are explicity redirected or "piped" in their command-lines will
;;; not be captured by this function (e.g. "cmd.exe /C echo Hello World > test.txt").
;;; </remarks>
;;; <example>
;;; MsgBox, % ConsoleApp_RunWait("cmd.exe /c echo Hello World.")
;;; </example>
ConsoleApp_RunWait(CmdLine, WorkingDir="", byref ExitCode="")
{
global
local ConsoleAppHandle, ConsoleAppStillRunning, StdOut, BytesAppended, FirstWin32Error
; Create the process
ConsoleAppHandle := ConsoleApp_Run(CmdLine, WorkingDir)
; In reality, this function will never return with a ConsoleAppHandle value of 0, but
; it is good to check for this possibility in case future versions do return a value of
; 0 for failure.
if (ConsoleAppHandle == 0)
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Unable to run console application.")
/* Continuously retrieve the process's output and write it to the edit control
* in a loop as it arrives.
*/
Loop
{
; Append the ConsoleApps standard output to StdOut.
ConsoleAppStillRunning := ConsoleApp_GetStdOut(ConsoleAppHandle, StdOut, BytesAppended, ExitCode)
; If the ConsoleApp is no longer running, then stop checking for output.
if (!ConsoleAppStillRunning)
break
; Give up remainder of time-slice to give the child process a chance to generate more output
; before checking again.
sleep 0
}
; This function must be called when the ConsoleAppHandle is no longer needed.
ConsoleApp_CloseHandle(ConsoleAppHandle)
return StdOut
}
;;; <summary>
;;; Runs an application and redirects its standard input/output handles such that they can be accessed
;;; from the script using the ConsoleApp_GetStdOut() function.
;;; </summary>
;;; <param="CmdLine">
;;; The executable file to run including any path information and arguments.
;;; </param>
;;; <param="WorkingDir">
;;; The startup directory for the program.
;;; </param>
;;; <param="Reserved">
;;; This parameter is reserved for future use and should be a null string ("") or should be omitted.
;;; </param>
;;; <param="PID">
;;; Specifies a variable to receive the ProcessID of the program. This parameter is optional.
;;; </param>
;;; <returns>
;;; Returns a proprietary handle to the ConsoleApp for use in calls to ConsoleApp_GetStdOut() and
;;; ConsoleApp_CloseHandle(). This handle cannot be specified in any Win32 API functions to identify
;;; a process.
;;; </returns>
;;; <remarks>
;;; If this function completes successfully, the handle returned by this function must be closed
;;; when no longer needed using the ConsoleApp_CloseHandle() function.
;;; The output of programs that are explicity redirected or "piped" in their command-lines will
;;; not be captured in calls to ConsoleApp_GetStdOut (e.g. "cmd.exe /C echo Hello World > test.txt").
;;; </remarks>
;;; <example>
;;; ConsoleAppHandle := ConsoleApp_Run("cmd.exe /c echo Hello World.")
;;; if (ConsoleAppHandle == 0)
;;; MsgBox, Unable to start cmd.exe
;;; else
;;; ConsoleApp_CloseHandle(ConsoleAppHandle)
;;; </example>
ConsoleApp_Run(CmdLine, WorkingDir="", Reserved="", byref PID="")
{
global
local sa, pi, si, lpCurrentDirectory
local hStdoutRead, hStdoutWrite
; local hStdinRead, hStdinWrite
local FirstWin32Error
local hHeap, lpCAPI
static RedProcNextHandle := 1
CONSOLEAPPS_PRIVATE_calloc(pi, 16, 0) ;PROCESS_INFORMATION
CONSOLEAPPS_PRIVATE_calloc(si, 4*18, 0) ;STARTUP_INFO
NumPut(4*18, si, 0, "uint") ;STARTUP_INFO {HANDLE cbSize}
NumPut(0x100 | 0x1, si, 4*11, "uint") ;STARTUP_INFO {dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW}
;NumPut(0x0, si, 4*12, "ushort") ;STARTUP_INFO {wShowWindow = SW_HIDE}
;ALLOC HANDLES
CONSOLEAPPS_PRIVATE_malloc(hStdoutRead, 4)
CONSOLEAPPS_PRIVATE_malloc(hStdoutWrite, 4)
CONSOLEAPPS_PRIVATE_malloc(hStdinRead, 4)
CONSOLEAPPS_PRIVATE_malloc(hStdinWrite, 4)
;ALLOC AND INIT SECURITY_ATTRIBUTES STRUC
CONSOLEAPPS_PRIVATE_calloc(sa, 12, 0) ;security attributes
NumPut(12, sa, 0, "uint")
NumPut(0, sa, 4, "uint")
NumPut(true, sa, 8, "int")
;CREATE PIPE FOR STDOUT
if (!DllCall("CreatePipe", "uint", &hStdoutRead, "uint", &hStdoutWrite, "uint", &sa, "uint", 0))
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Unable to create stdout pipe: ")
hStdoutRead := NumGet(hStdoutRead, 0, "uint")
hStdoutWrite := NumGet(hStdoutWrite, 0, "uint")
if (!DllCall("SetHandleInformation", "uint", hStdoutRead, "uint", 1, "uint", 0, "int"))
{
FirstWin32Error := A_LastError
DllCall("CloseHandle", "uint", hStdoutRead) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdoutWrite) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Unable to set handle information: ", "", FirstWin32Error)
}
/*
;CREATE PIPE FOR STDIN
if (!DllCall("CreatePipe", "uint", &hStdinRead, "uint", &hStdinWrite, "uint", &sa, "uint", 0))
{
FirstWin32Error := A_LastError
DllCall("CloseHandle", "uint", hStdoutRead) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdoutWrite) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Unable to create stdin pipe: ", "", FirstWin32Error)
}
hStdinRead := NumGet(hStdinRead, 0, "uint")
hStdinWrite := NumGet(hStdinWrite, 0, "uint")
if (!DllCall("SetHandleInformation", "uint", hStdinWrite, "uint", 1, "uint", 0, "int"))
{
FirstWin32Error := A_LastError
DllCall("CloseHandle", "uint", hStdoutRead) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdoutWrite) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdinRead) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdinWrite) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Unable to set handle information: ", "", FirstWin32Error)
}
*/
;USE PIPE HANDLES FOR STDIO
; NumPut(hStdinRead, si, 4*14, "uint") ;STARTUP_INFO {HANDLE hStdInput}
NumPut(hStdoutWrite, si, 4*15, "uint") ;STARTUP_INFO {HANDLE hStdOutput}
NumPut(hStdoutWrite, si, 4*16, "uint") ;STARTUP_INFO {HANDLE hStdError}
if (StrLen(WorkingDir) == 0)
lpCurrentDirectory := 0
else
lpCurrentDirectory := &WorkingDir
if (!DllCall("CreateProcess", "uint", 0
, "uint", &CmdLine
, "uint", 0
, "uint", 0
, "int", true
, "uint", 0
, "uint", 0
, "uint", lpCurrentDirectory
, "uint", &si
, "uint", &pi))
{
FirstWin32Error := A_LastError
DllCall("CloseHandle", "uint", hStdoutRead) ;HANDLE hThread
DllCall("CloseHandle", "uint", hStdoutWrite) ;HANDLE hThread
; DllCall("CloseHandle", "uint", hStdinRead) ;HANDLE hThread
; DllCall("CloseHandle", "uint", hStdinWrite) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Unable to run process: ", "", FirstWin32Error)
}
hProcess := NumGet(pi, 0, "uint")
hThread := NumGet(pi, 4, "uint")
PID := NumGet(pi, 8, "uint") ;DWORD dwProcessId
DllCall("CloseHandle", "uint", hThread) ;HANDLE hThread
; struct ConsoleAppsProcessInfo
; {
; int hProcess;
; int hStdoutRead;
; int hStdoutWrite;
; //int hStdinRead;
; //int hStdinWrite;
; }
hHeap := DllCall("GetProcessHeap", "uint")
lpCAPI := DllCall("HeapAlloc", "uint", hHeap, "uint", 0, "uint", 0xC, "uint")
NumPut(hProcess, lpCAPI + 0x0)
NumPut(hStdoutRead, lpCAPI + 0x4)
NumPut(hStdoutWrite, lpCAPI + 0x8)
; NumPut(hStdinRead, lpCAPI + 0xC)
; NumPut(hStdinWrite, lpCAPI + 0x10)
return lpCAPI
}
;;; <summary>
;;; Retrieves the standard output of a ConsoleApp that was run using ConsoleApp_Run().
;;; </summary>
;;; <param="ConsoleAppHandle">
;;; A handle to a ConsoleApp that was created in a call to ConsoleApp_Run.
;;; </param>
;;; <param="Stdout">
;;; A variable that is to be appended with the standard output of the ConsoleApp. The
;;; variable is appended with all of the standard output of the program since the last
;;; call to ConsoleApp_GetStdOut.
;;; </param>
;;; <param="BytesAppended">
;;; A variable that is to receive the number of bytes that were appended to the Stdout
;;; parameter.
;;; </param>
;;; <returns>
;;; Returns true if the ConsoleApp is still running.
;;; Returns false if the ConsoleApp is no longer running.
;;; </returns>
;;; <remarks>
;;; The output of programs that are explicity redirected or "piped" in their command-lines will
;;; not be captured by this function (e.g. "cmd.exe /C echo Hello World > test.txt").
;;; </remarks>
;;; <example>
;;; ; To run this example perform the following steps:
;;; ; 1. Create a folder named ConsoleApps
;;; ; 2. Copy "ConsoleApps.ahk" to the folder
;;; ; 3. Create 2 new files in the folder named "ConsoleApps_Test.ahk" and "ConsoleApps_TestFile.bat"
;;; ; 4. Paste the following text (without the comments) into "ConsoleApps_TestFile.bat":
;;; @ECHO OFF
;;; ECHO Processing %2 1 of 3
;;; ping 127.0.0.1 -n 2 -w 1000 > nul
;;; ping 127.0.0.1 -n 1 -w 1000 > nul
;;; ECHO Processing %2 2 of 3
;;; ping 127.0.0.1 -n 2 -w 1000 > nul
;;; ping 127.0.0.1 -n 1 -w 1000 > nul
;;; ECHO Processing %2 3 of 3
;;; ping 127.0.0.1 -n 2 -w 1000 > nul
;;; ping 127.0.0.1 -n 1 -w 1000 > nul
;;; ECHO Processing Complete;;; ;
;;; ; 5. Paste the following text (without the comments) into "ConsoleApps_Test.ahk", and then run "ConsoleApps_Test.ahk"
;;; #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
;;; #Include ConsoleApps.ahk
;;;
;;; ;Create GUI window with an edit control to print the output.
;;; Gui, Add, Edit, x15 y15 w460 h300 -Wrap ReadOnly hscroll vtxtStdout,
;;; Gui, Show, w490 h330, Standard Input/Output Redirection Example
;;;
;;; ; Create the process
;;; ConsoleAppHandle := ConsoleApp_Run("ConsoleApps_TestFile.bat -p nothing", A_ScriptDir)
;;; ; In reality, this function will never return with a ConsoleAppHandle value of 0, but
;;; ; it is good to check for this possibility in case future versions do return a value of
;;; ; 0 for failure.
;;; if (ConsoleAppHandle == 0)
;;; {
;;; MsgBox, Error running cmd.exe
;;; ExitApp
;;; }
;;;
;;; /* Continuously retrieve the process's output and write it to the edit control
;;; * in a loop as it arrives.
;;; */
;;; Loop
;;; {
;;; ; Append the ConsoleApps standard output to StdOut.
;;; ConsoleAppStillRunning := ConsoleApp_GetStdOut(ConsoleAppHandle, StdOut, BytesAppended, ExitCode)
;;; ; If StdOut was appended with new text, write it to the GUI window.
;;; if (BytesAppended)
;;; GuiControl, , txtStdOut, %StdOut% ; write the output to the edit control.
;;; ; If the ConsoleApp is no longer running, then stop checking for output.
;;; if (!ConsoleAppStillRunning)
;;; break
;;; ; Give up remainder of time-slice to give the child process a chance to generate more output
;;; ; before checking again.
;;; sleep 0
;;; }
;;; ; This function must be called when the ConsoleAppHandle is no longer needed.
;;; ConsoleApp_CloseHandle(ConsoleAppHandle)
;;; if (!ExitCode)
;;; MsgBox, The program has completed successfully.
;;; else
;;; MsgBox, The program has exitted with an error code of %ExitCode%.
;;; return
;;;
;;; ; The following label is receives control when the user closes the GUI window.
;;; GuiClose:
;;; ExitApp
;;; </example>
ConsoleApp_GetStdOut(ConsoleAppHandle, byref Stdout, byref BytesAppended = 0, byref ExitCode="")
{
global
local hProcess, hStdoutRead, buf, ec, cb, FirstWin32Error
hProcess := NumGet(ConsoleAppHandle + 0x0)
hStdoutRead := NumGet(ConsoleAppHandle + 0x4)
; hStdoutWrite := NumGet(ConsoleAppHandle + 0x8)
; hStdinRead := NumGet(ConsoleAppHandle + 0xC)
; hStdinWrite := NumGet(ConsoleAppHandle + 0x10)
CONSOLEAPPS_PRIVATE_malloc(cb, 4)
BytesAppended := 0
Loop
{
DllCall("PeekNamedPipe", "uint", hStdoutRead, "uint", 0, "uint", 0, "uint", 0, "uint", &cb, "uint", 0)
if (!NumGet(cb, 0, "uint"))
break
if (!CONSOLEAPPS_PRIVATE_ReadFile(hStdoutRead, buf, cb, 1024))
{
FirstWin32Error := A_LastError
ConsoleApp_CloseHandle(ConsoleAppHandle)
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Error reading process stdout: ", "", FirstWin32Error)
}
stdout := stdout . buf
BytesAppended += NumGet(cb, 0, "uint")
}
CONSOLEAPPS_PRIVATE_malloc(ec, 4)
if (!DllCall("GetExitCodeProcess", uint, hProcess, uint, &ec))
{
FirstWin32Error := A_LastError
ConsoleApp_CloseHandle(ConsoleAppHandle)
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Error getting process exit code: ", "", FirstWin32Error)
}
ExitCode := NumGet(ec)
; If the exit code of the process is STILL_ACTIVE (0x103) then the process is still running
if (ExitCode == 0x103)
return true
return false
}
;;; <summary>
;;; Closes a ConsoleApp handle returned by ConsoleApp_Run()
;;; </summary>
;;; <param="ConsoleAppHandle">
;;; Handle to close.
;;; </param>
;;; <returns>
;;; This function does not return a value.
;;; </returns>
;;; <remarks>
;;; Every handle returned by a successful call to ConsoleApp_Run() must be closed
;;; with this function.
;;; </remarks>
ConsoleApp_CloseHandle(ConsoleAppHandle)
{
global
local hProcess, hStdoutRead, hStdOutWrite
hProcess := NumGet(ConsoleAppHandle + 0x0)
hStdoutRead := NumGet(ConsoleAppHandle + 0x4)
hStdoutWrite := NumGet(ConsoleAppHandle + 0x8)
; hStdinRead := NumGet(ConsoleAppHandle + 0xC)
; hStdinWrite := NumGet(ConsoleAppHandle + 0x10)
; If any of the following functions fail, then the ConsoleAppProcessInfo structure must
; not be valid, or has already been closed. In this case we raise an error to alert the
; user of a possible mis-handling of the handle and prevent further corruption and memory
; leaks.
if (!DllCall("CloseHandle", "uint", hProcess)) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Error ConsoleAppHandle is corrupt or has already been closed.")
if (!DllCall("CloseHandle", "uint", hStdoutRead)) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Error ConsoleAppHandle is corrupt or has already been closed.")
if (!DllCall("CloseHandle", "uint", hStdoutWrite)) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Error ConsoleAppHandle is corrupt or has already been closed.")
/*
if (!DllCall("CloseHandle", "uint", hStdinRead)) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Error ConsoleAppHandle is corrupt or has already been closed.")
if (!DllCall("CloseHandle", "uint", hStdinWrite)) ;HANDLE hThread
CONSOLEAPPS_PRIVATE_throw(ERROR_GENERIC_ERROR, "Error ConsoleAppHandle is corrupt or has already been closed.")
*/
hHeap := DllCall("GetProcessHeap", "uint")
if (!DllCall("HeapFree", "uint", hHeap, "uint", 0, "uint", ConsoleAppHandle))
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR, "Error deallocating heap. This is a serious error which can cause heap corruption. This program will now close. Specifically: ")
}
; +----------------------+
; | PRIVATE DECLARATIONS |
; +----------------------+
CONSOLEAPPS_PRIVATE_EXIT_FAILURE := 1
CONSOLEAPPS_PRIVATE_MAXIMUM_INTEGER := 0x7FFFFFFF ; 2147483647
CONSOLEAPPS_PRIVATE_MAXIMUM_UNSIGNED_INTEGER := 0xFFFFFFFF ; 4294967295
CONSOLEAPPS_PRIVATE_ERROR_NOT_ENOUGH_MEMORY := 0x8
CONSOLEAPPS_PRIVATE_ERROR_INVALID_PARAMETER := 0x57
CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR := CONSOLEAPPS_PRIVATE_MAXIMUM_UNSIGNED_INTEGER + 1
CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%CONSOLEAPPS_PRIVATE_ERROR_NOT_ENOUGH_MEMORY%] := "Not enough storage is available to process this command."
CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%CONSOLEAPPS_PRIVATE_ERROR_INVALID_PARAMETER%] := "Invalid parameter value."
CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR%] := "Unspecified exception."
;BufferSize is including the terminating null character.
CONSOLEAPPS_PRIVATE_ReadFile(hFile, byref buf, byref BytesRead=0, BufferSize=4096)
{
if (BufferSize <= 0)
return false
CONSOLEAPPS_PRIVATE_malloc(Buf, BufferSize)
CONSOLEAPPS_PRIVATE_malloc(BytesRead, 4)
if (!DllCall("ReadFile", "uint", hFile, "uint", &buf, "uint", BufferSize-1, "uint", &BytesRead, "uint", 0))
return false
BytesRead := NumGet(BytesRead, 0, "uint")
NumPut(0, Buf, BytesRead, "uchar") ;terminate data read with a null
VarSetCapacity(buf, -1)
return true
}
CONSOLEAPPS_PRIVATE_abort()
{
global
Critical, %CONSOLEAPPS_PRIVATE_MAXIMUM_INTEGER%
CONSOLEAPPS_PRIVATE_STD_Exiting := True
OnExit
BlockInput, MouseMoveOff
BlockInput, Off
ExitApp, %CONSOLEAPPS_PRIVATE_EXIT_FAILURE%
}
CONSOLEAPPS_PRIVATE_calloc(byref Var, size, fillbyte=0)
{
global
local cb
if (cb := VarSetCapacity(Var, size, fillbyte) != size)
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_NOT_ENOUGH_MEMORY)
return cb
}
CONSOLEAPPS_PRIVATE_free(byref Var)
{
VarSetCapacity(Var, 0)
}
CONSOLEAPPS_PRIVATE_WIN32_MAKELANGID(p, s)
{
return (s << 10) | p
}
CONSOLEAPPS_PRIVATE_malloc(byref var, size)
{
global
if (cb := VarSetCapacity(var, size) != size)
CONSOLEAPPS_PRIVATE_throw(CONSOLEAPPS_PRIVATE_ERROR_NOT_ENOUGH_MEMORY)
return cb
}
;;; <summary>
;;; Returns the C string at the address in lpStr
;;; </summary>
;;; <param="lpStr">
;;; The address of a string in memory. lpStr is an AutoHotkey integer numeric.
;;; NOT a 4-byte dword value.
;;; </param>
CONSOLEAPPS_PRIVATE_PtrToStr(lpStr)
{
return DllCall("MSVCRT\memcpy", UINT, lpStr, UINT, 0, UINT, 0, "str") ; Doesn't copy data, only returns string
}
; ParamName is only valid if ErrorCode is CONSOLEAPPS_PRIVATE_ERROR_INVALID_PARAMETER
; LastWin32Error is only necessary if ErrorCode is CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR
; and the A_LastError built-in variable is no longer valid.
CONSOLEAPPS_PRIVATE_throw(ErrorCode, ErrorMessage="", ParamName="", LastWin32Error="")
{
global
local lpMsg
Critical, %CONSOLEAPPS_PRIVATE_MAXIMUM_INTEGER%
if (ErrorCode == CONSOLEAPPS_PRIVATE_ERROR_INVALID_PARAMETER)
{
if (StrLen(ErrorMessage) == 0)
ErrorMessage := CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%ErrorCode%]
if (StrLen(ParamName) != 0)
ErrorMessage .= "\nParameter: " . ParamName
}
else if (ErrorCode == CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR)
{
if (StrLen(ErrorMessage) == 0)
ErrorMessage := CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%ErrorCode%]
if (StrLen(LastWin32Error) == 0)
LastWin32Error := A_LastError
CONSOLEAPPS_PRIVATE_malloc(lpMsg, 4)
/* DWORD TCharsCopied = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
* 0,
* LastWin32Error,
* MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
* (LPTSTR)&lpMsg,
* 0,
* NULL)
*/
if (t := DllCall("FormatMessageA"
, "uint", 0x1300
, "uint", 0
, "uint", LastWin32Error
, "uint", CONSOLEAPPS_PRIVATE_WIN32_MAKELANGID(0x0, 0x1)
, "uint", &lpMsg
, "uint", 0
, "uint", 0, "uint") == 0)
{
ErrorMessage .= CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%CONSOLEAPPS_PRIVATE_ERROR_WIN32_ERROR%]
}
else
{
ErrorMessage .= CONSOLEAPPS_PRIVATE_PtrToStr(NumGet(lpMsg))
DllCall("LocalFree", "uint", lpMsg)
CONSOLEAPPS_PRIVATE_free(lpMsg)
}
}
else
{
if (StrLen(ErrorMessage) == 0)
ErrorMessage := CONSOLEAPPS_PRIVATE_STD_ERROR_CODES[%ErrorCode%]
}
MsgBox, 0x1010, %A_ScriptName%, %ErrorMessage%
CONSOLEAPPS_PRIVATE_abort()
}