/** winTimer() * * The classic Rexx external function, WinTimer() was documented prior to 4.0.0 * and therefore needs to be retained for backward compatibility. * * The original implementation was poor, using SetTimer() / KillTimer(). For * the wait mode, it used this loop: * * else if ( stricmp("WAIT", mode) == 0 ) * { * while ( !PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) * { * ; // do nothing * } * return 0; * } * * PeekMessage() returns immediately if there are no messages. Since there * were probably no windows on the thread, the WAIT function spun in a busy * loop consuming 100% of the CPU. * * svn revision 8968 and previous contains the original implementation if there * is a need to review that code. * * The original implmentation was replaced in ooDialog 4.2.2 with this * implementation using waitable timers instead. It is backwards compatible * with the original implementation, and needs to remain that way. * * For very small periods, SetTimer replaces the specified time with * USER_TIMER_MINIMUM. So when Rexx programmers specified 1 or 2 or 6 * milliseconds, the got USER_TIMER_MINIMUM instead. We mimic that behaviour * here, otherwise programs using a delay of 1 millisecond do not work the * same. We actually use 1.5 times USER_TIMER_MINIMUM because it seems to work * the best. * * @param mode Keyword for what is to be done. START creates the timer and * starts it. WAIT waits on the timer. STOP destroys the * timer. * * @param msOrId Either the period of the timer, in miliseconds, if mode is * START, or the timer ID for the other modes. * * @return The timer ID for the START mode, or success / error return code for * the other modes. * * @notes Sets the .SystemErrorCode. For the STOP and WAIT modes the system * error code value is returned in addition to setting the * .SystemErrorCode. * * @remarks If this routine was being implemented from scratch, it would be * done differently. However since it is being used to preserve * backwards compatibility, this implementation serves best. An * enhancement creating a new Waitable object class would be nice. */ RexxRoutine2(uintptr_t, winTimer_rtn, CSTRING, mode, uintptr_t, msOrId) { oodResetSysErrCode(context->threadContext); if ( stricmp("START", mode) == 0 ) { HANDLE hTimer = NULL; LARGE_INTEGER liDueTime; if ( msOrId < USER_TIMER_MINIMUM + 5 ) { msOrId = USER_TIMER_MINIMUM + 5; } liDueTime.QuadPart = msOrId * -10000; hTimer = CreateWaitableTimer(NULL, FALSE, NULL); if ( hTimer == NULL ) { oodSetSysErrCode(context->threadContext); return 0; } if ( ! SetWaitableTimer(hTimer, &liDueTime, (int32_t)msOrId, NULL, NULL, FALSE) ) { oodSetSysErrCode(context->threadContext); return 0; } return (uintptr_t)hTimer; } else if ( stricmp("STOP", mode) == 0 ) { if ( CancelWaitableTimer((HANDLE)msOrId) == 0 ) { uint32_t rc = GetLastError(); oodSetSysErrCode(context->threadContext, rc); return rc; } return 0; } else if ( stricmp("WAIT", mode) == 0 ) { if ( WaitForSingleObject((HANDLE)msOrId, INFINITE) != WAIT_OBJECT_0 ) { uint32_t rc = GetLastError(); oodSetSysErrCode(context->threadContext, rc); return rc; } return 0; } wrongArgValueException(context->threadContext, 1, "START, STOP, WAIT", mode); return 0; }
/** findWindow() * * Retrieves a window handle to the top-level window whose class name and * window name match the specified strings. This function does not search child * windows. This function does not perform a case-sensitive search. * * @param caption The title of the window to search for. Although this * argument is required, the empty string can be used to * indicate a null should be used for the caption. * * @param className [optional] Specifies the window class name of the window * to search for. The class name can be any name registered * with RegisterClass() or RegisterClassEx(), or any of the * predefined control-class names. * * If className is omitted, it finds any window whose title * matches the caption argument. * * @return The window handle if the window is found, otherwise 0. * * @note Sets the system error code. */ RexxRoutine2(RexxObjectPtr, findWindow_rtn, CSTRING, caption, OPTIONAL_CSTRING, className) { oodResetSysErrCode(context->threadContext); if ( strlen(caption) == 0 ) { caption = NULL; } HWND hwnd = FindWindow(className, caption); if ( hwnd == NULL ) { oodSetSysErrCode(context->threadContext); } return pointer2string(context->threadContext, hwnd); }
/** DialogControl::textSize() * * Computes the width and height in pixels of the specified string of text when * displayed by this control. * * @param text The text whose size is needed. * @param size [IN/OUT] A .Size object, the calculated size is returned here. * * @return True on success, otherwise false. It is unlikely that this * function would fail. * * @note Sets the .SystemErrorCode. */ RexxMethod3(RexxObjectPtr, dlgctrl_textSize, CSTRING, text, RexxObjectPtr, _size, CSELF, pCSelf) { oodResetSysErrCode(context->threadContext); RexxObjectPtr result = TheFalseObj; PSIZE size = rxGetSize(context, _size, 2); if ( size == NULL ) { return result; } HWND hCtrl = getDChCtrl(pCSelf); HDC hdc = GetDC(hCtrl); if ( hdc == NULL ) { oodSetSysErrCode(context->threadContext); return result; } HFONT hFont = (HFONT)SendMessage(hCtrl, WM_GETFONT, 0, 0); if ( hFont == NULL ) { // Font has not been set. hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); } HFONT hOldFont = (HFONT)SelectObject(hdc, hFont); RXCA2T(text); if ( GetTextExtentPoint32(hdc, textT, (int)_tcslen(textT), size) != 0 ) { result = TheTrueObj; } // Clean up. SelectObject(hdc, hOldFont); ReleaseDC(hCtrl, hdc); return result; }
/** MessageDialog() * * * @param text * @param hwnd Handle of owner window. If the user specifies 0 we do not use * an owner window. If the user omits hwnd, then we try the to * find and use the topmost dialog. * * * @note Sets the .SystemErrorCode. * */ RexxRoutine6(int, messageDialog_rtn, CSTRING, text, OPTIONAL_CSTRING, hwnd, OPTIONAL_CSTRING, _title, OPTIONAL_CSTRING, button, OPTIONAL_CSTRING, icon, OPTIONAL_CSTRING, miscStyles) { oodResetSysErrCode(context->threadContext); int result = -1; char *uprButton = NULL; char *uprIcon = NULL; char *uprMiscStyles = NULL; HWND hwndOwner = (HWND)string2pointer(hwnd); if ( hwndOwner == NULL ) { if ( argumentOmitted(2) && TopDlg != NULL && TopDlg->onTheTop ) { hwndOwner = TopDlg->hDlg; } } CSTRING title = "ooDialog Application Message"; if ( argumentExists(3) ) { title = _title; } // Defaults. These values are all 0. uint32_t flags = MB_OK | MB_DEFBUTTON1 | MB_APPLMODAL; uint32_t flag; if ( argumentExists(4) ) { uprButton = strdupupr(button); if ( uprButton == NULL ) { outOfMemoryException(context->threadContext); goto done_out; } flag = winKeyword2ID(uprButton, context->threadContext, 4, "MessageDialog button keyword"); if ( flag == (int)-1 ) { goto done_out; } flags |= flag; } // There is no default for the icon, if omitted there is no icon. if ( argumentExists(5) ) { uprIcon = strdupupr(icon); if ( uprIcon == NULL ) { outOfMemoryException(context->threadContext); goto done_out; } flag = winKeyword2ID(uprIcon, context->threadContext, 5, "MessageDialog icon keyword"); if ( flag == (int)-1 ) { goto done_out; } flags |= flag; } if ( argumentExists(6) ) { uprMiscStyles = strdupupr(miscStyles); if ( uprMiscStyles == NULL ) { outOfMemoryException(context->threadContext); goto done_out; } flag = getMiscMBStyle(uprMiscStyles, context, 6, "MessageDialog style keyword"); if ( flag == (int)-1 ) { goto done_out; } flags |= flag; } result = MessageBox(hwndOwner, text, title, flags); if ( result == 0 ) { oodSetSysErrCode(context->threadContext); } done_out: safeFree(uprButton); safeFree(uprIcon); safeFree(uprMiscStyles); return result; }
static char *searchSoundPath(CSTRING file, RexxCallContext *c) { oodResetSysErrCode(c->threadContext); // We need a buffer for the path to search, a buffer for the returned full // file name, (if found,) and a pointer to char (an unused arg to // SearchPath().) char *fullFileName = NULL; char *pFileName; // Calculate how much room we need for the search path buffer. uint32_t cchCWD = GetCurrentDirectory(0, NULL); // Many modern systems no longer have the SOUNDPATH set. SetLastError(0); uint32_t cchSoundPath = GetEnvironmentVariable("SOUNDPATH", NULL, 0); uint32_t rc = GetLastError(); if ( cchSoundPath == 0 && rc != ERROR_ENVVAR_NOT_FOUND ) { oodSetSysErrCode(c->threadContext, rc); return NULL; } // Allocate our needed buffers. AutoFree buf = (char *)malloc(cchCWD + cchSoundPath + 3); fullFileName = (char *)malloc(_MAX_PATH); if (buf == NULL || fullFileName == NULL) { safeFree(fullFileName); outOfMemoryException(c->threadContext); } // Now get the current directory and the sound path. cchCWD = GetCurrentDirectory(cchCWD + 1, buf); if (cchCWD == 0) { safeFree(fullFileName); oodSetSysErrCode(c->threadContext); return NULL; } if (cchSoundPath != 0) { buf[cchCWD++] = ';'; cchSoundPath = GetEnvironmentVariable("SOUNDPATH", buf + cchCWD, cchSoundPath + 1); if (cchSoundPath == 0) { safeFree(fullFileName); oodSetSysErrCode(c->threadContext); return NULL; } } AutoErrorMode errorMode(SEM_FAILCRITICALERRORS); cchSoundPath = SearchPath(buf, file, NULL, _MAX_PATH, fullFileName, &pFileName); if (cchSoundPath == 0 || cchSoundPath >= _MAX_PATH) { safeFree(fullFileName); oodSetSysErrCode(c->threadContext); return NULL; } return fullFileName; }
/** DialogControl::connectKeyEvent() * * Experimental! Connects a key event to a method in the Rexx dialog. * * * @return True for success, false for error * * */ RexxMethod2(RexxObjectPtr, dlgctrl_connectKeyEvent, CSTRING, methodName, CSELF, pCSelf) { oodResetSysErrCode(context->threadContext); RexxObjectPtr result = TheFalseObj; if ( ! requiredComCtl32Version(context, "connectKeyEvent", COMCTL32_6_0) ) { goto done_out; } if ( *methodName == '\0' ) { context->RaiseException1(Rexx_Error_Invalid_argument_null, TheOneObj); goto done_out; } pCDialogControl pcdc = (pCDialogControl)pCSelf; SUBCLASSDATA *pData = NULL; BOOL success = GetWindowSubclass(pcdc->hCtrl, KeyEventProc, pcdc->id, (DWORD_PTR *)&pData); // Nothing fancy yet, we could allow removing the subclass. if ( pData != NULL ) { // The subclass is already installed, we call this an error. oodSetSysErrCode(context->threadContext, ERROR_NOT_SUPPORTED); goto done_out; } pData = (SUBCLASSDATA *)LocalAlloc(LPTR, sizeof(SUBCLASSDATA)); if ( pData == NULL ) { outOfMemoryException(context->threadContext); goto done_out; } KEYEVENTDATA *pKeyEventData = (KEYEVENTDATA *)LocalAlloc(LPTR, sizeof(KEYEVENTDATA)); if ( pKeyEventData == NULL ) { LocalFree(pData); outOfMemoryException(context->threadContext); goto done_out; } pKeyEventData->method = (char *)malloc(strlen(methodName) + 1); if ( pKeyEventData->method == NULL ) { freeKeyEventData(pData); outOfMemoryException(context->threadContext); goto done_out; } strcpy(pKeyEventData->method, methodName); pData->hCtrl = pcdc->hCtrl; pData->uID = pcdc->id; pData->pData = pKeyEventData; if ( SendMessage(pcdc->hDlg, WM_USER_SUBCLASS, (WPARAM)KeyEventProc, (LPARAM)pData) == 0 ) { // The subclass was not installed, free memeory, set error code. freeKeyEventData(pData); oodSetSysErrCode(context->threadContext, ERROR_SIGNAL_REFUSED); goto done_out; } result = TheTrueObj; done_out: return result; }