RexxMethod2(logical_t, dlgctrl_hasKeyPressConnection, OPTIONAL_CSTRING, methodName, CSELF, pCSelf) { if ( ComCtl32Version < COMCTL32_6_0 ) { return FALSE; } pCDialogControl pcdc = (pCDialogControl)pCSelf; SUBCLASSDATA *pData = NULL; if ( ! GetWindowSubclass(pcdc->hCtrl, KeyPressSubclassProc, pcdc->id, (DWORD_PTR *)&pData) ) { return FALSE; } if ( pData == NULL ) { return FALSE; } if ( argumentOmitted(1) ) { return TRUE; } char *tmpName = strdupupr(methodName); if ( tmpName == NULL ) { outOfMemoryException(context->threadContext); return FALSE; } BOOL exists = (seekKeyPressMethod((KEYPRESSDATA *)pData->pData, tmpName) > 0); free(tmpName); return exists; }
RexxMethod2(int32_t, dlgctrl_connectFKeyPress, CSTRING, methodName, CSELF, pCSelf) { keyPressErr_t result = connectKeyPressSubclass(context, methodName, "FKEYS", NULL, (pCDialogControl)pCSelf); if ( result == memoryErr ) { outOfMemoryException(context->threadContext); } return -(int32_t)result; }
/** * Creates the Rexx dialog control object that represents the underlying Windows * dialog control. * * The control object can, almost, be created entirely from within the C / C++ * environment. A method context and the Rexx parent dialog are needed. * * @param c * @param hControl * @param hDlg * @param id * @param controlType * @param self * @param isCategoryDlg * @param putInBag * * @return RexxObjectPtr */ RexxObjectPtr createRexxControl(RexxMethodContext *c, HWND hControl, HWND hDlg, uint32_t id, oodControl_t controlType, RexxObjectPtr self, bool isCategoryDlg, bool putInBag) { RexxObjectPtr result = TheNilObj; // Check if the Rexx control object has already been instantiated. RexxObjectPtr rxControl = (RexxObjectPtr)getWindowPtr(hControl, GWLP_USERDATA); if ( rxControl != NULLOBJECT ) { // Okay, this specific control has already had a control object // instantiated to represent it. We return this object. result = rxControl; goto out; } // No pointer is stored in the user data area, so no control object has been // instantiated for this specific control, yet. We instantiate one now and // then store the object in the user data area of the control window. PNEWCONTROLPARAMS pArgs = (PNEWCONTROLPARAMS)malloc(sizeof(NEWCONTROLPARAMS)); if ( pArgs == NULL ) { outOfMemoryException(c->threadContext); goto out; } RexxClassObject controlCls = oodClass4controlType(c, controlType); if ( controlCls == NULLOBJECT ) { goto out; } pArgs->isCatDlg = isCategoryDlg; pArgs->controlType = controlType; pArgs->hwnd = hControl; pArgs->hwndDlg = hDlg; pArgs->id = id; pArgs->parentDlg = self; rxControl = c->SendMessage1(controlCls, "NEW", c->NewPointer(pArgs)); free(pArgs); if ( rxControl != NULLOBJECT && rxControl != TheNilObj ) { result = rxControl; setWindowPtr(hControl, GWLP_USERDATA, (LONG_PTR)result); if ( putInBag ) { c->SendMessage1(self, "PUTCONTROL", result); } } out: return result; }
RexxMethod4(int32_t, dlgctrl_connectKeyPress, CSTRING, methodName, CSTRING, keys, OPTIONAL_CSTRING, filter, CSELF, pCSelf) { keyPressErr_t result = connectKeyPressSubclass(context, methodName, keys, filter, (pCDialogControl)pCSelf); if ( result == memoryErr ) { outOfMemoryException(context->threadContext); } return -(int32_t)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; }
/** fileNameDialog() * * Displays either the Open File or Save File dialog to the user and returns * their selection to the Rexx programmer. * * This serves as the implementation for both the fileNameDialog() and the * getFileNameWindow() public routines. getFileNameWindow() was documented * prior to 4.0.0 and therefore must be retained for backward compatibility. * * All arguments are optional. * * @param preselected * @param _hwndOwner * @param fileFilter * @param loadOrSave * @param _title * @param _defExt * @param multi * @param _sep * * @return The selected file name(s) on success, 0 if the user cancelled or on * error. * * @remarks For the Default file extension. Previous to 4.2.0, .txt was * always used unless the user specified something else. There is * no way for the Rexx programmer to specify no extension. Now, if * the argument is used, but the empty string the programmer can * specify no extension. */ RexxRoutine8(RexxObjectPtr, fileNameDlg_rtn, OPTIONAL_CSTRING, preselected, OPTIONAL_CSTRING, _hwndOwner, OPTIONAL_RexxStringObject, fileFilter, OPTIONAL_CSTRING, loadOrSave, OPTIONAL_CSTRING, _title, OPTIONAL_CSTRING, _defExt, OPTIONAL_CSTRING, multi, OPTIONAL_CSTRING, _sep) { // The bulk of the work here is setting up the open file name struct based // on the arguements passed by the user. OPENFILENAME OpenFileName = {0}; OpenFileName.lStructSize = sizeof(OPENFILENAME); OpenFileName.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING; // Allocate a large buffer for the returned file name(s). char * pszFiles = (char *)LocalAlloc(GPTR, FILENAME_BUFFER_LEN); if ( pszFiles == NULL ) { outOfMemoryException(context->threadContext); return NULLOBJECT; } OpenFileName.lpstrFile = pszFiles; OpenFileName.nMaxFile = FILENAME_BUFFER_LEN; // Preselected file name and / or the directory to start in. if ( argumentExists(1) && *preselected != '\0' ) { if ( preselected[strlen(preselected) - 1] == '\\' ) { OpenFileName.lpstrInitialDir = preselected; } else { StrNCpy(pszFiles, preselected, _MAX_PATH); } } // Possible owner window. if ( argumentExists(2) && *_hwndOwner != '\0' ) { OpenFileName.hwndOwner = (HWND)string2pointer(_hwndOwner); } // File filter string. Note that the string needs to end with a double // null, which has never been documented well to the Rexx user. This makes // it a little tricky if the user sends a string. There is little chance // the user added the extra null. The need for embedded nulls to separate // strings has been documented, so we can expect embedded nulls in the // string. Therefore we have to get the real length of the string data. char *filterBuf = NULL; OpenFileName.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; OpenFileName.nFilterIndex = 1L; if ( argumentExists(3) ) { size_t len = context->StringLength(fileFilter); if ( len > 0 ) { filterBuf = (char *)LocalAlloc(GMEM_FIXED, len + 2); if ( filterBuf == NULL ) { outOfMemoryException(context->threadContext); LocalFree(pszFiles); return NULLOBJECT; } memcpy(filterBuf, context->StringData(fileFilter), len); filterBuf[len] = '\0'; filterBuf[len + 1] = '\0'; OpenFileName.lpstrFilter = filterBuf; } else { OpenFileName.lpstrFilter = NULL; OpenFileName.nFilterIndex = 0; } } // Open or save file dialog. Allow mutiple file selection on open, or not. bool open = true; bool multiSelect = false; if ( argumentExists(4) && *loadOrSave != '\0' ) { char f = toupper(*loadOrSave); if ( f == 'S' || f == '0' ) { open = false; } } if ( open && argumentExists(7) && *multi != '\0' ) { char f = toupper(*multi); if ( f == 'M' || f == '1' ) { multiSelect = true; } } // Dialog title. if ( argumentExists(5) && *_title != '\0' ) { OpenFileName.lpstrTitle = _title; } else { OpenFileName.lpstrTitle = (open ? "Open a File" : "Save File As"); } // Default file extension. if ( argumentExists(6) ) { OpenFileName.lpstrDefExt = *_defExt != '\0' ? _defExt : NULL; } else { OpenFileName.lpstrDefExt = "txt"; } // Hook procedure to bring dialog to the foreground. OpenFileName.lpfnHook = OFNSetForegroundHookProc; // Default separator character, can be changed by the user to handle file // names with spaces. char sepChar = ' '; if ( argumentExists(8) && *_sep != '\0' ) { sepChar = *_sep; } // Okay, show the dialog. BOOL success; if ( open ) { OpenFileName.Flags |= OFN_FILEMUSTEXIST; if ( multiSelect ) { OpenFileName.Flags |= OFN_ALLOWMULTISELECT; } success = GetOpenFileName(&OpenFileName); if ( success && multiSelect ) { // If more than one name selected, names are separated with ASCII 0 // instead of spaces. char *p = pszFiles; while ( (*p != '\0') || (*(p+1) != '\0') ) { if ( *p == 0 ) { *p = sepChar; } p++; } } } else { OpenFileName.Flags |= OFN_OVERWRITEPROMPT; success = GetSaveFileName(&OpenFileName); } // Return 0 if the user cancelled, or on error. Otherwise, the return is in // the allocated file buffer. RexxObjectPtr result = TheZeroObj; if ( success ) { result = context->String(pszFiles); } LocalFree(pszFiles); safeLocalFree(filterBuf); if ( ! success ) { // Raise an exception if this was a Windows API failure. Prior to // 4.0.0, this was a generic 'routine failed' exception. We'll try to // give the user a little more information. DWORD rc = CommDlgExtendedError(); if ( rc != 0 ) { systemServiceExceptionCode(context->threadContext, API_FAILED_MSG, open ? "GetOpenFileName" : "GetSaveFileName", rc); } } 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; }