{"id":865,"date":"2011-09-22T22:18:01","date_gmt":"2011-09-22T12:18:01","guid":{"rendered":"http:\/\/www.malcolmgroves.com\/blog\/?p=865"},"modified":"2015-03-13T10:49:35","modified_gmt":"2015-03-12T23:49:35","slug":"cross-platform-special-folders-in-firemonkey","status":"publish","type":"post","link":"http:\/\/www.malcolmgroves.com\/blog\/?p=865","title":{"rendered":"Cross-platform Special Folders in FireMonkey"},"content":{"rendered":"<p>There was a question on the <a href=\"http:\/\/www.adug.org.au\/Admin\/mailing_list.htm\">ADUG list<\/a> last week about how to retrieve &#8220;special folder&#8221; locations on OS X. By special folder, I mean locations like the user&#8217;s Home directory, the Documents directory, Temp directory, etc. I thought I&#8217;d write up the solution both because it&#8217;s probably something that more people will be wondering and also because it&#8217;s a nice little introduction to calling out to the OS X API.<\/p>\n<p>If you want either the path to the Home or the Temp directory, this is ridiculously easy. The <a href=\"http:\/\/docwiki.embarcadero.com\/VCL\/en\/IOUtils\" target=\"_blank\">IOUtils<\/a> unit already contains TPath.GetTempPath and TPath.GetHomePath, and these work on both Windows and OS X.<\/p>\n<p>However, if you want another directory, such as the Documents directory, you need to do a little more work.<\/p>\n<p><!--more-->I&#8217;m sure many of you have done this same thing on Windows, using the Windows API SHGetFolderPath, like this:<\/p>\n<pre lang=\"Delphi\">  function GetDocumentDirectory : string;\r\n  var\r\n    szBuffer: array [0..MAX_PATH] of Char;\r\n  begin\r\n    OleCheck (SHGetFolderPath ( FmxHandleToHWND(Handle),\r\n                               CSIDL_MYDOCUMENTS,\r\n                               0,\r\n                               0,\r\n                               szBuffer));\r\n    Result := szBuffer;\r\n  end;\r\n<\/pre>\n<p>As an aside, the first parameter to the SHGetFolderPath is a HWND. In VCL, you could just pass in the Handle of the form, however in FireMonkey the Window handle is a TFmxHandle, not a HWND. The Fmx.Platform.Win unit contains a FmxHandleToHWND function that, as the name suggests, will take your FireMOnkey handle and give you back a HWND.<\/p>\n<p>So, back to the point, if this is how we do it in FireMonkey on Windows, how do we do it on OS X? Let&#8217;s have a look:<\/p>\n<pre lang=\"Delphi\">  function GetDocumentDirectory : string;\r\n  var\r\n    FileMgr : NSFileManager;\r\n    URL : NSURL;\r\n    Error : NSError;\r\n  begin\r\n    FileMgr := TNSFileManager.Create;\r\n    URL := FileMgr.URLForDirectory(NSDocumentDirectory,\r\n                                   NSUserDomainMask,\r\n                                   nil,\r\n                                   false,\r\n                                   Error);\r\n    if Assigned(Error) then\r\n      raise Exception.Create(Error.localizedDescription.UTF8String);\r\n\r\n    Result := URL.path.UTF8String;\r\n  end;\r\n<\/pre>\n<p>First thing we do is get a reference to a <a href=\"http:\/\/developer.apple.com\/library\/mac\/#documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSFileManager_Class\/Reference\/Reference.html\" target=\"_blank\">NSFileManager<\/a> interface. It, and the TNSFileManager class that implements it, can be found in the Macapi.Foundation unit.<\/p>\n<p>Once we have our NSFileManager reference, we can use the URLForDirectory method, which is roughly equivalent to the SHGetFolderPath call in the Windows example. We need to pass in a NSError variable and then check it to make sure everything worked OK. We raise an exception if not.<\/p>\n<p>However, what we get back from URLForDirectory is not a string but a <a href=\"http:\/\/developer.apple.com\/library\/mac\/#documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSURL_Class\/Reference\/Reference.html\" target=\"_blank\">NSURL<\/a> instance. In order to get a string containing the path, we use, not surprisingly, NSURL.Path. However, this also is not a String, it&#8217;s a <a href=\"http:\/\/developer.apple.com\/library\/mac\/#documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSString_Class\/Reference\/NSString.html%23\/\/apple_ref\/doc\/c_ref\/NSString\" target=\"_blank\">NSString<\/a>. How do we convert that to a string? Well, NSString.UTF8String is a quick, easy way to get back a UTF8 encoded string. If you want a different encoding, check out some of the other extraction methods on NSString. <strong>Update<\/strong> : Chris Rolliston has written a <a href=\"http:\/\/delphihaven.wordpress.com\/2011\/09\/26\/converting-from-a-cocoa-string-to-a-delphi-string\/\" target=\"_blank\">nice follow-up post<\/a> digging into converting NSStrings to Delphi Strings in much more detail.<\/p>\n<p>In the example project, once I have the full path of the Documents directory, I use the IOUtils classes to enumerate over the folders and files in that folder and add the names to a listbox:<\/p>\n<pre lang=\"Delphi\">var\r\n  DocumentsPath, Filename : String;\r\nbegin\r\n  DocumentsPath := GetDocumentDirectory;\r\n  Label1.Text := DocumentsPath;\r\n\r\n\r\n  for Filename in TDirectory.GetDirectories(DocumentsPath) do\r\n    Listbox1.Items.Add(Format('Folder : %s', [Filename]));\r\n\r\n  for Filename in TDirectory.GetFiles(DocumentsPath) do\r\n    Listbox1.Items.Add(Format('File : %s', [Filename]));\r\n\r\nend;\r\n<\/pre>\n<p>Here&#8217;s the resulting app on Windows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" title=\"Screen shot 2011-09-22 at 10.05.32 PM.png\" src=\"http:\/\/www.malcolmgroves.com\/blog\/wp-content\/uploads\/2011\/09\/Screen-shot-2011-09-22-at-10.05.32-PM.png\" alt=\"Screen shot 2011 09 22 at 10 05 32 PM\" width=\"441\" height=\"453\" border=\"0\" \/><\/p>\n<p>and on OSX:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" title=\"Screen shot 2011-09-22 at 10.07.25 PM.png\" src=\"http:\/\/www.malcolmgroves.com\/blog\/wp-content\/uploads\/2011\/09\/Screen-shot-2011-09-22-at-10.07.25-PM.png\" alt=\"Screen shot 2011 09 22 at 10 07 25 PM\" width=\"427\" height=\"438\" border=\"0\" \/><\/p>\n<p>You can download the sample project from my <a href=\"http:\/\/code.google.com\/p\/malcolmgrovessamples\/\">delphi-samples repository<\/a> on github.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There was a question on the ADUG list last week about how to retrieve &#8220;special folder&#8221; locations on OS X. By special folder, I mean locations like the user&#8217;s Home directory, the Documents directory, Temp directory, etc. I thought I&#8217;d write up the solution both because it&#8217;s probably something that more people will be wondering [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[120,77],"tags":[81,19,48,80],"class_list":["post-865","post","type-post","status-publish","format-standard","hentry","category-firemonkey","category-os-x","tag-cross-platform","tag-delphi","tag-embarcadero","tag-os-x-api"],"_links":{"self":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/865","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=865"}],"version-history":[{"count":15,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/865\/revisions"}],"predecessor-version":[{"id":1769,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/865\/revisions\/1769"}],"wp:attachment":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=865"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}