void callFuncDllVariant(FuncAndToken *aFuncAndToken) { Func &func = *(aFuncAndToken->mFunc); ExprTokenType & aResultToken = aFuncAndToken->mToken ; // Func &func = *(Func *)g_script.mTempFunc ; if (!INTERRUPTIBLE_IN_EMERGENCY) return; if (g_nThreads >= g_MaxThreadsTotal) // Below: Only a subset of ACT_IS_ALWAYS_ALLOWED is done here because: // 1) The omitted action types seem too obscure to grant always-run permission for msg-monitor events. // 2) Reduction in code size. if (g_nThreads >= MAX_THREADS_EMERGENCY // To avoid array overflow, this limit must by obeyed except where otherwise documented. || func.mJumpToLine->mActionType != ACT_EXITAPP && func.mJumpToLine->mActionType != ACT_RELOAD) return; // Need to check if backup is needed in case script explicitly called the function rather than using // it solely as a callback. UPDATE: And now that max_instances is supported, also need it for that. // See ExpandExpression() for detailed comments about the following section. VarBkp *var_backup = NULL; // If needed, it will hold an array of VarBkp objects. int var_backup_count; // The number of items in the above array. if (func.mInstances > 0) // Backup is needed. if (!Var::BackupFunctionVars(func, var_backup, var_backup_count)) // Out of memory. return; // Since we're in the middle of processing messages, and since out-of-memory is so rare, // it seems justifiable not to have any error reporting and instead just avoid launching // the new thread. // Since above didn't return, the launch of the new thread is now considered unavoidable. // See MsgSleep() for comments about the following section. TCHAR ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE]; tcslcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), _countof(ErrorLevel_saved)); InitNewThread(0, false, true, func.mJumpToLine->mActionType); // v1.0.38.04: Below was added to maximize responsiveness to incoming messages. The reasoning // is similar to why the same thing is done in MsgSleep() prior to its launch of a thread, so see // MsgSleep for more comments: g_script.mLastScriptRest = g_script.mLastPeekTime = GetTickCount(); DEBUGGER_STACK_PUSH(func.mJumpToLine, func.mName) // ExprTokenType aResultToken; // ExprTokenType &aResultToken = aResultToken_to_return ; func.Call(&aResultToken); // Call the UDF. TokenToVariant(aResultToken, aFuncAndToken->variant_to_return_dll); DEBUGGER_STACK_POP() ResumeUnderlyingThread(ErrorLevel_saved); return; }
//H30 changed to not return anything since it is not used void callFuncDll(FuncAndToken *aFuncAndToken) { Func &func = *(aFuncAndToken->mFunc); ExprTokenType & aResultToken = aFuncAndToken->mToken ; // Func &func = *(Func *)g_script.mTempFunc ; if (!INTERRUPTIBLE_IN_EMERGENCY) return; if (g_nThreads >= g_MaxThreadsTotal) // Below: Only a subset of ACT_IS_ALWAYS_ALLOWED is done here because: // 1) The omitted action types seem too obscure to grant always-run permission for msg-monitor events. // 2) Reduction in code size. if (g_nThreads >= MAX_THREADS_EMERGENCY // To avoid array overflow, this limit must by obeyed except where otherwise documented. || func.mJumpToLine->mActionType != ACT_EXITAPP && func.mJumpToLine->mActionType != ACT_RELOAD) return; // Need to check if backup is needed in case script explicitly called the function rather than using // it solely as a callback. UPDATE: And now that max_instances is supported, also need it for that. // See ExpandExpression() for detailed comments about the following section. VarBkp *var_backup = NULL; // If needed, it will hold an array of VarBkp objects. int var_backup_count; // The number of items in the above array. if (func.mInstances > 0) // Backup is needed. if (!Var::BackupFunctionVars(func, var_backup, var_backup_count)) // Out of memory. return; // Since we're in the middle of processing messages, and since out-of-memory is so rare, // it seems justifiable not to have any error reporting and instead just avoid launching // the new thread. // Since above didn't return, the launch of the new thread is now considered unavoidable. // See MsgSleep() for comments about the following section. TCHAR ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE]; tcslcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), _countof(ErrorLevel_saved)); InitNewThread(0, false, true, func.mJumpToLine->mActionType); // v1.0.38.04: Below was added to maximize responsiveness to incoming messages. The reasoning // is similar to why the same thing is done in MsgSleep() prior to its launch of a thread, so see // MsgSleep for more comments: g_script.mLastScriptRest = g_script.mLastPeekTime = GetTickCount(); DEBUGGER_STACK_PUSH(func.mJumpToLine, func.mName) // ExprTokenType aResultToken; // ExprTokenType &aResultToken = aResultToken_to_return ; func.Call(&aResultToken); // Call the UDF. DEBUGGER_STACK_POP() switch (aFuncAndToken->mToken.symbol) { case SYM_VAR: // Caller has ensured that any SYM_VAR's Type() is VAR_NORMAL. if (_tcslen(aFuncAndToken->mToken.var->Contents())) { aFuncAndToken->result_to_return_dll = (LPTSTR )realloc((LPTSTR )aFuncAndToken->result_to_return_dll,_tcslen(aFuncAndToken->mToken.var->Contents())*sizeof(TCHAR)); _tcscpy(aFuncAndToken->result_to_return_dll,aFuncAndToken->mToken.var->Contents()); // Contents() vs. mContents to support VAR_CLIPBOARD, and in case mContents needs to be updated by Contents(). } else if (aFuncAndToken->result_to_return_dll) *aFuncAndToken->result_to_return_dll = '\0'; break; case SYM_STRING: case SYM_OPERAND: if (_tcslen(aFuncAndToken->mToken.marker)) { aFuncAndToken->result_to_return_dll = (LPTSTR )realloc((LPTSTR )aFuncAndToken->result_to_return_dll,_tcslen(aFuncAndToken->mToken.marker)*sizeof(TCHAR)); _tcscpy(aFuncAndToken->result_to_return_dll,aFuncAndToken->mToken.marker); } else if (aFuncAndToken->result_to_return_dll) *aFuncAndToken->result_to_return_dll = '\0'; break; case SYM_INTEGER: aFuncAndToken->result_to_return_dll = (LPTSTR )realloc((LPTSTR )aFuncAndToken->result_to_return_dll,MAX_INTEGER_LENGTH); ITOA64(aFuncAndToken->mToken.value_int64, aFuncAndToken->result_to_return_dll); break; case SYM_FLOAT: result_to_return_dll = (LPTSTR )realloc((LPTSTR )aFuncAndToken->result_to_return_dll,MAX_INTEGER_LENGTH); sntprintf(aFuncAndToken->result_to_return_dll, MAX_NUMBER_SIZE, g->FormatFloat, aFuncAndToken->mToken.value_double); break; //case SYM_OBJECT: // L31: Treat objects as empty strings (or TRUE where appropriate). default: // Not an operand: continue on to return the default at the bottom. if (aFuncAndToken->result_to_return_dll) *aFuncAndToken->result_to_return_dll = '\0'; } //Var::FreeAndRestoreFunctionVars(func, var_backup, var_backup_count); ResumeUnderlyingThread(ErrorLevel_saved); return; }
bool callFunc(WPARAM awParam, LPARAM alParam) { Func &func = *(Func *)g_script.mTempFunc ; if (!INTERRUPTIBLE_IN_EMERGENCY) return false; if (g_nThreads >= g_MaxThreadsTotal) // Below: Only a subset of ACT_IS_ALWAYS_ALLOWED is done here because: // 1) The omitted action types seem too obscure to grant always-run permission for msg-monitor events. // 2) Reduction in code size. if (func.mJumpToLine->mActionType != ACT_EXITAPP && func.mJumpToLine->mActionType != ACT_RELOAD) return false; // Need to check if backup is needed in case script explicitly called the function rather than using // it solely as a callback. UPDATE: And now that max_instances is supported, also need it for that. // See ExpandExpression() for detailed comments about the following section. VarBkp *var_backup = NULL; // If needed, it will hold an array of VarBkp objects. int var_backup_count; // The number of items in the above array. if (func.mInstances > 0) // Backup is needed. if (!Var::BackupFunctionVars(func, var_backup, var_backup_count)) // Out of memory. return false; // Since we're in the middle of processing messages, and since out-of-memory is so rare, // it seems justifiable not to have any error reporting and instead just avoid launching // the new thread. // Since above didn't return, the launch of the new thread is now considered unavoidable. // See MsgSleep() for comments about the following section. char ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE]; strlcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), sizeof(ErrorLevel_saved)); global_struct global_saved; CopyMemory(&global_saved, &g, sizeof(global_struct)); InitNewThread(0, false, true, func.mJumpToLine->mActionType); // See ExpandExpression() for detailed comments about the following section. if (func.mParamCount > 0) { // Copy the appropriate values into each of the function's formal parameters. func.mParam[0].var->Assign((char *)awParam); // Assign parameter #1: wParam if (func.mParamCount > 1) // Assign parameter #2: lParam { // v1.0.38.01: LPARAM is now written out as a DWORD because the majority of system messages // use LPARAM as a pointer or other unsigned value. This shouldn't affect most scripts because // of the way ATOI64() and ATOU() wrap a negative number back into the unsigned domain for // commands such as PostMessage/SendMessage. func.mParam[1].var->Assign((char *)alParam); } } // v1.0.38.04: Below was added to maximize responsiveness to incoming messages. The reasoning // is similar to why the same thing is done in MsgSleep() prior to its launch of a thread, so see // MsgSleep for more comments: g_script.mLastScriptRest = g_script.mLastPeekTime = GetTickCount(); char *return_value; func.Call(return_value); // Call the UDF. // Fix for v1.0.47: Must handle return_value BEFORE calling FreeAndRestoreFunctionVars() because return_value // might be the contents of one of the function's local variables (which are about to be free'd). /* bool block_further_processing = *return_value; // No need to check the following because they're implied for *return_value!=0: result != EARLY_EXIT && result != FAIL; if (block_further_processing) aMsgReply = (LPARAM)ATOI64(return_value); // Use 64-bit in case it's an unsigned number greater than 0x7FFFFFFF, in which case this allows it to wrap around to a negative. //else leave aMsgReply uninitialized because we'll be returning false later below, which tells our caller // to ignore aMsgReply. */ Var::FreeAndRestoreFunctionVars(func, var_backup, var_backup_count); ResumeUnderlyingThread(&global_saved, ErrorLevel_saved, true); return 0 ; // block_further_processing; // If false, the caller will ignore aMsgReply and process this message normally. If true, aMsgReply contains the reply the caller should immediately send for this message. }