2424
2525import  java .io .File ;
2626import  java .io .UnsupportedEncodingException ;
27+ import  java .util .HashMap ;
28+ import  java .util .Map ;
2729
2830import  com .sun .jna .Library ;
2931import  com .sun .jna .Native ;
32+ import  com .sun .jna .NativeMapped ;
33+ import  com .sun .jna .PointerType ;
34+ import  com .sun .jna .win32 .W32APIFunctionMapper ;
35+ import  com .sun .jna .win32 .W32APITypeMapper ;
3036
3137import  processing .app .Base ;
3238import  processing .app .Preferences ;
@@ -182,19 +188,34 @@ public File getSettingsFolder() throws Exception {
182188 // Value Type: REG_SZ 
183189 // Value Data: path 
184190
185-  String  keyPath  =
186-  "Software\\ Microsoft\\ Windows\\ CurrentVersion"  +
187-  "\\ Explorer\\ Shell Folders" ;
188-  String  appDataPath  =
189-  Registry .getStringValue (REGISTRY_ROOT_KEY .CURRENT_USER , keyPath , "AppData" );
191+  //String keyPath = 
192+  // "Software\\Microsoft\\Windows\\CurrentVersion" + 
193+  // "\\Explorer\\Shell Folders"; 
194+  //String appDataPath = 
195+  // Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "AppData"); 
196+  
197+  // Fix for Issue 410 
198+  // Java 1.6 doesn't provide a good workaround (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519127) 
199+  // Using JNA and SHGetFolderPath instead. 
200+  
201+  char [] pszPath  = new  char [Shell32 .MAX_PATH ]; // this will be contain the path if SHGetFolderPath is successful 
202+  int  hResult  = Shell32 .INSTANCE .SHGetFolderPath (null , Shell32 .CSIDL_APPDATA , null , Shell32 .SHGFP_TYPE_CURRENT , pszPath );
203+  
204+  if  (Shell32 .S_OK  != hResult ){ 
205+  throw  new  Exception ("Problem city, population your computer" );
206+  }
190207
191-  File  dataFolder  = new  File (appDataPath , "Processing" );
192-  return  dataFolder ;
208+  String  appDataPath  = new  String (pszPath );
209+  int  len  = appDataPath .indexOf ("\0 " );
210+  appDataPath  = appDataPath .substring (0 , len );
211+  
212+  // DEBUG 
213+  //throw new Exception("win: " + appDataPath); 
214+  return  new  File (appDataPath , "Processing" );
193215 }
194216
195217
196218 // looking for Documents and Settings/blah/My Documents/Processing 
197-  // (though using a reg key since it's different on other platforms) 
198219 public  File  getDefaultSketchbookFolder () throws  Exception  {
199220
200221 // http://support.microsoft.com/?kbid=221837&sd=RMVP 
@@ -211,12 +232,28 @@ public File getDefaultSketchbookFolder() throws Exception {
211232 // in some instances, this may be overridden by a policy, in which case check: 
212233 // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders 
213234
214-  String  keyPath  =
215-  "Software\\ Microsoft\\ Windows\\ CurrentVersion"  +
216-  "\\ Explorer\\ Shell Folders" ;
217-  String  personalPath  =
218-  Registry .getStringValue (REGISTRY_ROOT_KEY .CURRENT_USER , keyPath , "Personal" );
235+  //String keyPath = 
236+  // "Software\\Microsoft\\Windows\\CurrentVersion" + 
237+  // "\\Explorer\\Shell Folders"; 
238+  //String personalPath = 
239+  // Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "Personal"); 
240+  
241+  // "The "Shell Folders" key exists solely to permit four programs written  
242+  // in 1994 to continue running on the RTM version of Windows 95." -- Raymond Chen, MSDN 
243+ 
244+  char [] pszPath  = new  char [Shell32 .MAX_PATH ]; // this will be contain the path if SHGetFolderPath is successful 
245+  int  hResult  = Shell32 .INSTANCE .SHGetFolderPath (null , Shell32 .CSIDL_PERSONAL , null , Shell32 .SHGFP_TYPE_CURRENT , pszPath );
246+  
247+  if  (Shell32 .S_OK  != hResult ){ 
248+  throw  new  Exception ("Problem city, population your computer" );
249+  }
219250
251+  String  personalPath  = new  String (pszPath );
252+  int  len  = personalPath .indexOf ("\0 " );
253+  personalPath  = personalPath .substring (0 , len );
254+  
255+  // DEBUG 
256+  //throw new Exception("win: " + personalPath); 
220257 return  new  File (personalPath , "Processing" );
221258 }
222259
@@ -285,7 +322,7 @@ public interface WinLibC extends Library {
285322 public  int  _putenv (String  name );
286323 }
287324
288- 
325+   
289326 public  void  setenv (String  variable , String  value ) {
290327 //WinLibC clib = WinLibC.INSTANCE; 
291328 clib ._putenv (variable  + "="  + value );
@@ -303,4 +340,47 @@ public int unsetenv(String variable) {
303340 //return 0; 
304341 return  clib ._putenv (variable  + "=" );
305342 }
343+  
344+  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
345+  
346+  // JNA code for using SHGetFolderPath to fix Issue 410 
347+  // Based on answer provided by McDowell at 
348+  // http://stackoverflow.com/questions/585534/ 
349+  // what-is-the-best-way-to-find-the-users-home-directory-in-java/586917#586917 
350+  
351+  private  static  Map <String , Object > OPTIONS  = new  HashMap <String , Object >();
352+  
353+  static {
354+  OPTIONS .put (Library .OPTION_TYPE_MAPPER , W32APITypeMapper .UNICODE );
355+  OPTIONS .put (Library .OPTION_FUNCTION_MAPPER , W32APIFunctionMapper .UNICODE );
356+  }
357+  
358+  static  class  HANDLE  extends  PointerType  implements  NativeMapped {}
359+  
360+  static  class  HWND  extends  HANDLE  {}
361+  
362+  public  interface  Shell32  extends  Library {
363+  
364+  public  static  final  int  MAX_PATH  = 260 ;
365+  public  static  final  int  SHGFP_TYPE_CURRENT  = 0 ;
366+  public  static  final  int  SHGFP_TYPE_DEFAULT  = 1 ;
367+  public  static  final  int  S_OK  = 0 ;
368+  
369+  // KNOWNFOLDERIDs are preferred to CSDIL values 
370+  // but Windows XP only supports CSDIL so thats what we have to use 
371+  public  static  final  int  CSIDL_APPDATA  = 0x001c ; // "Application Data" 
372+  public  static  final  int  CSIDL_PERSONAL  = 0x0005 ; // "My Documents" 
373+  
374+  static  Shell32  INSTANCE  = (Shell32 ) Native .loadLibrary ("shell32" , Shell32 .class , OPTIONS );
375+  
376+  /** 
377+  * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx 
378+  *  
379+  * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken, 
380+  * DWORD dwFlags, LPTSTR pszPath); 
381+  */ 
382+  public  int  SHGetFolderPath (HWND  hwndOwner , int  nFolder , HANDLE  hToken ,
383+  int  dwFlags , char [] pszPath );
384+  }
385+  
306386}
0 commit comments