Esempio n. 1
0
/** 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;
}
Esempio n. 2
0
void systemServiceExceptionCode(RexxThreadContext *context, const char *msg, const char *arg1)
{
    systemServiceExceptionCode(context, msg, arg1, GetLastError());
}