UTILITY.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:28k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * UTILITY.C
  3.  *
  4.  * Utility routines for functions inside OLESTD.LIB
  5.  *
  6.  *  General:
  7.  *  ----------------------
  8.  *  HourGlassOn             Displays the hourglass
  9.  *  HourGlassOff            Hides the hourglass
  10.  *
  11.  *  Misc Tools:
  12.  *  ----------------------
  13.  *  Browse                  Displays the "File..." or "Browse..." dialog.
  14.  *  ReplaceCharWithNull     Used to form filter strings for Browse.
  15.  *  ErrorWithFile           Creates an error message with embedded filename
  16.  *  OpenFileError           Give error message for OpenFile error return
  17.  *  ChopText                Chop a file path to fit within a specified width
  18.  *  DoesFileExist           Checks if file is valid
  19.  *
  20.  *  Registration Database:
  21.  *  ----------------------
  22.  *  HIconFromClass          Extracts the first icon in a class's server path
  23.  *  FServerFromClass        Retrieves the server path for a class name (fast)
  24.  *  UClassFromDescription   Finds the classname given a description (slow)
  25.  *  UDescriptionFromClass   Retrieves the description for a class name (fast)
  26.  *  FGetVerb                Retrieves a specific verb for a class (fast)
  27.  *
  28.  *
  29.  * Copyright (c)1992-1996 Microsoft Corporation, All Right Reserved
  30.  */
  31. #define STRICT  1
  32. #include "olestd.h"
  33. #include <stdlib.h>
  34. #include <commdlg.h>
  35. #include <memory.h>
  36. #include <cderr.h>
  37. #include "common.h"
  38. #include "utility.h"
  39. #ifdef WIN32
  40. /* 1/23/94 - define LINK_COMMDLG to avoid LoadLibrary("commdlg.dll") */
  41. #define LINK_COMMDLG
  42. #endif
  43. OLEDBGDATA
  44. /*
  45.  * HourGlassOn
  46.  *
  47.  * Purpose:
  48.  *  Shows the hourglass cursor returning the last cursor in use.
  49.  *
  50.  * Parameters:
  51.  *  None
  52.  *
  53.  * Return Value:
  54.  *  HCURSOR         Cursor in use prior to showing the hourglass.
  55.  */
  56. HCURSOR WINAPI HourGlassOn(void)
  57.    {
  58.    HCURSOR     hCur;
  59.    hCur=SetCursor(LoadCursor(NULL, IDC_WAIT));
  60.    ShowCursor(TRUE);
  61.    return hCur;
  62.    }
  63. /*
  64.  * HourGlassOff
  65.  *
  66.  * Purpose:
  67.  *  Turns off the hourglass restoring it to a previous cursor.
  68.  *
  69.  * Parameters:
  70.  *  hCur            HCURSOR as returned from HourGlassOn
  71.  *
  72.  * Return Value:
  73.  *  None
  74.  */
  75. void WINAPI HourGlassOff(HCURSOR hCur)
  76.    {
  77.    ShowCursor(FALSE);
  78.    SetCursor(hCur);
  79.    return;
  80.    }
  81. /*
  82.  * Browse
  83.  *
  84.  * Purpose:
  85.  *  Displays the standard GetOpenFileName dialog with the title of
  86.  *  "Browse."  The types listed in this dialog are controlled through
  87.  *  iFilterString.  If it's zero, then the types are filled with "*.*"
  88.  *  Otherwise that string is loaded from resources and used.
  89.  *
  90.  * Parameters:
  91.  *  hWndOwner       HWND owning the dialog
  92.  *  lpszFile        LPSTR specifying the initial file and the buffer in
  93.  *                  which to return the selected file.  If there is no
  94.  *                  initial file the first character of this string should
  95.  *                  be NULL.
  96.  *  lpszInitialDir  LPSTR specifying the initial directory.  If none is to
  97.  *                  set (ie, the cwd should be used), then this parameter
  98.  *                  should be NULL.
  99.  *  cchFile         UINT length of pszFile
  100.  *  iFilterString   UINT index into the stringtable for the filter string.
  101.  *  dwOfnFlags      DWORD flags to OR with OFN_HIDEREADONLY
  102.  *
  103.  * Return Value:
  104.  *  BOOL            TRUE if the user selected a file and pressed OK.
  105.  *                  FALSE otherwise, such as on pressing Cancel.
  106.  */
  107. BOOL WINAPI Browse(HWND hWndOwner, LPSTR lpszFile, LPSTR lpszInitialDir, UINT cchFile, UINT iFilterString, DWORD dwOfnFlags)
  108.    {
  109.       UINT           cch;
  110.       char           szFilters[256];
  111.       OPENFILENAME   ofn;
  112.       BOOL           fStatus;
  113.       DWORD          dwError;
  114.       char            szDlgTitle[128];  // that should be big enough
  115. #if !defined( LINK_COMMDLG )
  116.       HINSTANCE hinstCommDlg = NULL;
  117.       typedef BOOL (WINAPI* LPFNGETOPENFILENAME) (OPENFILENAME FAR*);
  118.       LPFNGETOPENFILENAME lpfnGetOpenFileName;
  119.       typedef DWORD (WINAPI* LPFNCOMMDLGEXTENDEDERROR) (void);
  120.       LPFNCOMMDLGEXTENDEDERROR lpfnCommDlgExtendedError;
  121. #endif
  122.    if (NULL==lpszFile || 0==cchFile)
  123.       return FALSE;
  124.    /*
  125.     * REVIEW:  Exact contents of the filter combobox is TBD.  One idea
  126.     * is to take all the extensions in the RegDB and place them in here
  127.     * with the descriptive class name associate with them.  This has the
  128.     * extra step of finding all extensions of the same class handler and
  129.     * building one extension string for all of them.  Can get messy quick.
  130.     * UI demo has only *.* which we do for now.
  131.     */
  132.    if (0!=iFilterString)
  133.       cch=LoadString(ghInst, iFilterString, /*(LPSTR)*/szFilters, sizeof(szFilters));
  134.    else
  135.       {
  136.       szFilters[0]=0;
  137.       cch=1;
  138.       }
  139.    if (0==cch)
  140.       return FALSE;
  141.    ReplaceCharWithNull(szFilters, szFilters[cch-1]);
  142.    //Prior string must also be initialized, if there is one.
  143.    _fmemset((LPOPENFILENAME)&ofn, 0, sizeof(ofn));
  144.    ofn.lStructSize =sizeof(ofn);
  145.    ofn.hwndOwner   =hWndOwner;
  146.    ofn.lpstrFile   =lpszFile;
  147.    ofn.nMaxFile    =cchFile;
  148.    ofn.lpstrFilter =/*(LPSTR)*/szFilters;
  149.    ofn.nFilterIndex=1;
  150.    if (LoadString(ghInst, (UINT)IDS_BROWSE, /*(LPSTR)*/szDlgTitle, sizeof(szDlgTitle)))
  151.       ofn.lpstrTitle  =/*(LPSTR)*/szDlgTitle;
  152.    ofn.hInstance = ghInst;
  153.    ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPEN);
  154.    if (NULL != lpszInitialDir)
  155.      ofn.lpstrInitialDir = lpszInitialDir;
  156.    ofn.Flags= OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | (dwOfnFlags) ;
  157. #if !defined( LINK_COMMDLG )
  158.    // Load the COMMDLG.DLL library module
  159.    hinstCommDlg = LoadLibrary("COMMDLG.DLL");
  160.    if (hinstCommDlg <= HINSTANCE_ERROR)   /* load failed */
  161.       return FALSE;
  162.    // Retrieve the address of required functions
  163.    lpfnGetOpenFileName = (LPFNGETOPENFILENAME)
  164.          GetProcAddress(hinstCommDlg, "GetOpenFileName");
  165.    lpfnCommDlgExtendedError = (LPFNCOMMDLGEXTENDEDERROR)
  166.          GetProcAddress(hinstCommDlg, "CommDlgExtendedError");
  167.    if (lpfnGetOpenFileName == NULL || lpfnCommDlgExtendedError == NULL)
  168.       {
  169.       FreeLibrary(hinstCommDlg);
  170.       return FALSE;
  171.       }
  172.    //On success, copy the chosen filename to the static display
  173.    fStatus = (*lpfnGetOpenFileName) ((LPOPENFILENAME)&ofn);
  174.    dwError = (*lpfnCommDlgExtendedError)();
  175.    FreeLibrary(hinstCommDlg);
  176.    return fStatus;
  177. #else
  178.    //On success, copy the chosen filename to the static display
  179.    fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);
  180.    dwError = CommDlgExtendedError();
  181.    return fStatus;
  182. #endif
  183.    }
  184. /*
  185.  * ReplaceCharWithNull
  186.  *
  187.  * Purpose:
  188.  *  Walks a null-terminated string and replaces a given character
  189.  *  with a zero.  Used to turn a single string for file open/save
  190.  *  filters into the appropriate filter string as required by the
  191.  *  common dialog API.
  192.  *
  193.  * Parameters:
  194.  *  psz             LPSTR to the string to process.
  195.  *  ch              int character to replace.
  196.  *
  197.  * Return Value:
  198.  *  int             Number of characters replaced.  -1 if psz is NULL.
  199.  */
  200. int WINAPI ReplaceCharWithNull(LPSTR psz, int ch)
  201.    {
  202.    int             cChanged=-1;
  203.    if (NULL!=psz)
  204.       {
  205.       while (0!=*psz)
  206.          {
  207.          if (ch==*psz)
  208.             {
  209.             *psz=0;
  210.             cChanged++;
  211.             }
  212.          psz++;
  213.          }
  214.       }
  215.    return cChanged;
  216.    }
  217. /*
  218.  * ErrorWithFile
  219.  *
  220.  * Purpose:
  221.  *  Displays a message box built from a stringtable string containing
  222.  *  one %s as a placeholder for a filename and from a string of the
  223.  *  filename to place there.
  224.  *
  225.  * Parameters:
  226.  *  hWnd            HWND owning the message box.  The caption of this
  227.  *                  window is the caption of the message box.
  228.  *  hInst           HINSTANCE from which to draw the idsErr string.
  229.  *  idsErr          UINT identifier of a stringtable string containing
  230.  *                  the error message with a %s.
  231.  *  lpszFile        LPSTR to the filename to include in the message.
  232.  *  uFlags          UINT flags to pass to MessageBox, like MB_OK.
  233.  *
  234.  * Return Value:
  235.  *  int             Return value from MessageBox.
  236.  */
  237. int WINAPI ErrorWithFile(HWND hWnd, HINSTANCE hInst, UINT idsErr
  238.               , LPSTR pszFile, UINT uFlags)
  239.    {
  240.    int             iRet=0;
  241.    HANDLE          hMem;
  242.    const UINT      cb=(2*OLEUI_CCHPATHMAX);
  243.    LPSTR           psz1, psz2, psz3;
  244.    if (NULL==hInst || NULL==pszFile)
  245.       return iRet;
  246.    //Allocate three 2*OLEUI_CCHPATHMAX byte work buffers
  247.    hMem=GlobalAlloc(GHND, (DWORD)(3*cb));
  248.    if (NULL==hMem)
  249.       return iRet;
  250.    psz1=GlobalLock(hMem);
  251.    psz2=psz1+cb;
  252.    psz3=psz2+cb;
  253.    if (0!=LoadString(hInst, idsErr, psz1, cb))
  254.       {
  255.       wsprintf(psz2, psz1, pszFile);
  256.       //Steal the caption of the dialog
  257.       GetWindowText(hWnd, psz3, cb);
  258.       iRet=MessageBox(hWnd, psz2, psz3, uFlags);
  259.       }
  260.    GlobalUnlock(hMem);
  261.    GlobalFree(hMem);
  262.    return iRet;
  263.    }
  264. /*
  265.  * HIconFromClass
  266.  *
  267.  * Purpose:
  268.  *  Given an object class name, finds an associated executable in the
  269.  *  registration database and extracts the first icon from that
  270.  *  executable.  If none is available or the class has no associated
  271.  *  executable, this function returns NULL.
  272.  *
  273.  * Parameters:
  274.  *  pszClass        LPSTR giving the object class to look up.
  275.  *
  276.  * Return Value:
  277.  *  HICON           Handle to the extracted icon if there is a module
  278.  *                  associated to pszClass.  NULL on failure to either
  279.  *                  find the executable or extract and icon.
  280.  */
  281. HICON WINAPI HIconFromClass(LPSTR pszClass)
  282.    {
  283.    HICON           hIcon;
  284.    char            szEXE[OLEUI_CCHPATHMAX];
  285.    UINT            Index;
  286.    CLSID           clsid;
  287.    OLECHAR         szUniStr[256];
  288.    if (NULL==pszClass)
  289.       return NULL;
  290.    A2W (pszClass, szUniStr, 256);
  291.    CLSIDFromString(szUniStr, &clsid);
  292.    if (!FIconFileFromClass((REFCLSID)&clsid, szEXE, sizeof(szEXE), &Index))
  293.       return NULL;
  294.    hIcon=ExtractIcon(ghInst, szEXE, Index);
  295.    if ((HICON)32 > hIcon)
  296.       hIcon=NULL;
  297.    return hIcon;
  298.    }
  299. /*
  300.  * FServerFromClass
  301.  *
  302.  * Purpose:
  303.  *  Looks up the classname in the registration database and retrieves
  304.  *  the name under CLSID[Local|InProc]Server.
  305.  *
  306.  * Parameters:
  307.  *  pszClass        LPSTR to the classname to look up.
  308.  *  pszEXE          LPSTR at which to store the server name
  309.  *  cch             UINT size of pszEXE
  310.  *
  311.  * Return Value:
  312.  *  BOOL            TRUE if one or more characters were loaded into pszEXE.
  313.  *                  FALSE otherwise.
  314.  */
  315. BOOL WINAPI FServerFromClass(LPSTR pszClass, LPSTR pszEXE, UINT cch)
  316. {
  317.    DWORD       dw;
  318.    LONG        lRet;
  319.    HKEY        hKey;
  320.    if (NULL==pszClass || NULL==pszEXE || 0==cch)
  321.       return FALSE;
  322.    /*
  323.     * We have to go walking in the registration database under the
  324.     * classname, so we first open the classname key and then check
  325.     * under "\LocalServer" to get the .EXE.
  326.     */
  327.    //Open up the class key
  328.    lRet=RegOpenKey(HKEY_CLASSES_ROOT, pszClass, &hKey);
  329.    if ((LONG)ERROR_SUCCESS!=lRet)
  330.       return FALSE;
  331.    //Get the executable path.
  332.    dw=(DWORD)cch;
  333. #ifdef WIN32
  334.    lRet=RegQueryValue(hKey, "LocalServer32", pszEXE, &dw);
  335. #else
  336.    lRet=RegQueryValue(hKey, "LocalServer", pszEXE, &dw);
  337. #endif
  338.    if ((LONG)ERROR_SUCCESS!=lRet)
  339.         {
  340.         //Try InprocServer
  341. #ifdef WIN32
  342.         lRet=RegQueryValue(hKey, "InProcServer32", pszEXE, &dw);
  343. #else
  344.         lRet=RegQueryValue(hKey, "InProcServer32", pszEXE, &dw);
  345. #endif
  346.         }
  347.    RegCloseKey(hKey);
  348.    return ((ERROR_SUCCESS == lRet) && (dw > 0));
  349. }
  350. /*
  351.  * UClassFromDescription
  352.  *
  353.  * Purpose:
  354.  *  Looks up the actual OLE class name in the registration database
  355.  *  for the given descriptive name chosen from a listbox.
  356.  *
  357.  * Parameters:
  358.  *  psz             LPSTR to the descriptive name.
  359.  *  pszClass        LPSTR in which to store the class name.
  360.  *  cb              UINT maximum length of pszClass.
  361.  *
  362.  * Return Value:
  363.  *  UINT            Number of characters copied to pszClass.  0 on failure.
  364.  */
  365. UINT WINAPI UClassFromDescription(LPSTR psz, LPSTR pszClass, UINT cb)
  366.    {
  367.    DWORD           dw;
  368.    HKEY            hKey;
  369.    char            szClass[OLEUI_CCHKEYMAX];
  370.    LONG            lRet;
  371.    UINT            i;
  372.    //Open up the root key.
  373.    lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  374.    if ((LONG)ERROR_SUCCESS!=lRet)
  375.       return 0;
  376.    i=0;
  377.    lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX);
  378.    //Walk the available keys
  379.    while ((LONG)ERROR_SUCCESS==lRet)
  380.       {
  381.       dw=(DWORD)cb;
  382.       lRet=RegQueryValue(hKey, szClass, pszClass, &dw);
  383.       //Check if the description matches the one just enumerated
  384.       if ((LONG)ERROR_SUCCESS==lRet)
  385.          {
  386.          if (!lstrcmp(pszClass, psz))
  387.             break;
  388.          }
  389.       //Continue with the next key.
  390.       lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX);
  391.       }
  392.    //If we found it, copy to the return buffer
  393.    if ((LONG)ERROR_SUCCESS==lRet)
  394.       lstrcpy(pszClass, szClass);
  395.    else
  396.       dw=0L;
  397.    RegCloseKey(hKey);
  398.    return (UINT)dw;
  399.    }
  400. /*
  401.  * UDescriptionFromClass
  402.  *
  403.  * Purpose:
  404.  *  Looks up the actual OLE descriptive name name in the registration
  405.  *  database for the given class name.
  406.  *
  407.  * Parameters:
  408.  *  pszClass        LPSTR to the class name.
  409.  *  psz             LPSTR in which to store the descriptive name.
  410.  *  cb              UINT maximum length of psz.
  411.  *
  412.  * Return Value:
  413.  *  UINT            Number of characters copied to pszClass.  0 on failure.
  414.  */
  415. UINT WINAPI UDescriptionFromClass(LPSTR pszClass, LPSTR psz, UINT cb)
  416.    {
  417.    DWORD           dw;
  418.    HKEY            hKey;
  419.    LONG            lRet;
  420.    if (NULL==pszClass || NULL==psz)
  421.       return 0;
  422.    //Open up the root key.
  423.    lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  424.    if ((LONG)ERROR_SUCCESS!=lRet)
  425.       return 0;
  426.    //Get the descriptive name using the class name.
  427.    dw=(DWORD)cb;
  428.    lRet=RegQueryValue(hKey, pszClass, psz, &dw);
  429.    RegCloseKey(hKey);
  430.    psz+=lstrlen(psz)+1;
  431.    *psz=0;
  432.    if ((LONG)ERROR_SUCCESS!=lRet)
  433.       return 0;
  434.    return (UINT)dw;
  435.    }
  436. // returns width of line of text. this is a support routine for ChopText
  437. static LONG GetTextWSize(HDC hDC, LPSTR lpsz)
  438. {
  439.    SIZE size;
  440.    if (GetTextExtentPoint(hDC, lpsz, lstrlen(lpsz), (LPSIZE)&size))
  441.       return size.cx;
  442.    else {
  443.       return 0;
  444.    }
  445. }
  446. /*
  447.  * ChopText
  448.  *
  449.  * Purpose:
  450.  *  Parse a string (pathname) and convert it to be within a specified
  451.  *  length by chopping the least significant part
  452.  *
  453.  * Parameters:
  454.  *  hWnd            window handle in which the string resides
  455.  *  nWidth          max width of string in pixels
  456.  *                  use width of hWnd if zero
  457.  *  lpch            pointer to beginning of the string
  458.  *
  459.  * Return Value:
  460.  *  pointer to the modified string
  461.  */
  462. LPSTR WINAPI ChopText(HWND hWnd, int nWidth, LPSTR lpch)
  463. {
  464. #define PREFIX_SIZE    7 + 1
  465. #define PREFIX_FORMAT "%c%c%c...\"
  466.    char    szPrefix[PREFIX_SIZE];
  467.    BOOL    fDone = FALSE;
  468.    int     i;
  469.    RECT    rc;
  470.    HDC     hdc;
  471.    HFONT   hfont;
  472.    HFONT   hfontOld = NULL;
  473.    if (!hWnd || !lpch)
  474.       return NULL;
  475.    /* Get length of static field. */
  476.    if (!nWidth) {
  477.       GetClientRect(hWnd, (LPRECT)&rc);
  478.       nWidth = rc.right - rc.left;
  479.    }
  480.    /* Set up DC appropriately for the static control */
  481.    hdc = GetDC(hWnd);
  482.    hfont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
  483.    if (NULL != hfont)   // WM_GETFONT returns NULL if window uses system font
  484.       hfontOld = SelectObject(hdc, hfont);
  485.    /* check horizontal extent of string */
  486.    if (GetTextWSize(hdc, lpch) > nWidth) {
  487.       /* string is too long to fit in static control; chop it */
  488.       /* set up new prefix & determine remaining space in control */
  489.       wsprintf(/*(LPSTR)*/ szPrefix, PREFIX_FORMAT, lpch[0], lpch[1], lpch[2]);
  490.       nWidth -= (int)GetTextWSize(hdc, /*(LPSTR)*/ szPrefix);
  491.       /*
  492.       ** advance a directory at a time until the remainder of the
  493.       ** string fits into the static control after the "x:..." prefix
  494.       */
  495.       while (!fDone) {
  496. #ifdef DBCS
  497.          while (*lpch && (*lpch != '\'))
  498.             lpch = AnsiNext(lpch);
  499.          if (*lpch)
  500.             lpch = AnsiNext(lpch);
  501. #else
  502.          while (*lpch && (*lpch++ != '\'));
  503. #endif
  504.          if (!*lpch || GetTextWSize(hdc, lpch) <= nWidth) {
  505.             if (!*lpch)
  506.                /*
  507.                ** Nothing could fit after the prefix; remove the
  508.                ** final "" from the prefix
  509.                */
  510.                szPrefix[lstrlen(/*(LPSTR)*/ szPrefix) - 1] = 0;
  511.                /* rest or string fits -- stick prefix on front */
  512.                for (i = lstrlen(/*(LPSTR)*/ szPrefix) - 1; i >= 0; --i)
  513.                   *--lpch = szPrefix[i];
  514.                fDone = TRUE;
  515.          }
  516.       }
  517.    }
  518.    if (NULL != hfont)
  519.      SelectObject(hdc, hfontOld);
  520.    ReleaseDC(hWnd, hdc);
  521.    return(lpch);
  522. #undef PREFIX_SIZE
  523. #undef PREFIX_FORMAT
  524. }
  525. /*
  526.  * OpenFileError
  527.  *
  528.  * Purpose:
  529.  *  display message for error returned from OpenFile
  530.  *
  531.  * Parameters:
  532.  *  hDlg            HWND of the dialog.
  533.  *  nErrCode        UINT error code returned in OFSTRUCT passed to OpenFile
  534.  *  lpszFile        LPSTR file name passed to OpenFile
  535.  *
  536.  * Return Value:
  537.  *  None
  538.  */
  539. void WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPSTR lpszFile)
  540. {
  541.    switch (nErrCode) {
  542.       case 0x0005:    // Access denied
  543.          ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILEACCESS, lpszFile, MB_OK);
  544.          break;
  545.       case 0x0020:    // Sharing violation
  546.          ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILESHARE, lpszFile, MB_OK);
  547.          break;
  548.       case 0x0002:    // File not found
  549.       case 0x0003:    // Path not found
  550.          ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIINVALIDFILE, lpszFile, MB_OK);
  551.          break;
  552.       default:
  553.          ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILEOPENFAIL, lpszFile, MB_OK);
  554.          break;
  555.    }
  556. }
  557. #define chSpace        ' '
  558. #define chPeriod       '.'
  559. #define PARSE_EMPTYSTRING   -1
  560. #define PARSE_INVALIDDRIVE  -2
  561. #define PARSE_INVALIDPERIOD -3
  562. #define PARSE_INVALIDDIRCHAR    -4
  563. #define PARSE_INVALIDCHAR   -5
  564. #define PARSE_WILDCARDINDIR -6
  565. #define PARSE_INVALIDNETPATH    -7
  566. #define PARSE_INVALIDSPACE  -8
  567. #define PARSE_EXTENTIONTOOLONG  -9
  568. #define PARSE_DIRECTORYNAME -10
  569. #define PARSE_FILETOOLONG   -11
  570. /*---------------------------------------------------------------------------
  571.  * ParseFile
  572.  * Purpose:  Determine if the filename is a legal DOS name
  573.  * Input:    Long pointer to a SINGLE file name
  574.  *           Circumstance checked:
  575.  *           1) Valid as directory name, but not as file name
  576.  *           2) Empty String
  577.  *           3) Illegal Drive label
  578.  *           4) Period in invalid location (in extention, 1st in file name)
  579.  *           5) Missing directory character
  580.  *           6) Illegal character
  581.  *           7) Wildcard in directory name
  582.  *           8) Double slash beyond 1st 2 characters
  583.  *           9) Space character in the middle of the name (trailing spaces OK)
  584.  *          10) Filename greater than 8 characters
  585.  *          11) Extention greater than 3 characters
  586.  * Notes:
  587.  *   Filename length is NOT checked.
  588.  *   Valid filenames will have leading spaces, trailing spaces and
  589.  *     terminating period stripped in place.
  590.  *
  591.  * Returns:  If valid, LOWORD is byte offset to filename
  592.  *                     HIWORD is byte offset to extention
  593.  *                            if string ends with period, 0
  594.  *                            if no extention is given, string length
  595.  *           If invalid, LOWORD is error code suggesting problem (< 0)
  596.  *                       HIWORD is approximate offset where problem found
  597.  *                       Note that this may be beyond the offending character
  598.  *--------------------------------------------------------------------------*/
  599. static long ParseFile(LPSTR lpstrFileName)
  600. {
  601.   short nFile, nExt, nFileOffset, nExtOffset;
  602.   BOOL bExt;
  603.   BOOL bWildcard;
  604.   short nNetwork = 0;
  605.   BOOL  bUNCPath = FALSE;
  606.   LPSTR lpstr = lpstrFileName;
  607. /* Strip off initial white space.  Note that TAB is not checked */
  608. /* because it cannot be received out of a standard edit control */
  609. /* 30 January 1991  clarkc                                      */
  610.   while (*lpstr == chSpace)
  611.      lpstr++;
  612.   if (!*lpstr)
  613.    {
  614.      nFileOffset = PARSE_EMPTYSTRING;
  615.      goto FAILURE;
  616.    }
  617.   if (lpstr != lpstrFileName)
  618.    {
  619.      lstrcpy(lpstrFileName, lpstr);
  620.      lpstr = lpstrFileName;
  621.    }
  622.   if (*AnsiNext(lpstr) == ':')
  623.    {
  624.      char cDrive = (*lpstr | (BYTE) 0x20);  /* make lowercase */
  625. /* This does not test if the drive exists, only if it's legal */
  626.      if ((cDrive < 'a') || (cDrive > 'z'))
  627.       {
  628.         nFileOffset = PARSE_INVALIDDRIVE;
  629.         goto FAILURE;
  630.       }
  631.      lpstr = AnsiNext(AnsiNext(lpstr));
  632.    }
  633.   if ((*lpstr == '\') || (*lpstr == '/'))
  634.    {
  635.      if (*++lpstr == chPeriod)               /* cannot have c:. */
  636.       {
  637.         if ((*++lpstr != '\') && (*lpstr != '/'))   /* unless it's stupid */
  638.          {
  639.            if (!*lpstr)        /* it's the root directory */
  640.               goto MustBeDir;
  641.            nFileOffset = PARSE_INVALIDPERIOD;
  642.            goto FAILURE;
  643.          }
  644.         else
  645.            ++lpstr;   /* it's saying top directory (again), thus allowed */
  646.       }
  647.      else if ((*lpstr == '\') && (*(lpstr-1) == '\'))
  648.       {
  649. /* It seems that for a full network path, whether a drive is declared or
  650.  * not is insignificant, though if a drive is given, it must be valid
  651.  * (hence the code above should remain there).
  652.  * 13 February 1991           clarkc
  653.  */
  654.         ++lpstr;            /* ...since it's the first slash, 2 are allowed */
  655.         nNetwork = -1;      /* Must receive server and share to be real     */
  656.         bUNCPath = TRUE;    /* No wildcards allowed if UNC name             */
  657.       }
  658.      else if (*lpstr == '/')
  659.       {
  660.         nFileOffset = PARSE_INVALIDDIRCHAR;
  661.         goto FAILURE;
  662.       }
  663.    }
  664.   else if (*lpstr == chPeriod)
  665.    {
  666.      if (*++lpstr == chPeriod)  /* Is this up one directory? */
  667.         ++lpstr;
  668.      if (!*lpstr)
  669.         goto MustBeDir;
  670.      if ((*lpstr != '\') && (*lpstr != '/'))
  671.       {
  672.         nFileOffset = PARSE_INVALIDPERIOD;
  673.         goto FAILURE;
  674.       }
  675.      else
  676.         ++lpstr;   /* it's saying directory, thus allowed */
  677.    }
  678.   if (!*lpstr)
  679.    {
  680.      goto MustBeDir;
  681.    }
  682. /* Should point to first char in 8.3 filename by now */
  683.   nFileOffset = nExtOffset = nFile = nExt = 0;
  684.   bWildcard = bExt = FALSE;
  685.   while (*lpstr)
  686.    {
  687. /*
  688.  *  The next comparison MUST be unsigned to allow for extended characters!
  689.  *  21 Feb 1991   clarkc
  690.  */
  691.      if (*lpstr < chSpace)
  692.       {
  693.         nFileOffset = PARSE_INVALIDCHAR;
  694.         goto FAILURE;
  695.       }
  696.      switch (*lpstr)
  697.       {
  698.         case '"':             /* All invalid */
  699.         case '+':
  700.         case ',':
  701.         case ':':
  702.         case ';':
  703.         case '<':
  704.         case '=':
  705.         case '>':
  706.         case '[':
  707.         case ']':
  708.         case '|':
  709.          {
  710.            nFileOffset = PARSE_INVALIDCHAR;
  711.            goto FAILURE;
  712.          }
  713.         case '\':      /* Subdirectory indicators */
  714.         case '/':
  715.          nNetwork++;
  716.          if (bWildcard)
  717.            {
  718.             nFileOffset = PARSE_WILDCARDINDIR;
  719.             goto FAILURE;
  720.            }
  721.          else if (nFile == 0)        /* can't have 2 in a row */
  722.            {
  723.             nFileOffset = PARSE_INVALIDDIRCHAR;
  724.             goto FAILURE;
  725.            }
  726.          else
  727.            {                         /* reset flags */
  728.             ++lpstr;
  729.             if (!nNetwork && !*lpstr)
  730.               {
  731.                nFileOffset = PARSE_INVALIDNETPATH;
  732.                goto FAILURE;
  733.               }
  734.             nFile = nExt = 0;
  735.             bExt = FALSE;
  736.            }
  737.          break;
  738.         case chSpace:
  739.          {
  740.            LPSTR lpSpace = lpstr;
  741.            *lpSpace = '';
  742.            while (*++lpSpace)
  743.             {
  744.               if (*lpSpace != chSpace)
  745.                {
  746.                  *lpstr = chSpace;        /* Reset string, abandon ship */
  747.                  nFileOffset = PARSE_INVALIDSPACE;
  748.                  goto FAILURE;
  749.                }
  750.             }
  751.          }
  752.          break;
  753.         case chPeriod:
  754.          if (nFile == 0)
  755.            {
  756.             if (*++lpstr == chPeriod)
  757.                ++lpstr;
  758.             if (!*lpstr)
  759.                goto MustBeDir;
  760.             if ((*lpstr != '\') && (*lpstr != '/'))
  761.               {
  762.                nFileOffset = PARSE_INVALIDPERIOD;
  763.                goto FAILURE;
  764.               }
  765.             ++lpstr;              /* Flags are already set */
  766.            }
  767.          else if (bExt)
  768.            {
  769.             nFileOffset = PARSE_INVALIDPERIOD;  /* can't have one in ext */
  770.             goto FAILURE;
  771.            }
  772.          else
  773.            {
  774.             nExtOffset = 0;
  775.             ++lpstr;
  776.             bExt = TRUE;
  777.            }
  778.          break;
  779.         case '*':
  780.         case '?':
  781.          if (bUNCPath)
  782.            {
  783.             nFileOffset = PARSE_INVALIDNETPATH;
  784.             goto FAILURE;
  785.            }
  786.          bWildcard = TRUE;
  787. /* Fall through to normal character processing */
  788.         default:
  789.          if (bExt)
  790.            {
  791.             if (++nExt == 1)
  792.                nExtOffset = lpstr - lpstrFileName;
  793.             else if (nExt > 3)
  794.               {
  795.                nFileOffset = PARSE_EXTENTIONTOOLONG;
  796.                goto FAILURE;
  797.               }
  798.             if ((nNetwork == -1) && (nFile + nExt > 11))
  799.               {
  800.                nFileOffset = PARSE_INVALIDNETPATH;
  801.                goto FAILURE;
  802.               }
  803.            }
  804.          else if (++nFile == 1)
  805.             nFileOffset = lpstr - lpstrFileName;
  806.          else if (nFile > 8)
  807.            {
  808.             /* If it's a server name, it can have 11 characters */
  809.             if (nNetwork != -1)
  810.               {
  811.                nFileOffset = PARSE_FILETOOLONG;
  812.                goto FAILURE;
  813.               }
  814.             else if (nFile > 11)
  815.               {
  816.                nFileOffset = PARSE_INVALIDNETPATH;
  817.                goto FAILURE;
  818.               }
  819.            }
  820.          lpstr = AnsiNext(lpstr);
  821.          break;
  822.       }
  823.    }
  824. /* Did we start with a double backslash but not have any more slashes? */
  825.   if (nNetwork == -1)
  826.    {
  827.      nFileOffset = PARSE_INVALIDNETPATH;
  828.      goto FAILURE;
  829.    }
  830.   if (!nFile)
  831.    {
  832. MustBeDir:
  833.      nFileOffset = PARSE_DIRECTORYNAME;
  834.      goto FAILURE;
  835.    }
  836.   if ((*(lpstr - 1) == chPeriod) &&          /* if true, no extention wanted */
  837.            (*AnsiNext(lpstr-2) == chPeriod))
  838.      *(lpstr - 1) = '';               /* Remove terminating period   */
  839.   else if (!nExt)
  840. FAILURE:
  841.      nExtOffset = lpstr - lpstrFileName;
  842.   return(MAKELONG(nFileOffset, nExtOffset));
  843. }
  844. /*
  845.  * DoesFileExist
  846.  *
  847.  * Purpose:
  848.  *  Determines if a file path exists
  849.  *
  850.  * Parameters:
  851.  *  lpszFile        LPSTR - file name
  852.  *  lpOpenBuf       OFSTRUCT FAR* - points to the OFSTRUCT structure that
  853.  *                      will receive information about the file when the
  854.  *                      file is first opened. this field is filled by the
  855.  *                      Windows OpenFile API.
  856.  *
  857.  * Return Value:
  858.  *  HFILE   HFILE_ERROR - file does NOT exist
  859.  *          file handle (as returned from OpenFile) - file exists
  860.  */
  861. HFILE WINAPI DoesFileExist(LPSTR lpszFile, OFSTRUCT FAR* lpOpenBuf)
  862. {
  863.    long        nRet;
  864.    int         i;
  865.    static char *arrIllegalNames[] = {
  866.       "LPT1",
  867.       "LPT2",
  868.       "LPT3",
  869.       "COM1",
  870.       "COM2",
  871.       "COM3",
  872.       "COM4",
  873.       "CON",
  874.       "AUX",
  875.       "PRN"
  876.    };
  877.    // Check if file name is syntactically correct.
  878.    //   (OpenFile sometimes crashes if path is not syntactically correct)
  879.    nRet = ParseFile(lpszFile);
  880.    if (LOWORD(nRet) < 0)
  881.       goto error;
  882.    // Check is the name is an illegal name (eg. the name of a device)
  883.    for (i=0; i < (sizeof(arrIllegalNames)/sizeof(arrIllegalNames[0])); i++) {
  884.       if (lstrcmpi(lpszFile, arrIllegalNames[i])==0)
  885.          goto error; // illegal name FOUND
  886.    }
  887.    return OpenFile(lpszFile, lpOpenBuf, OF_EXIST);
  888. error:
  889.    _fmemset(lpOpenBuf, 0, sizeof(OFSTRUCT));
  890.    lpOpenBuf->nErrCode = 0x0002;   // File not found
  891.    return HFILE_ERROR;
  892. }