PageRenderTime 83ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 3ms

/Source/script.cpp

https://github.com/Geargia/AutoHotkey
C++ | 9651 lines | 7330 code | 411 blank | 1910 comment | 1500 complexity | 61daa4a3e240093c68914366f52d2ccc MD5 | raw file
Possible License(s): AGPL-1.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. AutoHotkey
  3. Copyright 2003-2009 Chris Mallett (support@autohotkey.com)
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. */
  13. #include "stdafx.h" // pre-compiled headers
  14. #include "script.h"
  15. #include "globaldata.h" // for a lot of things
  16. #include "util.h" // for strlcpy() etc.
  17. #include "mt19937ar-cok.h" // for random number generator
  18. #include "window.h" // for a lot of things
  19. #include "application.h" // for MsgSleep()
  20. // Globals that are for only this module:
  21. #define MAX_COMMENT_FLAG_LENGTH 15
  22. static char g_CommentFlag[MAX_COMMENT_FLAG_LENGTH + 1] = ";"; // Adjust the below for any changes.
  23. static size_t g_CommentFlagLength = 1; // pre-calculated for performance
  24. // General note about the methods in here:
  25. // Want to be able to support multiple simultaneous points of execution
  26. // because more than one subroutine can be executing simultaneously
  27. // (well, more precisely, there can be more than one script subroutine
  28. // that's in a "currently running" state, even though all such subroutines,
  29. // except for the most recent one, are suspended. So keep this in mind when
  30. // using things such as static data members or static local variables.
  31. Script::Script()
  32. : mFirstLine(NULL), mLastLine(NULL), mCurrLine(NULL), mPlaceholderLabel(NULL), mLineCount(0)
  33. , mThisHotkeyName(""), mPriorHotkeyName(""), mThisHotkeyStartTime(0), mPriorHotkeyStartTime(0)
  34. , mEndChar(0), mThisHotkeyModifiersLR(0)
  35. , mNextClipboardViewer(NULL), mOnClipboardChangeIsRunning(false), mOnClipboardChangeLabel(NULL)
  36. , mOnExitLabel(NULL), mExitReason(EXIT_NONE)
  37. , mFirstLabel(NULL), mLastLabel(NULL)
  38. , mFirstFunc(NULL), mLastFunc(NULL)
  39. , mFirstTimer(NULL), mLastTimer(NULL), mTimerEnabledCount(0), mTimerCount(0)
  40. , mFirstMenu(NULL), mLastMenu(NULL), mMenuCount(0)
  41. , mVar(NULL), mVarCount(0), mVarCountMax(0), mLazyVar(NULL), mLazyVarCount(0)
  42. , mCurrentFuncOpenBlockCount(0), mNextLineIsFunctionBody(false)
  43. , mFuncExceptionVar(NULL), mFuncExceptionVarCount(0)
  44. , mCurrFileIndex(0), mCombinedLineNumber(0), mNoHotkeyLabels(true), mMenuUseErrorLevel(false)
  45. , mFileSpec(""), mFileDir(""), mFileName(""), mOurEXE(""), mOurEXEDir(""), mMainWindowTitle("")
  46. , mIsReadyToExecute(false), mAutoExecSectionIsRunning(false)
  47. , mIsRestart(false), mIsAutoIt2(false), mErrorStdOut(false)
  48. #ifdef AUTOHOTKEYSC
  49. , mCompiledHasCustomIcon(false)
  50. #else
  51. , mIncludeLibraryFunctionsThenExit(NULL)
  52. #endif
  53. , mLinesExecutedThisCycle(0), mUninterruptedLineCountMax(1000), mUninterruptibleTime(15)
  54. , mRunAsUser(NULL), mRunAsPass(NULL), mRunAsDomain(NULL)
  55. , mCustomIcon(NULL) // Normally NULL unless there's a custom tray icon loaded dynamically.
  56. , mCustomIconFile(NULL), mIconFrozen(false), mTrayIconTip(NULL) // Allocated on first use.
  57. , mCustomIconNumber(0)
  58. {
  59. // v1.0.25: mLastScriptRest and mLastPeekTime are now initialized right before the auto-exec
  60. // section of the script is launched, which avoids an initial Sleep(10) in ExecUntil
  61. // that would otherwise occur.
  62. *mThisMenuItemName = *mThisMenuName = '\0';
  63. ZeroMemory(&mNIC, sizeof(mNIC)); // Constructor initializes this, to be safe.
  64. mNIC.hWnd = NULL; // Set this as an indicator that it tray icon is not installed.
  65. // Lastly (after the above have been initialized), anything that can fail:
  66. if ( !(mTrayMenu = AddMenu("Tray")) ) // realistically never happens
  67. {
  68. ScriptError("No tray mem");
  69. ExitApp(EXIT_CRITICAL);
  70. }
  71. else
  72. mTrayMenu->mIncludeStandardItems = true;
  73. #ifdef _DEBUG
  74. if (ID_FILE_EXIT < ID_MAIN_FIRST) // Not a very thorough check.
  75. ScriptError("DEBUG: ID_FILE_EXIT is too large (conflicts with IDs reserved via ID_USER_FIRST).");
  76. if (MAX_CONTROLS_PER_GUI > ID_USER_FIRST - 3)
  77. ScriptError("DEBUG: MAX_CONTROLS_PER_GUI is too large (conflicts with IDs reserved via ID_USER_FIRST).");
  78. int LargestMaxParams, i, j;
  79. ActionTypeType *np;
  80. // Find the Largest value of MaxParams used by any command and make sure it
  81. // isn't something larger than expected by the parsing routines:
  82. for (LargestMaxParams = i = 0; i < g_ActionCount; ++i)
  83. {
  84. if (g_act[i].MaxParams > LargestMaxParams)
  85. LargestMaxParams = g_act[i].MaxParams;
  86. // This next part has been tested and it does work, but only if one of the arrays
  87. // contains exactly MAX_NUMERIC_PARAMS number of elements and isn't zero terminated.
  88. // Relies on short-circuit boolean order:
  89. for (np = g_act[i].NumericParams, j = 0; j < MAX_NUMERIC_PARAMS && *np; ++j, ++np);
  90. if (j >= MAX_NUMERIC_PARAMS)
  91. {
  92. ScriptError("DEBUG: At least one command has a NumericParams array that isn't zero-terminated."
  93. " This would result in reading beyond the bounds of the array.");
  94. return;
  95. }
  96. }
  97. if (LargestMaxParams > MAX_ARGS)
  98. ScriptError("DEBUG: At least one command supports more arguments than allowed.");
  99. if (sizeof(ActionTypeType) == 1 && g_ActionCount > 256)
  100. ScriptError("DEBUG: Since there are now more than 256 Action Types, the ActionTypeType"
  101. " typedef must be changed.");
  102. #endif
  103. }
  104. Script::~Script() // Destructor.
  105. {
  106. // MSDN: "Before terminating, an application must call the UnhookWindowsHookEx function to free
  107. // system resources associated with the hook."
  108. AddRemoveHooks(0); // Remove all hooks.
  109. if (mNIC.hWnd) // Tray icon is installed.
  110. Shell_NotifyIcon(NIM_DELETE, &mNIC); // Remove it.
  111. // Destroy any Progress/SplashImage windows that haven't already been destroyed. This is necessary
  112. // because sometimes these windows aren't owned by the main window:
  113. int i;
  114. for (i = 0; i < MAX_PROGRESS_WINDOWS; ++i)
  115. {
  116. if (g_Progress[i].hwnd && IsWindow(g_Progress[i].hwnd))
  117. DestroyWindow(g_Progress[i].hwnd);
  118. if (g_Progress[i].hfont1) // Destroy font only after destroying the window that uses it.
  119. DeleteObject(g_Progress[i].hfont1);
  120. if (g_Progress[i].hfont2) // Destroy font only after destroying the window that uses it.
  121. DeleteObject(g_Progress[i].hfont2);
  122. if (g_Progress[i].hbrush)
  123. DeleteObject(g_Progress[i].hbrush);
  124. }
  125. for (i = 0; i < MAX_SPLASHIMAGE_WINDOWS; ++i)
  126. {
  127. if (g_SplashImage[i].pic)
  128. g_SplashImage[i].pic->Release();
  129. if (g_SplashImage[i].hwnd && IsWindow(g_SplashImage[i].hwnd))
  130. DestroyWindow(g_SplashImage[i].hwnd);
  131. if (g_SplashImage[i].hfont1) // Destroy font only after destroying the window that uses it.
  132. DeleteObject(g_SplashImage[i].hfont1);
  133. if (g_SplashImage[i].hfont2) // Destroy font only after destroying the window that uses it.
  134. DeleteObject(g_SplashImage[i].hfont2);
  135. if (g_SplashImage[i].hbrush)
  136. DeleteObject(g_SplashImage[i].hbrush);
  137. }
  138. // It is safer/easier to destroy the GUI windows prior to the menus (especially the menu bars).
  139. // This is because one GUI window might get destroyed and take with it a menu bar that is still
  140. // in use by an existing GUI window. GuiType::Destroy() adheres to this philosophy by detaching
  141. // its menu bar prior to destroying its window:
  142. for (i = 0; i < MAX_GUI_WINDOWS; ++i)
  143. GuiType::Destroy(i); // Static method to avoid problems with object destroying itself.
  144. for (i = 0; i < GuiType::sFontCount; ++i) // Now that GUI windows are gone, delete all GUI fonts.
  145. if (GuiType::sFont[i].hfont)
  146. DeleteObject(GuiType::sFont[i].hfont);
  147. // The above might attempt to delete an HFONT from GetStockObject(DEFAULT_GUI_FONT), etc.
  148. // But that should be harmless:
  149. // MSDN: "It is not necessary (but it is not harmful) to delete stock objects by calling DeleteObject."
  150. // Above: Probably best to have removed icon from tray and destroyed any Gui/Splash windows that were
  151. // using it prior to getting rid of the script's custom icon below:
  152. if (mCustomIcon)
  153. DestroyIcon(mCustomIcon);
  154. // Since they're not associated with a window, we must free the resources for all popup menus.
  155. // Update: Even if a menu is being used as a GUI window's menu bar, see note above for why menu
  156. // destruction is done AFTER the GUI windows are destroyed:
  157. UserMenu *menu_to_delete;
  158. for (UserMenu *m = mFirstMenu; m;)
  159. {
  160. menu_to_delete = m;
  161. m = m->mNextMenu;
  162. ScriptDeleteMenu(menu_to_delete);
  163. // Above call should not return FAIL, since the only way FAIL can realistically happen is
  164. // when a GUI window is still using the menu as its menu bar. But all GUI windows are gone now.
  165. }
  166. // Since tooltip windows are unowned, they should be destroyed to avoid resource leak:
  167. for (i = 0; i < MAX_TOOLTIPS; ++i)
  168. if (g_hWndToolTip[i] && IsWindow(g_hWndToolTip[i]))
  169. DestroyWindow(g_hWndToolTip[i]);
  170. if (g_hFontSplash) // The splash window itself should auto-destroyed, since it's owned by main.
  171. DeleteObject(g_hFontSplash);
  172. if (mOnClipboardChangeLabel) // Remove from viewer chain.
  173. ChangeClipboardChain(g_hWnd, mNextClipboardViewer);
  174. // Close any open sound item to prevent hang-on-exit in certain operating systems or conditions.
  175. // If there's any chance that a sound was played and not closed out, or that it is still playing,
  176. // this check is done. Otherwise, the check is avoided since it might be a high overhead call,
  177. // especially if the sound subsystem part of the OS is currently swapped out or something:
  178. if (g_SoundWasPlayed)
  179. {
  180. char buf[MAX_PATH * 2];
  181. mciSendString("status " SOUNDPLAY_ALIAS " mode", buf, sizeof(buf), NULL);
  182. if (*buf) // "playing" or "stopped"
  183. mciSendString("close " SOUNDPLAY_ALIAS, NULL, 0, NULL);
  184. }
  185. #ifdef ENABLE_KEY_HISTORY_FILE
  186. KeyHistoryToFile(); // Close the KeyHistory file if it's open.
  187. #endif
  188. DeleteCriticalSection(&g_CriticalRegExCache); // g_CriticalRegExCache is used elsewhere for thread-safety.
  189. }
  190. ResultType Script::Init(global_struct &g, char *aScriptFilename, bool aIsRestart)
  191. // Returns OK or FAIL.
  192. // Caller has provided an empty string for aScriptFilename if this is a compiled script.
  193. // Otherwise, aScriptFilename can be NULL if caller hasn't determined the filename of the script yet.
  194. {
  195. mIsRestart = aIsRestart;
  196. char buf[2048]; // Just to make sure we have plenty of room to do things with.
  197. #ifdef AUTOHOTKEYSC
  198. // Fix for v1.0.29: Override the caller's use of __argv[0] by using GetModuleFileName(),
  199. // so that when the script is started from the command line but the user didn't type the
  200. // extension, the extension will be included. This necessary because otherwise
  201. // #SingleInstance wouldn't be able to detect duplicate versions in every case.
  202. // It also provides more consistency.
  203. GetModuleFileName(NULL, buf, sizeof(buf));
  204. #else
  205. if (!aScriptFilename) // v1.0.46.08: Change in policy: store the default script in the My Documents directory rather than in Program Files. It's more correct and solves issues that occur due to Vista's file-protection scheme.
  206. {
  207. // Since no script-file was specified on the command line, use the default name.
  208. // For backward compatibility, FIRST check if there's an AutoHotkey.ini file in the current
  209. // directory. If there is, that needs to be used to retain compatibility.
  210. aScriptFilename = NAME_P ".ini";
  211. if (GetFileAttributes(aScriptFilename) == 0xFFFFFFFF) // File doesn't exist, so fall back to new method.
  212. {
  213. aScriptFilename = buf;
  214. VarSizeType filespec_length = BIV_MyDocuments(aScriptFilename, ""); // e.g. C:\Documents and Settings\Home\My Documents
  215. if (filespec_length > sizeof(buf)-16) // Need room for 16 characters ('\\' + "AutoHotkey.ahk" + terminator).
  216. return FAIL; // Very rare, so for simplicity just abort.
  217. strcpy(aScriptFilename + filespec_length, "\\AutoHotkey.ahk"); // Append the filename: .ahk vs. .ini seems slightly better in terms of clarity and usefulness (e.g. the ability to double click the default script to launch it).
  218. // Now everything is set up right because even if aScriptFilename is a nonexistent file, the
  219. // user will be prompted to create it by a stage further below.
  220. }
  221. //else since the legacy .ini file exists, everything is now set up right. (The file might be a directory, but that isn't checked due to rarity.)
  222. }
  223. // In case the script is a relative filespec (relative to current working dir):
  224. char *unused;
  225. if (!GetFullPathName(aScriptFilename, sizeof(buf), buf, &unused)) // This is also relied upon by mIncludeLibraryFunctionsThenExit. Succeeds even on nonexistent files.
  226. return FAIL; // Due to rarity, no error msg, just abort.
  227. #endif
  228. // Using the correct case not only makes it look better in title bar & tray tool tip,
  229. // it also helps with the detection of "this script already running" since otherwise
  230. // it might not find the dupe if the same script name is launched with different
  231. // lowercase/uppercase letters:
  232. ConvertFilespecToCorrectCase(buf); // This might change the length, e.g. due to expansion of 8.3 filename.
  233. char *filename_marker;
  234. if ( !(filename_marker = strrchr(buf, '\\')) )
  235. filename_marker = buf;
  236. else
  237. ++filename_marker;
  238. if ( !(mFileSpec = SimpleHeap::Malloc(buf)) ) // The full spec is stored for convenience, and it's relied upon by mIncludeLibraryFunctionsThenExit.
  239. return FAIL; // It already displayed the error for us.
  240. filename_marker[-1] = '\0'; // Terminate buf in this position to divide the string.
  241. size_t filename_length = strlen(filename_marker);
  242. if ( mIsAutoIt2 = (filename_length >= 4 && !stricmp(filename_marker + filename_length - 4, EXT_AUTOIT2)) )
  243. {
  244. // Set the old/AutoIt2 defaults for maximum safety and compatibilility.
  245. // Standalone EXEs (compiled scripts) are always considered to be non-AutoIt2 (otherwise,
  246. // the user should probably be using the AutoIt2 compiler).
  247. g_AllowSameLineComments = false;
  248. g_EscapeChar = '\\';
  249. g.TitleFindFast = true; // In case the normal default is false.
  250. g.DetectHiddenText = false;
  251. // Make the mouse fast like AutoIt2, but not quite insta-move. 2 is expected to be more
  252. // reliable than 1 since the AutoIt author said that values less than 2 might cause the
  253. // drag to fail (perhaps just for specific apps, such as games):
  254. g.DefaultMouseSpeed = 2;
  255. g.KeyDelay = 20;
  256. g.WinDelay = 500;
  257. g.LinesPerCycle = 1;
  258. g.IntervalBeforeRest = -1; // i.e. this method is disabled by default for AutoIt2 scripts.
  259. // Reduce max params so that any non escaped delimiters the user may be using literally
  260. // in "window text" will still be considered literal, rather than as delimiters for
  261. // args that are not supported by AutoIt2, such as exclude-title, exclude-text, MsgBox
  262. // timeout, etc. Note: Don't need to change IfWinExist and such because those already
  263. // have special handling to recognize whether exclude-title is really a valid command
  264. // instead (e.g. IfWinExist, title, text, Gosub, something).
  265. // NOTE: DO NOT ADD the IfWin command series to this section, since there is special handling
  266. // for parsing those commands to figure out whether they're being used in the old AutoIt2
  267. // style or the new Exclude Title/Text mode.
  268. // v1.0.40.02: The following is no longer done because a different mechanism is required now
  269. // that the ARGn macros do not check whether mArgc is too small and substitute an empty string
  270. // (instead, there is a loop in ExpandArgs that puts an empty string in each sArgDeref entry
  271. // for which the script omitted a parameter [and that loop relies on MaxParams being absolutely
  272. // accurate rather than conditional upon whether the script is of type ".aut"]).
  273. //g_act[ACT_FILESELECTFILE].MaxParams -= 2;
  274. //g_act[ACT_FILEREMOVEDIR].MaxParams -= 1;
  275. //g_act[ACT_MSGBOX].MaxParams -= 1;
  276. //g_act[ACT_INIREAD].MaxParams -= 1;
  277. //g_act[ACT_STRINGREPLACE].MaxParams -= 1;
  278. //g_act[ACT_STRINGGETPOS].MaxParams -= 2;
  279. //g_act[ACT_WINCLOSE].MaxParams -= 3; // -3 for these two, -2 for the others.
  280. //g_act[ACT_WINKILL].MaxParams -= 3;
  281. //g_act[ACT_WINACTIVATE].MaxParams -= 2;
  282. //g_act[ACT_WINMINIMIZE].MaxParams -= 2;
  283. //g_act[ACT_WINMAXIMIZE].MaxParams -= 2;
  284. //g_act[ACT_WINRESTORE].MaxParams -= 2;
  285. //g_act[ACT_WINHIDE].MaxParams -= 2;
  286. //g_act[ACT_WINSHOW].MaxParams -= 2;
  287. //g_act[ACT_WINSETTITLE].MaxParams -= 2;
  288. //g_act[ACT_WINGETTITLE].MaxParams -= 2;
  289. }
  290. if ( !(mFileDir = SimpleHeap::Malloc(buf)) )
  291. return FAIL; // It already displayed the error for us.
  292. if ( !(mFileName = SimpleHeap::Malloc(filename_marker)) )
  293. return FAIL; // It already displayed the error for us.
  294. #ifdef AUTOHOTKEYSC
  295. // Omit AutoHotkey from the window title, like AutoIt3 does for its compiled scripts.
  296. // One reason for this is to reduce backlash if evil-doers create viruses and such
  297. // with the program:
  298. snprintf(buf, sizeof(buf), "%s\\%s", mFileDir, mFileName);
  299. #else
  300. snprintf(buf, sizeof(buf), "%s\\%s - %s", mFileDir, mFileName, NAME_PV);
  301. #endif
  302. if ( !(mMainWindowTitle = SimpleHeap::Malloc(buf)) )
  303. return FAIL; // It already displayed the error for us.
  304. // It may be better to get the module name this way rather than reading it from the registry
  305. // (though it might be more proper to parse it out of the command line args or something),
  306. // in case the user has moved it to a folder other than the install folder, hasn't installed it,
  307. // or has renamed the EXE file itself. Also, enclose the full filespec of the module in double
  308. // quotes since that's how callers usually want it because ActionExec() currently needs it that way:
  309. *buf = '"';
  310. if (GetModuleFileName(NULL, buf + 1, sizeof(buf) - 2)) // -2 to leave room for the enclosing double quotes.
  311. {
  312. size_t buf_length = strlen(buf);
  313. buf[buf_length++] = '"';
  314. buf[buf_length] = '\0';
  315. if ( !(mOurEXE = SimpleHeap::Malloc(buf)) )
  316. return FAIL; // It already displayed the error for us.
  317. else
  318. {
  319. char *last_backslash = strrchr(buf, '\\');
  320. if (!last_backslash) // probably can't happen due to the nature of GetModuleFileName().
  321. mOurEXEDir = "";
  322. last_backslash[1] = '\0'; // i.e. keep the trailing backslash for convenience.
  323. if ( !(mOurEXEDir = SimpleHeap::Malloc(buf + 1)) ) // +1 to omit the leading double-quote.
  324. return FAIL; // It already displayed the error for us.
  325. }
  326. }
  327. return OK;
  328. }
  329. ResultType Script::CreateWindows()
  330. // Returns OK or FAIL.
  331. {
  332. if (!mMainWindowTitle || !*mMainWindowTitle) return FAIL; // Init() must be called before this function.
  333. // Register a window class for the main window:
  334. WNDCLASSEX wc = {0};
  335. wc.cbSize = sizeof(wc);
  336. wc.lpszClassName = WINDOW_CLASS_MAIN;
  337. wc.hInstance = g_hInstance;
  338. wc.lpfnWndProc = MainWindowProc;
  339. // The following are left at the default of NULL/0 set higher above:
  340. //wc.style = 0; // CS_HREDRAW | CS_VREDRAW
  341. //wc.cbClsExtra = 0;
  342. //wc.cbWndExtra = 0;
  343. wc.hIcon = wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_MAIN), IMAGE_ICON, 0, 0, LR_SHARED); // Use LR_SHARED to conserve memory (since the main icon is loaded for so many purposes).
  344. wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
  345. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); // Needed for ProgressBar. Old: (HBRUSH)GetStockObject(WHITE_BRUSH);
  346. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_MAIN); // NULL; // "MainMenu";
  347. if (!RegisterClassEx(&wc))
  348. {
  349. MsgBox("RegClass"); // Short/generic msg since so rare.
  350. return FAIL;
  351. }
  352. // Register a second class for the splash window. The only difference is that
  353. // it doesn't have the menu bar:
  354. wc.lpszClassName = WINDOW_CLASS_SPLASH;
  355. wc.lpszMenuName = NULL; // Override the non-NULL value set higher above.
  356. if (!RegisterClassEx(&wc))
  357. {
  358. MsgBox("RegClass"); // Short/generic msg since so rare.
  359. return FAIL;
  360. }
  361. char class_name[64];
  362. HWND fore_win = GetForegroundWindow();
  363. bool do_minimize = !fore_win || (GetClassName(fore_win, class_name, sizeof(class_name))
  364. && !stricmp(class_name, "Shell_TrayWnd")); // Shell_TrayWnd is the taskbar's class on Win98/XP and probably the others too.
  365. // Note: the title below must be constructed the same was as is done by our
  366. // WinMain() (so that we can detect whether this script is already running)
  367. // which is why it's standardized in g_script.mMainWindowTitle.
  368. // Create the main window. Prevent momentary disruption of Start Menu, which
  369. // some users understandably don't like, by omitting the taskbar button temporarily.
  370. // This is done because testing shows that minimizing the window further below, even
  371. // though the window is hidden, would otherwise briefly show the taskbar button (or
  372. // at least redraw the taskbar). Sometimes this isn't noticeable, but other times
  373. // (such as when the system is under heavy load) a user reported that it is quite
  374. // noticeable. WS_EX_TOOLWINDOW is used instead of WS_EX_NOACTIVATE because
  375. // WS_EX_NOACTIVATE is available only on 2000/XP.
  376. if ( !(g_hWnd = CreateWindowEx(do_minimize ? WS_EX_TOOLWINDOW : 0
  377. , WINDOW_CLASS_MAIN
  378. , mMainWindowTitle
  379. , WS_OVERLAPPEDWINDOW // Style. Alt: WS_POPUP or maybe 0.
  380. , CW_USEDEFAULT // xpos
  381. , CW_USEDEFAULT // ypos
  382. , CW_USEDEFAULT // width
  383. , CW_USEDEFAULT // height
  384. , NULL // parent window
  385. , NULL // Identifies a menu, or specifies a child-window identifier depending on the window style
  386. , g_hInstance // passed into WinMain
  387. , NULL)) ) // lpParam
  388. {
  389. MsgBox("CreateWindow"); // Short msg since so rare.
  390. return FAIL;
  391. }
  392. #ifdef AUTOHOTKEYSC
  393. HMENU menu = GetMenu(g_hWnd);
  394. // Disable the Edit menu item, since it does nothing for a compiled script:
  395. EnableMenuItem(menu, ID_FILE_EDITSCRIPT, MF_DISABLED | MF_GRAYED);
  396. EnableOrDisableViewMenuItems(menu, MF_DISABLED | MF_GRAYED); // Fix for v1.0.47.06: No point in checking g_AllowMainWindow because the script hasn't starting running yet, so it will always be false.
  397. // But leave the ID_VIEW_REFRESH menu item enabled because if the script contains a
  398. // command such as ListLines in it, Refresh can be validly used.
  399. #endif
  400. if ( !(g_hWndEdit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER
  401. | ES_LEFT | ES_MULTILINE | ES_READONLY | WS_VSCROLL // | WS_HSCROLL (saves space)
  402. , 0, 0, 0, 0, g_hWnd, (HMENU)1, g_hInstance, NULL)) )
  403. {
  404. MsgBox("CreateWindow"); // Short msg since so rare.
  405. return FAIL;
  406. }
  407. // FONTS: The font used by default, at least on XP, is GetStockObject(SYSTEM_FONT).
  408. // It seems preferable to smaller fonts such DEFAULT_GUI_FONT(DEFAULT_GUI_FONT).
  409. // For more info on pre-loaded fonts (not too many choices), see MSDN's GetStockObject().
  410. //SendMessage(g_hWndEdit, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
  411. // v1.0.30.05: Specifying a limit of zero opens the control to its maximum text capacity,
  412. // which removes the 32K size restriction. Testing shows that this does not increase the actual
  413. // amount of memory used for controls containing small amounts of text. All it does is allow
  414. // the control to allocate more memory as needed. By specifying zero, a max
  415. // of 64K becomes available on Windows 9x, and perhaps as much as 4 GB on NT/2k/XP.
  416. SendMessage(g_hWndEdit, EM_LIMITTEXT, 0, 0);
  417. // Some of the MSDN docs mention that an app's very first call to ShowWindow() makes that
  418. // function operate in a special mode. Therefore, it seems best to get that first call out
  419. // of the way to avoid the possibility that the first-call behavior will cause problems with
  420. // our normal use of ShowWindow() below and other places. Also, decided to ignore nCmdShow,
  421. // to avoid any momentary visual effects on startup.
  422. // Update: It's done a second time because the main window might now be visible if the process
  423. // that launched ours specified that. It seems best to override the requested state because
  424. // some calling processes might specify "maximize" or "shownormal" as generic launch method.
  425. // The script can display it's own main window with ListLines, etc.
  426. // MSDN: "the nCmdShow value is ignored in the first call to ShowWindow if the program that
  427. // launched the application specifies startup information in the structure. In this case,
  428. // ShowWindow uses the information specified in the STARTUPINFO structure to show the window.
  429. // On subsequent calls, the application must call ShowWindow with nCmdShow set to SW_SHOWDEFAULT
  430. // to use the startup information provided by the program that launched the application."
  431. ShowWindow(g_hWnd, SW_HIDE);
  432. ShowWindow(g_hWnd, SW_HIDE);
  433. // Now that the first call to ShowWindow() is out of the way, minimize the main window so that
  434. // if the script is launched from the Start Menu (and perhaps other places such as the
  435. // Quick-launch toolbar), the window that was active before the Start Menu was displayed will
  436. // become active again. But as of v1.0.25.09, this minimize is done more selectively to prevent
  437. // the launch of a script from knocking the user out of a full-screen game or other application
  438. // that would be disrupted by an SW_MINIMIZE:
  439. if (do_minimize)
  440. {
  441. ShowWindow(g_hWnd, SW_MINIMIZE);
  442. SetWindowLong(g_hWnd, GWL_EXSTYLE, 0); // Give the main window back its taskbar button.
  443. }
  444. // Note: When the window is not minimized, task manager reports that a simple script (such as
  445. // one consisting only of the single line "#Persistent") uses 2600 KB of memory vs. ~452 KB if
  446. // it were immediately minimized. That is probably just due to the vagaries of how the OS
  447. // manages windows and memory and probably doesn't actually impact system performance to the
  448. // degree indicated. In other words, it's hard to imagine that the failure to do
  449. // ShowWidnow(g_hWnd, SW_MINIMIZE) unconditionally upon startup (which causes the side effects
  450. // discussed further above) significantly increases the actual memory load on the system.
  451. g_hAccelTable = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
  452. if (g_NoTrayIcon)
  453. mNIC.hWnd = NULL; // Set this as an indicator that tray icon is not installed.
  454. else
  455. // Even if the below fails, don't return FAIL in case the user is using a different shell
  456. // or something. In other words, it is expected to fail under certain circumstances and
  457. // we want to tolerate that:
  458. CreateTrayIcon();
  459. if (mOnClipboardChangeLabel)
  460. mNextClipboardViewer = SetClipboardViewer(g_hWnd);
  461. return OK;
  462. }
  463. void Script::EnableOrDisableViewMenuItems(HMENU aMenu, UINT aFlags)
  464. {
  465. EnableMenuItem(aMenu, ID_VIEW_KEYHISTORY, aFlags);
  466. EnableMenuItem(aMenu, ID_VIEW_LINES, aFlags);
  467. EnableMenuItem(aMenu, ID_VIEW_VARIABLES, aFlags);
  468. EnableMenuItem(aMenu, ID_VIEW_HOTKEYS, aFlags);
  469. }
  470. void Script::CreateTrayIcon()
  471. // It is the caller's responsibility to ensure that the previous icon is first freed/destroyed
  472. // before calling us to install a new one. However, that is probably not needed if the Explorer
  473. // crashed, since the memory used by the tray icon was probably destroyed along with it.
  474. {
  475. ZeroMemory(&mNIC, sizeof(mNIC)); // To be safe.
  476. // Using NOTIFYICONDATA_V2_SIZE vs. sizeof(NOTIFYICONDATA) improves compatibility with Win9x maybe.
  477. // MSDN: "Using [NOTIFYICONDATA_V2_SIZE] for cbSize will allow your application to use NOTIFYICONDATA
  478. // with earlier Shell32.dll versions, although without the version 6.0 enhancements."
  479. // Update: Using V2 gives an compile error so trying V1. Update: Trying sizeof(NOTIFYICONDATA)
  480. // for compatibility with VC++ 6.x. This is also what AutoIt3 uses:
  481. mNIC.cbSize = sizeof(NOTIFYICONDATA); // NOTIFYICONDATA_V1_SIZE
  482. mNIC.hWnd = g_hWnd;
  483. mNIC.uID = AHK_NOTIFYICON; // This is also used for the ID, see TRANSLATE_AHK_MSG for details.
  484. mNIC.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON;
  485. mNIC.uCallbackMessage = AHK_NOTIFYICON;
  486. #ifdef AUTOHOTKEYSC
  487. // i.e. don't override the user's custom icon:
  488. mNIC.hIcon = mCustomIcon ? mCustomIcon : (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(mCompiledHasCustomIcon ? IDI_MAIN : g_IconTray), IMAGE_ICON, 0, 0, LR_SHARED);
  489. #else
  490. mNIC.hIcon = mCustomIcon ? mCustomIcon : (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(g_IconTray), IMAGE_ICON, 0, 0, LR_SHARED); // Use LR_SHARED to conserve memory (since the main icon is loaded for so many purposes).
  491. #endif
  492. UPDATE_TIP_FIELD
  493. // If we were called due to an Explorer crash, I don't think it's necessary to call
  494. // Shell_NotifyIcon() to remove the old tray icon because it was likely destroyed
  495. // along with Explorer. So just add it unconditionally:
  496. if (!Shell_NotifyIcon(NIM_ADD, &mNIC))
  497. mNIC.hWnd = NULL; // Set this as an indicator that tray icon is not installed.
  498. }
  499. void Script::UpdateTrayIcon(bool aForceUpdate)
  500. {
  501. if (!mNIC.hWnd) // tray icon is not installed
  502. return;
  503. static bool icon_shows_paused = false;
  504. static bool icon_shows_suspended = false;
  505. if (!aForceUpdate && (mIconFrozen || (g->IsPaused == icon_shows_paused && g_IsSuspended == icon_shows_suspended)))
  506. return; // it's already in the right state
  507. int icon;
  508. if (g->IsPaused && g_IsSuspended)
  509. icon = IDI_PAUSE_SUSPEND;
  510. else if (g->IsPaused)
  511. icon = IDI_PAUSE;
  512. else if (g_IsSuspended)
  513. icon = g_IconTraySuspend;
  514. else
  515. #ifdef AUTOHOTKEYSC
  516. icon = mCompiledHasCustomIcon ? IDI_MAIN : g_IconTray; // i.e. don't override the user's custom icon.
  517. #else
  518. icon = g_IconTray;
  519. #endif
  520. // Use the custom tray icon if the icon is normal (non-paused & non-suspended):
  521. mNIC.hIcon = (mCustomIcon && (mIconFrozen || (!g->IsPaused && !g_IsSuspended))) ? mCustomIcon
  522. : (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(icon), IMAGE_ICON, 0, 0, LR_SHARED); // Use LR_SHARED for simplicity and performance more than to conserve memory in this case.
  523. if (Shell_NotifyIcon(NIM_MODIFY, &mNIC))
  524. {
  525. icon_shows_paused = g->IsPaused;
  526. icon_shows_suspended = g_IsSuspended;
  527. }
  528. // else do nothing, just leave it in the same state.
  529. }
  530. ResultType Script::AutoExecSection()
  531. // Returns FAIL if can't run due to critical error. Otherwise returns OK.
  532. {
  533. // Now that g_MaxThreadsTotal has been permanently set by the processing of script directives like
  534. // #MaxThreads, an appropriately sized array can be allocated:
  535. if ( !(g_array = (global_struct *)malloc((g_MaxThreadsTotal+TOTAL_ADDITIONAL_THREADS) * sizeof(global_struct))) )
  536. return FAIL; // Due to rarity, just abort. It wouldn't be safe to run ExitApp() due to possibility of an OnExit routine.
  537. CopyMemory(g_array, g, sizeof(global_struct)); // Copy the temporary/startup "g" into array[0] to preserve historical behaviors that may rely on the idle thread starting with that "g".
  538. g = g_array; // Must be done after above.
  539. // v1.0.48: Due to switching from SET_UNINTERRUPTIBLE_TIMER to IsInterruptible():
  540. // In spite of the comments in IsInterruptible(), periodically have a timer call IsInterruptible() due to
  541. // the following scenario:
  542. // - Interrupt timeout is 60 seconds (or 60 milliseconds for that matter).
  543. // - For some reason IsInterrupt() isn't called for 24+ hours even though there is a current/active thread.
  544. // - RefreshInterruptibility() fires at 23 hours and marks the thread interruptible.
  545. // - Sometime after that, one of the following happens:
  546. // Computer is suspended/hibernated and stays that way for 50+ days.
  547. // IsInterrupt() is never called (except by RefreshInterruptibility()) for 50+ days.
  548. // (above is currently unlikely because MSG_FILTER_MAX calls IsInterruptible())
  549. // In either case, RefreshInterruptibility() has prevented the uninterruptibility duration from being
  550. // wrongly extended by up to 100% of g_script.mUninterruptibleTime. This isn't a big deal if
  551. // g_script.mUninterruptibleTime is low (like it almost always is); but if it's fairly large, say an hour,
  552. // this can prevent an unwanted extension of up to 1 hour.
  553. // Although any call frequency less than 49.7 days should work, currently calling once per 23 hours
  554. // in case any older operating systems have a SetTimer() limit of less than 0x7FFFFFFF (and also to make
  555. // it less likely that a long suspend/hibernate would cause the above issue). The following was
  556. // actually tested on Windows XP and a message does indeed arrive 23 hours after the script starts.
  557. SetTimer(g_hWnd, TIMER_ID_REFRESH_INTERRUPTIBILITY, 23*60*60*1000, RefreshInterruptibility); // 3rd param must not exceed 0x7FFFFFFF (2147483647; 24.8 days).
  558. ResultType ExecUntil_result;
  559. if (!mFirstLine) // In case it's ever possible to be empty.
  560. ExecUntil_result = OK;
  561. // And continue on to do normal exit routine so that the right ExitCode is returned by the program.
  562. else
  563. {
  564. // Choose a timeout that's a reasonable compromise between the following competing priorities:
  565. // 1) That we want hotkeys to be responsive as soon as possible after the program launches
  566. // in case the user launches by pressing ENTER on a script, for example, and then immediately
  567. // tries to use a hotkey. In addition, we want any timed subroutines to start running ASAP
  568. // because in rare cases the user might rely upon that happening.
  569. // 2) To support the case when the auto-execute section never finishes (such as when it contains
  570. // an infinite loop to do background processing), yet we still want to allow the script
  571. // to put custom defaults into effect globally (for things such as KeyDelay).
  572. // Obviously, the above approach has its flaws; there are ways to construct a script that would
  573. // result in unexpected behavior. However, the combination of this approach with the fact that
  574. // the global defaults are updated *again* when/if the auto-execute section finally completes
  575. // raises the expectation of proper behavior to a very high level. In any case, I'm not sure there
  576. // is any better approach that wouldn't break existing scripts or require a redesign of some kind.
  577. // If this method proves unreliable due to disk activity slowing the program down to a crawl during
  578. // the critical milliseconds after launch, one thing that might fix that is to have ExecUntil()
  579. // be forced to run a minimum of, say, 100 lines (if there are that many) before allowing the
  580. // timer expiration to have its effect. But that's getting complicated and I'd rather not do it
  581. // unless someone actually reports that such a thing ever happens. Still, to reduce the chance
  582. // of such a thing ever happening, it seems best to boost the timeout from 50 up to 100:
  583. SET_AUTOEXEC_TIMER(100);
  584. mAutoExecSectionIsRunning = true;
  585. // v1.0.25: This is now done here, closer to the actual execution of the first line in the script,
  586. // to avoid an unnecessary Sleep(10) that would otherwise occur in ExecUntil:
  587. mLastScriptRest = mLastPeekTime = GetTickCount();
  588. ++g_nThreads;
  589. ExecUntil_result = mFirstLine->ExecUntil(UNTIL_RETURN); // Might never return (e.g. infinite loop or ExitApp).
  590. --g_nThreads;
  591. // Our caller will take care of setting g_default properly.
  592. KILL_AUTOEXEC_TIMER // See also: AutoExecSectionTimeout().
  593. mAutoExecSectionIsRunning = false;
  594. }
  595. // REMEMBER: The ExecUntil() call above will never return if the AutoExec section never finishes
  596. // (e.g. infinite loop) or it uses Exit/ExitApp.
  597. // The below is done even if AutoExecSectionTimeout() already set the values once.
  598. // This is because when the AutoExecute section finally does finish, by definition it's
  599. // supposed to store the global settings that are currently in effect as the default values.
  600. // In other words, the only purpose of AutoExecSectionTimeout() is to handle cases where
  601. // the AutoExecute section takes a long time to complete, or never completes (perhaps because
  602. // it is being used by the script as a "backround thread" of sorts):
  603. // Save the values of KeyDelay, WinDelay etc. in case they were changed by the auto-execute part
  604. // of the script. These new defaults will be put into effect whenever a new hotkey subroutine
  605. // is launched. Each launched subroutine may then change the values for its own purposes without
  606. // affecting the settings for other subroutines:
  607. global_clear_state(*g); // Start with a "clean slate" in both g_default and g (in case things like InitNewThread() check some of the values in g prior to launching a new thread).
  608. // Always want g_default.AllowInterruption==true so that InitNewThread() doesn't have to
  609. // set it except when Critical or "Thread Interrupt" require it. If the auto-execute section ended
  610. // without anyone needing to call IsInterruptible() on it, AllowInterruption could be false
  611. // even when Critical is off.
  612. // Even if the still-running AutoExec section has turned on Critical, the assignment below is still okay
  613. // because InitNewThread() adjusts AllowInterruption based on the value of ThreadIsCritical.
  614. // See similar code in AutoExecSectionTimeout().
  615. g->AllowThreadToBeInterrupted = true; // Mostly for the g_default line below. See comments above.
  616. CopyMemory(&g_default, g, sizeof(global_struct)); // g->IsPaused has been set to false higher above in case it's ever possible that it's true as a result of AutoExecSection().
  617. // After this point, the values in g_default should never be changed.
  618. global_maximize_interruptibility(*g); // See below.
  619. // Now that any changes made by the AutoExec section have been saved to g_default (including
  620. // the commands Critical and Thread), ensure that the very first g-item is always interruptible.
  621. // This avoids having to treat the first g-item as special in various places.
  622. // It seems best to set ErrorLevel to NONE after the auto-execute part of the script is done.
  623. // However, it isn't set to NONE right before launching each new thread (e.g. hotkey subroutine)
  624. // because it's more flexible that way (i.e. the user may want one hotkey subroutine to use the value
  625. // of ErrorLevel set by another). This reset was also done by LoadFromFile(), but it is done again
  626. // here in case the auto-execute section changed it:
  627. g_ErrorLevel->Assign(ERRORLEVEL_NONE);
  628. // BEFORE DOING THE BELOW, "g" and "g_default" should be set up properly in case there's an OnExit
  629. // routine (even non-persistent scripts can have one).
  630. // If no hotkeys are in effect, the user hasn't requested a hook to be activated, and the script
  631. // doesn't contain the #Persistent directive we're done unless there is an OnExit subroutine and it
  632. // doesn't do "ExitApp":
  633. if (!IS_PERSISTENT) // Resolve macro again in case any of its components changed since the last time.
  634. g_script.ExitApp(ExecUntil_result == FAIL ? EXIT_ERROR : EXIT_EXIT);
  635. return OK;
  636. }
  637. ResultType Script::Edit()
  638. {
  639. #ifdef AUTOHOTKEYSC
  640. return OK; // Do nothing.
  641. #else
  642. // This is here in case a compiled script ever uses the Edit command. Since the "Edit This
  643. // Script" menu item is not available for compiled scripts, it can't be called from there.
  644. TitleMatchModes old_mode = g->TitleMatchMode;
  645. g->TitleMatchMode = FIND_ANYWHERE;
  646. HWND hwnd = WinExist(*g, mFileName, "", mMainWindowTitle, ""); // Exclude our own main window.
  647. g->TitleMatchMode = old_mode;
  648. if (hwnd)
  649. {
  650. char class_name[32];
  651. GetClassName(hwnd, class_name, sizeof(class_name));
  652. if (!strcmp(class_name, "#32770") || !strnicmp(class_name, "AutoHotkey", 10)) // MessageBox(), InputBox(), FileSelectFile(), or GUI/script-owned window.
  653. hwnd = NULL; // Exclude it from consideration.
  654. }
  655. if (hwnd) // File appears to already be open for editing, so use the current window.
  656. SetForegroundWindowEx(hwnd);
  657. else
  658. {
  659. char buf[MAX_PATH * 2];
  660. // Enclose in double quotes anything that might contain spaces since the CreateProcess()
  661. // method, which is attempted first, is more likely to succeed. This is because it uses
  662. // the command line method of creating the process, with everything all lumped together:
  663. snprintf(buf, sizeof(buf), "\"%s\"", mFileSpec);
  664. if (!ActionExec("edit", buf, mFileDir, false)) // Since this didn't work, try notepad.
  665. {
  666. // v1.0.40.06: Try to open .ini files first with their associated editor rather than trying the
  667. // "edit" verb on them:
  668. char *file_ext;
  669. if ( !(file_ext = strrchr(mFileName, '.')) || stricmp(file_ext, ".ini")
  670. || !ActionExec("open", buf, mFileDir, false) ) // Relies on short-circuit boolean order.
  671. {
  672. // Even though notepad properly handles filenames with spaces in them under WinXP,
  673. // even without double quotes around them, it seems safer and more correct to always
  674. // enclose the filename in double quotes for maximum compatibility with all OSes:
  675. if (!ActionExec("notepad.exe", buf, mFileDir, false))
  676. MsgBox("Could not open script."); // Short message since so rare.
  677. }
  678. }
  679. }
  680. return OK;
  681. #endif
  682. }
  683. ResultType Script::Reload(bool aDisplayErrors)
  684. {
  685. // The new instance we're about to start will tell our process to stop, or it will display
  686. // a syntax error or some other error, in which case our process will still be running:
  687. #ifdef AUTOHOTKEYSC
  688. // This is here in case a compiled script ever uses the Reload command. Since the "Reload This
  689. // Script" menu item is not available for compiled scripts, it can't be called from there.
  690. return g_script.ActionExec(mOurEXE, "/restart", g_WorkingDirOrig, aDisplayErrors);
  691. #else
  692. char arg_string[MAX_PATH + 512];
  693. snprintf(arg_string, sizeof(arg_string), "/restart \"%s\"", mFileSpec);
  694. return g_script.ActionExec(mOurEXE, arg_string, g_WorkingDirOrig, aDisplayErrors);
  695. #endif
  696. }
  697. ResultType Script::ExitApp(ExitReasons aExitReason, char *aBuf, int aExitCode)
  698. // Normal exit (if aBuf is NULL), or a way to exit immediately on error (which is mostly
  699. // for times when it would be unsafe to call MsgBox() due to the possibility that it would
  700. // make the situation even worse).
  701. {
  702. mExitReason = aExitReason;
  703. bool terminate_afterward = aBuf && !*aBuf;
  704. if (aBuf && *aBuf)
  705. {
  706. char buf[1024];
  707. // No more than size-1 chars will be written and string will be terminated:
  708. snprintf(buf, sizeof(buf), "Critical Error: %s\n\n" WILL_EXIT, aBuf);
  709. // To avoid chance of more errors, don't use MsgBox():
  710. MessageBox(g_hWnd, buf, g_script.mFileSpec, MB_OK | MB_SETFOREGROUND | MB_APPLMODAL);
  711. TerminateApp(CRITICAL_ERROR); // Only after the above.
  712. }
  713. // Otherwise, it's not a critical error. Note that currently, mOnExitLabel can only be
  714. // non-NULL if the script is in a runnable state (since registering an OnExit label requires
  715. // that a script command has executed to do it). If this ever changes, the !mIsReadyToExecute
  716. // condition should be added to the below if statement:
  717. static bool sExitLabelIsRunning = false;
  718. if (!mOnExitLabel || sExitLabelIsRunning) // || !mIsReadyToExecute
  719. // In the case of sExitLabelIsRunning == true:
  720. // There is another instance of this function beneath us on the stack. Since we have
  721. // been called, this is a true exit condition and we exit immediately.
  722. // MUST NOT create a new thread when sExitLabelIsRunning because g_array allows only one
  723. // extra thread for ExitApp() (which allows it to run even when MAX_THREADS_EMERGENCY has
  724. // been reached). See TOTAL_ADDITIONAL_THREADS.
  725. TerminateApp(aExitCode);
  726. // Otherwise, the script contains the special RunOnExit label that we will run here instead
  727. // of exiting. And since it does, we know that the script is in a ready-to-execute state
  728. // because that is the only way an OnExit label could have been defined in the first place.
  729. // Usually, the RunOnExit subroutine will contain an Exit or ExitApp statement
  730. // which results in a recursive call to this function, but this is not required (e.g. the
  731. // Exit subroutine could display an "Are you sure?" prompt, and if the user chooses "No",
  732. // the Exit sequence can be aborted by simply not calling ExitApp and letting the thread
  733. // we create below end normally).
  734. // Next, save the current state of the globals so that they can be restored just prior
  735. // to returning to our caller:
  736. char ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE];
  737. strlcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), sizeof(ErrorLevel_saved)); // Save caller's errorlevel.
  738. InitNewThread(0, true, true, ACT_INVALID); // Uninterruptibility is handled below. Since this special thread should always run, no checking of g_MaxThreadsTotal is done before calling this.
  739. // Turn on uninterruptibility to forbid any hotkeys, timers, or user defined menu items
  740. // to interrupt. This is mainly done for peace-of-mind (since possible interactions due to
  741. // interruptions have not been studied) and the fact that this most users would not want this
  742. // subroutine to be interruptible (it usually runs quickly anyway). Another reason to make
  743. // it non-interruptible is that some OnExit subroutines might destruct things used by the
  744. // script's hotkeys/timers/menu items, and activating these items during the deconstruction
  745. // would not be safe. Finally, if a logoff or shutdown is occurring, it seems best to prevent
  746. // timed subroutines from running -- which might take too much time and prevent the exit from
  747. // occurring in a timely fashion. An option can be added via the FutureUse param to make it
  748. // interruptible if there is ever a demand for that.
  749. // UPDATE: g_AllowInterruption is now used instead of g->AllowThreadToBeInterrupted for two reasons:
  750. // 1) It avoids the need to do "int mUninterruptedLineCountMax_prev = g_script.mUninterruptedLineCountMax;"
  751. // (Disable this item so that ExecUntil() won't automatically make our new thread uninterruptible
  752. // after it has executed a certain number of lines).
  753. // 2) Mostly obsolete: If the thread we're interrupting is uninterruptible, the uinterruptible timer
  754. // might be currently pending. When it fires, it would make the OnExit subroutine interruptible
  755. // rather than the underlying subroutine. The above fixes the first part of that problem.
  756. // The 2nd part is fixed by reinstating the timer when the uninterruptible thread is resumed.
  757. // This special handling is only necessary here -- not in other places where new threads are
  758. // created -- because OnExit is the only type of thread that can interrupt an uninterruptible
  759. // thread.
  760. BOOL g_AllowInterruption_prev = g_AllowInterruption; // Save current setting.
  761. g_AllowInterruption = FALSE; // Mark the thread just created above as permanently uninterruptible (i.e. until it finishes and is destroyed).
  762. sExitLabelIsRunning = true;
  763. if (mOnExitLabel->Execute() == FAIL)
  764. // If the subroutine encounters a failure condition such as a runtime error, exit immediately.
  765. // Otherwise, there will be no way to exit the script if the subroutine fails on each attempt.
  766. TerminateApp(aExitCode);
  767. sExitLabelIsRunning = false; // In case the user wanted the thread to end normally (see above).
  768. if (terminate_afterward)
  769. TerminateApp(aExitCode);
  770. // Otherwise:
  771. ResumeUnderlyingThread(ErrorLevel_saved);
  772. g_AllowInterruption = g_AllowInterruption_prev; // Restore original setting.
  773. return OK; // for caller convenience.
  774. }
  775. void Script::TerminateApp(int aExitCode)
  776. // Note that g_script's destructor takes care of most other cleanup work, such as destroying
  777. // tray icons, menus, and unowned windows such as ToolTip.
  778. {
  779. // We call DestroyWindow() because MainWindowProc() has left that up to us.
  780. // DestroyWindow() will cause MainWindowProc() to immediately receive and process the
  781. // WM_DESTROY msg, which should in turn result in any child windows being destroyed
  782. // and other cleanup being done:
  783. if (IsWindow(g_hWnd)) // Adds peace of mind in case WM_DESTROY was already received in some unusual way.
  784. {
  785. g_DestroyWindowCalled = true;
  786. DestroyWindow(g_hWnd);
  787. }
  788. Hotkey::AllDestructAndExit(aExitCode);
  789. }
  790. #ifdef AUTOHOTKEYSC
  791. LineNumberType Script::LoadFromFile()
  792. #else
  793. LineNumberType Script::LoadFromFile(bool aScriptWasNotspecified)
  794. #endif
  795. // Returns the number of non-comment lines that were loaded, or LOADING_FAILED on error.
  796. {
  797. mNoHotkeyLabels = true; // Indicate that there are no hotkey labels, since we're (re)loading the entire file.
  798. mIsReadyToExecute = mAutoExecSectionIsRunning = false;
  799. if (!mFileSpec || !*mFileSpec) return LOADING_FAILED;
  800. #ifndef AUTOHOTKEYSC // When not in stand-alone mode, read an external script file.
  801. DWORD attr = GetFileAttributes(mFileSpec);
  802. if (attr == MAXDWORD) // File does not exist or lacking the authorization to get its attributes.
  803. {
  804. char buf[MAX_PATH + 256];
  805. if (aScriptWasNotspecified) // v1.0.46.09: Give a more descriptive prompt to help users get started.
  806. {
  807. snprintf(buf, sizeof(buf),
  808. "To help you get started, would you like to create a sample script in the My Documents folder?\n"
  809. "\n"
  810. "Press YES to create and display the sample script.\n"
  811. "Press NO to exit.\n");
  812. }
  813. else // Mostly for backward compatibility, also prompt to create if an explicitly specified script doesn't exist.
  814. snprintf(buf, sizeof(buf), "The script file \"%s\" does not exist. Create it now?", mFileSpec);
  815. int response = MsgBox(buf, MB_YESNO);
  816. if (response != IDYES)
  817. return 0;
  818. FILE *fp2 = fopen(mFileSpec, "a");
  819. if (!fp2)
  820. {
  821. MsgBox("Could not create file, perhaps because the current directory is read-only"
  822. " or has insufficient permissions.");
  823. return LOADING_FAILED;
  824. }
  825. fputs(
  826. "; IMPORTANT INFO ABOUT GETTING STARTED: Lines that start with a\n"
  827. "; semicolon, such as this one, are comments. They are not executed.\n"
  828. "\n"
  829. "; This script has a special filename and path because it is automatically\n"
  830. "; launched when you run the program directly. Also, any text file whose\n"
  831. "; name ends in .ahk is associated with the program, which means that it\n"
  832. "; can be launched simply by double-clicking it. You can have as many .ahk\n"
  833. "; files as you want, located in any folder. You can also run more than\n"
  834. "; one ahk file simultaneously and each will get its own tray icon.\n"
  835. "\n"
  836. "; SAMPLE HOTKEYS: Below are two sample hotkeys. The first is Win+Z and it\n"
  837. "; launches a web site in the default browser. The second is Control+Alt+N\n"
  838. "; and it launches a new Notepad window (or activates an existing one). To\n"
  839. "; try out these hotkeys, run AutoHotkey again, which will load this file.\n"
  840. "\n"
  841. "#z::Run www.autohotkey.com\n"
  842. "\n"
  843. "^!n::\n"
  844. "IfWinExist Untitled - Notepad\n"
  845. "\tWinActivate\n"
  846. "else\n"
  847. "\tRun Notepad\n"
  848. "return\n"
  849. "\n"
  850. "\n"
  851. "; Note: From now on whenever you run AutoHotkey directly, this script\n"
  852. "; will be loaded. So feel free to customize it…

Large files files are truncated, but you can click here to view the full file