예제 #1
0
/** 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;
}
예제 #2
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);
}
예제 #3
0
/** 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;
}
예제 #4
0
/** 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;
}
예제 #5
0
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;
}
예제 #6
0
/** 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;
}