native.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 13k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // Contains code that needs to be dual compiled, once for ansi and once for unicode
  2. #include "priv.h"
  3. #include "native.h"     // definitions of files in native.cpp
  4. #include "fstream.h"    // definition of CFileStream used by _CreateStreamOnFile
  5. #include <w95wraps.h>
  6. // create an IStream from a Win32 file name.
  7. // in:
  8. //      pszFile     file name to open
  9. //      grfMode     STGM_ flags
  10. //
  11. STDAPI _CreateStreamOnFile(LPCTSTR pszFile, DWORD grfMode, IStream **ppstm)
  12. {
  13.     HANDLE hFile;
  14.     *ppstm = NULL;
  15.     //
  16.     //  we only handle the below modes (they map to STGM_ flags),
  17.     //  don't let anything else through
  18.     //
  19.     if (grfMode &
  20.         ~(STGM_READ             |
  21.           STGM_WRITE            |
  22.           STGM_SHARE_DENY_NONE  |
  23.           STGM_SHARE_DENY_READ  |
  24.           STGM_SHARE_DENY_WRITE |
  25.           STGM_SHARE_EXCLUSIVE  |
  26.           STGM_READWRITE        |
  27.           STGM_CREATE         ))
  28.     {
  29.         DebugMsg(DM_ERROR, TEXT("CreateSreamOnFile: Invalid STGM_ mode"));
  30.         return E_INVALIDARG;
  31.     }
  32.     if ( grfMode & STGM_CREATE)
  33.     {
  34.         // Need to get the file attributes of the file first, so
  35.         // that CREATE_ALWAYS will succeed for HIDDEN and SYSTEM
  36.         // attributes.
  37.         DWORD dwAttrib = GetFileAttributes( pszFile );
  38.         if ((DWORD)-1 == dwAttrib )
  39.         {
  40.             // something went wrong, so set attributes to something
  41.             // normal before we try to create the file...
  42.             dwAttrib = 0;
  43.         }
  44.         // STGM_CREATE
  45.         hFile = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE,
  46.             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
  47.             dwAttrib, NULL);
  48.     }
  49.     else
  50.     {
  51.         DWORD dwDesiredAccess, dwShareMode, dwShareBits;
  52.         // not STGM_CREATE
  53.         if ( grfMode & STGM_WRITE )
  54.         {
  55.             dwDesiredAccess = GENERIC_WRITE;
  56.         }
  57.         else
  58.         {
  59.             dwDesiredAccess = GENERIC_READ;
  60.         }
  61.         if ( grfMode & STGM_READWRITE )
  62.         {
  63.             dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
  64.         }
  65.         dwShareBits = grfMode & (STGM_SHARE_EXCLUSIVE | 
  66.                                  STGM_SHARE_DENY_WRITE | 
  67.                                  STGM_SHARE_DENY_READ | 
  68.                                  STGM_SHARE_DENY_NONE);
  69.         switch( dwShareBits ) {
  70.             case STGM_SHARE_DENY_WRITE:
  71.                 dwShareMode = FILE_SHARE_READ;
  72.                 break;
  73.             case STGM_SHARE_DENY_READ:
  74.                 dwShareMode = FILE_SHARE_WRITE;
  75.                 break;
  76.             case STGM_SHARE_EXCLUSIVE:
  77.                 dwShareMode = 0;
  78.                 break;
  79.             default:
  80.                 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  81.                 break;
  82.         }
  83.         hFile = CreateFile(pszFile, dwDesiredAccess, dwShareMode, NULL,
  84.                                    OPEN_EXISTING, 0, NULL);
  85.     }
  86.     if (hFile == INVALID_HANDLE_VALUE)
  87.     {
  88.         DebugMsg(DM_TRACE, TEXT("CreateSreamOnFile: CreateFileW() failed %s"), pszFile);
  89.         return HRESULT_FROM_WIN32(GetLastError());
  90.     }
  91.     *ppstm = (IStream *)new CFileStream(hFile, grfMode);
  92.     if (*ppstm)
  93.     {
  94.         return S_OK;
  95.     }
  96.     else
  97.     {
  98.         CloseHandle(hFile);
  99.         return E_OUTOFMEMORY;
  100.     }
  101. }
  102. BOOL _PathAppend(LPCTSTR pszBase, LPCTSTR pszAppend, LPTSTR pszOut, DWORD cchOut)
  103. {
  104.     DWORD cchBase = lstrlen(pszBase);
  105.     //  +1 is one for the whack 
  106.     if (cchOut > cchBase + lstrlen(pszAppend) + 1)
  107.     {
  108.         StrCpy(pszOut, pszBase);
  109.         pszOut+=cchBase;
  110.         *pszOut++ = TEXT('\');
  111.         StrCpy(pszOut, pszAppend);
  112.         return TRUE;
  113.     }
  114.     return FALSE;
  115. }
  116. #define REGSTR_PATH_EXPLORER_FILEEXTS   TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts")
  117. LWSTDAPI AssocMakeFileExtsToApplication(ASSOCMAKEF flags, LPCTSTR pszExt, LPCTSTR pszApplication)
  118. {
  119.     HRESULT hr = E_INVALIDARG;
  120.     if (pszExt)
  121.     {
  122.         TCHAR szKey[MAX_PATH];
  123.         _PathAppend(REGSTR_PATH_EXPLORER_FILEEXTS, pszExt, szKey, SIZECHARS(szKey));
  124.         DWORD err;
  125.         if (!pszApplication)
  126.             err = SHDeleteValue(HKEY_CURRENT_USER, szKey, TEXT("Application"));
  127.         else
  128.             err = SHSetValue(HKEY_CURRENT_USER, szKey, TEXT("Application"),
  129.                 REG_SZ, pszApplication, CbFromCch(lstrlen(pszApplication) +1));
  130.         hr = HRESULT_FROM_WIN32(err);
  131.     }
  132.     return hr;
  133. }
  134. HRESULT _AllocValueString(HKEY hkey, LPCTSTR pszKey, LPCTSTR pszVal, LPTSTR *ppsz)
  135. {
  136.     DWORD cb, err;
  137.     err = SHGetValue(hkey, pszKey, pszVal, NULL, NULL, &cb);
  138.     ASSERT(ppsz);
  139.     *ppsz = NULL;
  140.     
  141.     if (NOERROR == err)
  142.     {
  143.         LPTSTR psz = (LPTSTR) LocalAlloc(LPTR, cb);
  144.         if (psz)
  145.         {
  146.             err = SHGetValue(hkey, pszKey, pszVal, NULL, (LPVOID)psz, &cb);
  147.             if (NOERROR == err)
  148.                 *ppsz = psz;
  149.             else
  150.                 LocalFree(psz);
  151.         }
  152.         else
  153.             err = ERROR_OUTOFMEMORY;
  154.     }
  155.     return HRESULT_FROM_WIN32(err);
  156. }
  157. // <Swipped from the NT5 version of Shell32>
  158. #define SZ_REGKEY_FILEASSOCIATION TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\FileAssociation")
  159. VOID WINAPI PrettifyFileDescription(LPTSTR pszDesc, LPCTSTR pszCutList)
  160. {
  161.     LPTSTR pszCutListReg;
  162.     
  163.     if (!pszDesc || !*pszDesc)
  164.         return;
  165.     // get the Cut list from registry
  166.     //  this is MULTI_SZ
  167.     if (S_OK == _AllocValueString(HKEY_LOCAL_MACHINE, SZ_REGKEY_FILEASSOCIATION, TEXT("CutList"), &pszCutListReg))
  168.     {
  169.         pszCutList = pszCutListReg;
  170.     }
  171.     if (pszCutList)
  172.     {
  173.         // cut strings in cut list from file description
  174.         for (LPCTSTR pszCut = pszCutList; *pszCut; pszCut = pszCut + lstrlen(pszCut) + 1)
  175.         {
  176.             LPTSTR pch = StrRStrI(pszDesc, NULL, pszCut);
  177.             // cut the exact substring from the end of file description
  178.             if (pch && !*(pch + lstrlen(pszCut)))
  179.             {
  180.                 *pch = '';
  181.                 // remove trailing spaces
  182.                 for (--pch; (pch >= pszDesc) && (TEXT(' ') == *pch); pch--)
  183.                     *pch = 0;
  184.                 break;
  185.             }
  186.         }
  187.         
  188.         if (pszCutListReg)
  189.             LocalFree(pszCutListReg);
  190.     }
  191. }
  192. /*
  193.     <Swipped from the NT5 version of Shell32>
  194.     GetFileDescription retrieves the friendly name from a file's verion rsource.
  195.     The first language we try will be the first item in the
  196.     "VarFileInfoTranslations" section;  if there's nothing there,
  197.     we try the one coded into the IDS_VN_FILEVERSIONKEY resource string.
  198.     If we can't even load that, we just use English (040904E4).  We
  199.     also try English with a null codepage (04090000) since many apps
  200.     were stamped according to an old spec which specified this as
  201.     the required language instead of 040904E4.
  202.     
  203.     If there is no FileDescription in version resource, return the file name.
  204.     Parameters:
  205.         LPCTSTR pszPath: full path of the file
  206.         LPTSTR pszDesc: pointer to the buffer to receive friendly name. If NULL, 
  207.                         *pcchDesc will be set to the length of friendly name in 
  208.                         characters, including ending NULL, on successful return.
  209.         UINT *pcchDesc: length of the buffer in characters. On successful return,
  210.                         it contains number of characters copied to the buffer,
  211.                         including ending NULL.
  212.     Return:
  213.         TRUE on success, and FALSE otherwise
  214. */
  215. BOOL WINAPI SHGetFileDescription(LPCTSTR pszPath, LPCTSTR pszVersionKeyIn, LPCTSTR pszCutListIn, LPTSTR pszDesc, UINT *pcchDesc)
  216. {
  217.     UINT cchValue = 0;
  218.     TCHAR szPath[MAX_PATH], *pszValue = NULL;
  219.     
  220.     DWORD dwHandle;                 /* version subsystem handle */
  221.     DWORD dwVersionSize;            /* size of the version data */
  222.     LPTSTR lpVersionBuffer = NULL;  /* pointer to version data */
  223.     TCHAR szVersionKey[60];         /* big enough for anything we need */
  224.     
  225.     struct _VERXLATE
  226.     {
  227.         WORD wLanguage;
  228.         WORD wCodePage;
  229.     } *lpXlate;                     /* ptr to translations data */
  230.     
  231.     ASSERT(pszPath && *pszPath && pcchDesc);
  232.     
  233.     if (!PathFileExists(pszPath))
  234.         return FALSE;
  235.     lstrcpyn(szPath, pszPath, ARRAYSIZE(szPath));
  236.         
  237.     dwVersionSize = GetFileVersionInfoSize(szPath, &dwHandle);
  238.     if (dwVersionSize == 0L)
  239.         goto Error;                 /* no version info */
  240.     lpVersionBuffer = (LPTSTR)LocalAlloc(LPTR, dwVersionSize);
  241.     if (lpVersionBuffer == NULL)
  242.         goto Error;
  243.     if (!GetFileVersionInfo(szPath, dwHandle, dwVersionSize, lpVersionBuffer))
  244.         goto Error;
  245.     // Try same language as the caller 
  246.     if (pszVersionKeyIn)
  247.     {
  248.         lstrcpyn(szVersionKey, pszVersionKeyIn, ARRAYSIZE(szVersionKey));
  249.         if (VerQueryValue(lpVersionBuffer, szVersionKey, (void **)&pszValue, &cchValue))
  250.         {
  251.             goto Exit;
  252.         }
  253.     }
  254.     // Try first language this supports
  255.     // Look for translations
  256.     if (VerQueryValue(lpVersionBuffer, TEXT("\VarFileInfo\Translation"),
  257.                       (void **)&lpXlate, &cchValue)
  258.         && cchValue)
  259.     {
  260.         wnsprintf(szVersionKey, ARRAYSIZE(szVersionKey), TEXT("\StringFileInfo\%04X%04X\FileDescription"),
  261.                  lpXlate[0].wLanguage, lpXlate[0].wCodePage);
  262.         if (VerQueryValue(lpVersionBuffer, szVersionKey, (void **)&pszValue, &cchValue))
  263.             goto Exit;
  264.     }
  265. #ifdef UNICODE
  266.     // try English, unicode code page
  267.     lstrcpy(szVersionKey, TEXT("\StringFileInfo\040904B0\FileDescription"));
  268.     if (VerQueryValue(lpVersionBuffer, szVersionKey, (void **)&pszValue, &cchValue))
  269.         goto Exit;
  270. #endif
  271.     // try English
  272.     lstrcpy(szVersionKey, TEXT("\StringFileInfo\040904E4\FileDescription"));
  273.     if (VerQueryValue(lpVersionBuffer, szVersionKey, (void **)&pszValue, &cchValue))
  274.         goto Exit;
  275.     // try English, null codepage
  276.     lstrcpy(szVersionKey, TEXT("\StringFileInfo\04090000\FileDescription"));
  277.     if (VerQueryValue(lpVersionBuffer, szVersionKey, (void **)&pszValue, &cchValue))
  278.         goto Exit;
  279. Error:  // Could not find FileVersion info in a reasonable format, return file name
  280.     PathRemoveExtension(szPath);
  281.     pszValue = PathFindFileName(szPath);
  282.     cchValue = lstrlen(pszValue);
  283.     
  284. Exit:   
  285.     PrettifyFileDescription(pszValue, pszCutListIn);
  286.     cchValue = lstrlen(pszValue) + 1;
  287.     
  288.     if (!pszDesc)   // only want to know the length of the friendly name
  289.         *pcchDesc = cchValue;
  290.     else
  291.     {
  292.         *pcchDesc = min(*pcchDesc, cchValue);
  293.         lstrcpyn(pszDesc, pszValue, *pcchDesc);
  294.     }
  295.     
  296.     if (lpVersionBuffer) 
  297.         LocalFree(lpVersionBuffer);
  298.         
  299.     return TRUE;
  300. }
  301. // Convert LPTSTR to LPSTR and return TRUE if the LPSTR can
  302. // be converted back to LPTSTR without unacceptible data loss
  303. //
  304. BOOL DoesStringRoundTrip(LPCTSTR pwszIn, LPSTR pszOut, UINT cchOut)
  305. {
  306. #ifdef UNICODE
  307.     // On NT5 we have to be more stringent since you can switch UI
  308.     // languages on the fly, thereby breaking this constant codepage
  309.     // assumption inherent in the downlevel implementations.
  310.     //
  311.     if (g_bRunningOnNT5OrHigher)
  312.     {
  313.         LPCTSTR pIn = pwszIn;
  314.         LPSTR pOut = pszOut;
  315.         UINT cch = cchOut;
  316.         
  317.         while (*pIn && cch)
  318.         {
  319.             if (*pIn > ((TCHAR)127))
  320.             {
  321. #ifdef DEBUG
  322.                 SHUnicodeToAnsiCP(CP_ACPNOVALIDATE, pwszIn, pszOut, cchOut);
  323. #else
  324.                 SHUnicodeToAnsi(pwszIn, pszOut, cchOut);
  325. #endif
  326.                 return FALSE;
  327.             }
  328.             *pOut++ = (char)*pIn++;
  329.             cch--;
  330.         }
  331.         // Null terminate the out buffer
  332.         if (cch)
  333.         {
  334.             *pOut = '';
  335.         }
  336.         else if (cchOut)
  337.         {
  338.             *(pOut-1) = '';
  339.         }
  340.         // Everything was low ascii, no dbcs worries and it will always round-trip
  341.         return TRUE;
  342.     }
  343.     else
  344.     // but we probably don't want to change downlevel shell behavior
  345.     // in this regard, so we keep that implementation:
  346.     //
  347.     {
  348.         BOOL fRet = FALSE;
  349.         WCHAR wszTemp[MAX_PATH];
  350.         LPWSTR pwszTemp = wszTemp;
  351.         UINT cchTemp = ARRAYSIZE(wszTemp);
  352.         // We better have enough room for the buffer.
  353.         if (ARRAYSIZE(wszTemp) < cchOut)
  354.         {
  355.             pwszTemp = (LPWSTR)LocalAlloc(LPTR, cchOut*sizeof(WCHAR));
  356.             cchTemp = cchOut;
  357.         }
  358.         if (pwszTemp)
  359.         {
  360. #ifdef DEBUG
  361.             SHUnicodeToAnsiCP(CP_ACPNOVALIDATE, pwszIn, pszOut, cchOut);
  362. #else
  363.             SHUnicodeToAnsi(pwszIn, pszOut, cchOut);
  364. #endif
  365.             SHAnsiToUnicode(pszOut, pwszTemp, cchTemp);
  366.             fRet = lstrcmp(pwszIn, pwszTemp) == 0;     // are they the same?
  367.             if (pwszTemp != wszTemp)
  368.             {
  369.                 LocalFree(pwszTemp);
  370.             }
  371.         }
  372.         return fRet;
  373.     }
  374.     
  375. #else
  376.     StrCpyN(pszOut, pwszIn, cchOut);
  377.     return TRUE;
  378. #endif
  379. }