Browse Source

LocalAppDataLow

David Rose 16 years ago
parent
commit
fada2d5933

+ 121 - 101
direct/src/plugin/find_root_dir.cxx

@@ -25,6 +25,34 @@
 #include <sys/stat.h>
 #endif
 
+// From KnownFolders.h (part of Vista SDK):
+#define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+   const GUID name = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
+DEFINE_KNOWN_FOLDER(FOLDERID_LocalAppData, 0xF1B32785, 0x6FBA, 0x4FCF, 0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91);
+DEFINE_KNOWN_FOLDER(FOLDERID_LocalAppDataLow, 0xA520A1A4, 0x1780, 0x4FF6, 0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16);
+DEFINE_KNOWN_FOLDER(FOLDERID_InternetCache, 0x352481E8, 0x33BE, 0x4251, 0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D); 
+
+
+#ifdef _WIN32
+////////////////////////////////////////////////////////////////////
+//     Function: check_root_dir
+//  Description: Tests the proposed root dir string for validity.
+//               Returns true if Panda3D can be successfully created
+//               within the dir, false otherwise.
+////////////////////////////////////////////////////////////////////
+static bool
+check_root_dir(const string &root) {
+  // Attempt to make it first, if possible.
+  CreateDirectory(root.c_str(), NULL);
+  
+  bool isdir = false;
+  DWORD results = GetFileAttributes(root.c_str());
+  if (results != -1) {
+    isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  }
+  return isdir;
+}
+#endif // _WIN32
 
 #ifdef _WIN32
 ////////////////////////////////////////////////////////////////////
@@ -38,30 +66,11 @@ get_csidl_dir(int csidl) {
   static const int buffer_size = MAX_PATH;
   char buffer[buffer_size];
   if (SHGetSpecialFolderPath(NULL, buffer, csidl, true)) {
-    bool isdir = false;
-    DWORD results = GetFileAttributes(buffer);
-    if (results != -1) {
-      isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
-    }
-
-    if (isdir) {
-      // The user prefix exists; do we have a Panda3D child?
-      string root = buffer;
-      root += string("/Panda3D");
-
-      // Attempt to make it first, if possible.
-      CreateDirectory(root.c_str(), NULL);
-
-      isdir = false;
-      results = GetFileAttributes(root.c_str());
-      if (results != -1) {
-        isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
-      }
-
-      if (isdir) {
-        // The directory exists!
-        return root;
-      }
+    string root = buffer;
+    root += string("/Panda3D");
+    
+    if (check_root_dir(root)) {
+      return root;
     }
   }
 
@@ -96,6 +105,7 @@ wstr_to_string(string &result, const LPWSTR wstr) {
 }
 #endif  // _WIN32
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: find_root_dir
 //  Description: Returns the path to the installable Panda3D directory
@@ -105,13 +115,14 @@ string
 find_root_dir(ostream &logfile) {
 #ifdef _WIN32
   // First, use IEIsProtectedModeProcess() to determine if we are
-  // running in IE's "protected mode".
+  // running in IE's "protected mode" under Vista.
 
+  string root;
   bool is_protected = false;
-  HMODULE module = LoadLibrary("ieframe.dll");
-  if (module != NULL) {
+  HMODULE ieframe = LoadLibrary("ieframe.dll");
+  if (ieframe != NULL) {
     typedef HRESULT STDAPICALLTYPE IEIsProtectedModeProcess(BOOL *pbResult);
-    IEIsProtectedModeProcess *func = (IEIsProtectedModeProcess *)GetProcAddress(module, "IEIsProtectedModeProcess");
+    IEIsProtectedModeProcess *func = (IEIsProtectedModeProcess *)GetProcAddress(ieframe, "IEIsProtectedModeProcess");
     if (func != NULL) {
       BOOL result = false;
       HRESULT hr = (*func)(&result);
@@ -123,99 +134,108 @@ find_root_dir(ostream &logfile) {
       // E_NOTIMPL, which means we're not running under Vista.  In
       // this case we can assume we're not running in protected mode.
     }
-  }    
-
-  int csidl = CSIDL_APPDATA;
-  // e.g., c:/Documents and Settings/<username>/Application Data/Panda3D
-
-  if (is_protected) {
-    // In IE's "protected mode", we have to use the common directory,
-    // which has already been created for us with low-level
-    // permissions.
 
-    csidl = CSIDL_COMMON_APPDATA;
-    // e.g., c:/Documents and Settings/All Users/Application Data/Panda3D
-  }
-  string root = get_csidl_dir(csidl);
-  if (!root.empty()) {
-    if (module != NULL) {
-      FreeLibrary(module);
-    }
-    return root;
-  }
-
-  // All right, couldn't get a writable pointer to our APPDATA folder.
-  // We're in fallback mode now.  Start by asking for a "writeable
-  // path" to a temporary folder.
-  if (module != NULL) {
-    typedef HRESULT STDAPICALLTYPE IEGetWriteableFolderPath(REFGUID clsidFolderID, LPWSTR* lppwstrPath);
-    IEGetWriteableFolderPath *func = (IEGetWriteableFolderPath *)GetProcAddress(module, "IEGetWriteableFolderPath");
-    if (func != NULL) {
-      // From KnownFolders.h (part of Vista SDK):
-#define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
-   const GUID name = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
-      DEFINE_KNOWN_FOLDER(FOLDERID_InternetCache, 0x352481E8, 0x33BE, 0x4251, 0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D); 
+    if (is_protected) {
+      // If we *are* running in protected mode, we need to use
+      // FOLDERID_LocalAppDataLow.
       
-      LPWSTR cache_path = NULL;
-      HRESULT hr = (*func)(FOLDERID_InternetCache, &cache_path);
-      if (SUCCEEDED(hr)) {
-        if (!wstr_to_string(root, cache_path)) {
-          // Couldn't decode the LPWSTR.
-          CoTaskMemFree(cache_path);
-        } else {
-          CoTaskMemFree(cache_path);
-          root += string("/Panda3D");
-          
-          // Attempt to make it first, if possible.
-          CreateDirectory(root.c_str(), NULL);
+      // We should be able to use IEGetWriteableFolderPath() to query
+      // this folder, but for some reason, that function returns
+      // E_ACCESSDENIED on FOLDERID_LocalAppDataLow, even though this is
+      // certainly a folder we have write access to.
+      
+      // Well, SHGetKnownFolderPath() does work.  This function only
+      // exists on Vista and above, though, so we still have to pull it
+      // out of the DLL instead of hard-linking it.
+      
+      HMODULE shell32 = LoadLibrary("shell32.dll");
+      if (shell32 != NULL) {
+        typedef HRESULT STDAPICALLTYPE SHGetKnownFolderPath(REFGUID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
+        SHGetKnownFolderPath *func = (SHGetKnownFolderPath *)GetProcAddress(shell32, "SHGetKnownFolderPath");
+        if (func != NULL) {
+          LPWSTR cache_path = NULL;
+          HRESULT hr = (*func)(FOLDERID_LocalAppDataLow, 0, NULL, &cache_path);
           
-          bool isdir = false;
-          DWORD results = GetFileAttributes(root.c_str());
-          if (results != -1) {
-            isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
-          }
-        
-          if (isdir) {
-            // The directory exists!
-            FreeLibrary(module);
-            return root;
+          if (SUCCEEDED(hr)) {
+            if (!wstr_to_string(root, cache_path)) {
+              // Couldn't decode the LPWSTR.
+              CoTaskMemFree(cache_path);
+            } else {
+              CoTaskMemFree(cache_path);
+              
+              root += string("/Panda3D");
+              if (check_root_dir(root)) {
+                FreeLibrary(shell32);
+                FreeLibrary(ieframe);
+                return root;
+              }
+            }
           }
         }
+        FreeLibrary(shell32);
+      }
+      
+      // Couldn't get FOLDERID_LocalAppDataLow for some reason.  We're
+      // in fallback mode now.  Use IEGetWriteableFolderPath to get
+      // the standard cache folder.
+      typedef HRESULT STDAPICALLTYPE IEGetWriteableFolderPath(REFGUID clsidFolderID, LPWSTR* lppwstrPath);
+      IEGetWriteableFolderPath *func = (IEGetWriteableFolderPath *)GetProcAddress(ieframe, "IEGetWriteableFolderPath");
+      if (func != NULL) {
+        LPWSTR cache_path = NULL;
+
+        // Since we're here, we'll start by asking for
+        // LocalAppDataLow, even though I know it doesn't work.
+        HRESULT hr = (*func)(FOLDERID_LocalAppDataLow, &cache_path);
+        if (FAILED(hr)) {
+          // This one should work.
+          hr = (*func)(FOLDERID_InternetCache, &cache_path);
+        }
+
+        if (SUCCEEDED(hr)) {
+          if (!wstr_to_string(root, cache_path)) {
+            // Couldn't decode the LPWSTR.
+            CoTaskMemFree(cache_path);
+          } else {
+            CoTaskMemFree(cache_path);
+            root += string("/Panda3D");
+            if (check_root_dir(root)) {
+              FreeLibrary(ieframe);
+              return root;
+            }
+          }            
+        }
       }
     }
-  }    
 
-  // We're done with the HMODULE now.
-  if (module != NULL) {
-    FreeLibrary(module);
+    FreeLibrary(ieframe);
+  }
+
+  // All right, here we are in the normal, unprotected mode.  This is
+  // also the normal XP codepath.
+
+  // e.g., c:/Documents and Settings/<username>/Local Settings/Application Data/Panda3D
+  root = get_csidl_dir(CSIDL_LOCAL_APPDATA);
+  if (!root.empty()) {
+    return root;
   }
 
-  // All right, GetWriteableFolderPath failed; fall back to the XP-era
-  // way of asking for the "Temporary Internet Files".
+  // For some crazy reason, we can't get CSIDL_LOCAL_APPDATA.  Fall
+  // back to the cache folder.
+
+  // e.g. c:/Documents and Settings/<username>/Local Settings/Temporary Internet Files/Panda3D
   root = get_csidl_dir(CSIDL_INTERNET_CACHE);
   if (!root.empty()) {
     return root;
   }
   
   // If we couldn't get any of those folders, huh.  Punt and try for
-  // Temp, for lack of a better place.
+  // the old standby GetTempPath, for lack of anything better.
   static const int buffer_size = MAX_PATH;
   char buffer[buffer_size];
   if (GetTempPath(buffer_size, buffer) != 0) {
-    string root = buffer;
+    root = buffer;
     root += string("Panda3D");
-    
-    // Attempt to make it first, if possible.
-    CreateDirectory(root.c_str(), NULL);
-    
-    bool isdir = false;
-    DWORD results = GetFileAttributes(root.c_str());
-    if (results != -1) {
-      isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
-    }
-    
-    if (isdir) {
-      // The directory exists!
+    if (check_root_dir(root)) {
       return root;
     }
   }

+ 1 - 0
direct/src/plugin/p3dAuthSession.cxx

@@ -342,6 +342,7 @@ win_create_process() {
   delete[] command_line;
 
   if (!started_program) {
+    nout << "CreateProcess failed, error: " << GetLastError() << "\n";
     return INVALID_HANDLE_VALUE;
   }
 

+ 4 - 0
direct/src/plugin/p3dSession.cxx

@@ -1250,6 +1250,10 @@ win_create_process() {
      &startup_info, &process_info);
   bool started_program = (result != 0);
 
+  if (!started_program) {
+    nout << "CreateProcess failed, error: " << GetLastError() << "\n";
+  }
+
   delete[] command_line;
 
   // Close the pipe handles that are now owned by the child.