Onderstaande heb ik geschreven zonder verder kennis van Vista dan het bovenstande. Code werkt wel in XP.
Ik schrijf graag allerlei data naar een subfolder van een App, maar WindowsVista geeft je APP geen toestemming om naar de program folder te schrijven.
Toevallig heb ik me onlangs al in de systeemfolders van Microsoft verdiept.
Voor mezelf heb ik toen een unit ApiSpecialFolders.pas geschreven, met de function getSpecialFolder(n:integer):string.
Het best kun je dan naar de folder:
getSpecialFolder(CSIDL_APPDATA) + '\' + appname +'\'
schrijven.
Er zijn ook allerlei Apps die naar de folder Mijn Documenten schrijven, wat heel onprettig is.
Door de typische Microsoft aanpak komen files die bij elkaar horen op allerlei plekken te staan. Maar goed, je hebt er maar mee te leren leven.
CSIDL_APPDATA (0x001a)
Version 4.71. The file system directory that serves as a common repository for application-specific data. A typical path is C:\Documents and Settings\username\Application Data. This CSIDL is supported by the redistributable Shfolder.dll for systems that do not have the Microsoft Internet Explorer 4.0 integrated Shell installed.
Natuurlijk bevalt me de oplossing van microsoft niet, in bepaalde gevallen veroorzaakt hij problemen:
1. Er kunnen meerdere schijven zijn. Het programma is geinstalleerd in de folder 'E:\myapp' en de schijf 'c:\' waar ook MijnDocumenten, etc staan, is vrijwel vol.
Stel dat myapp echt heel grote bestanden aanmaakt, bij elkaar zo'n tien GByte. Dan moet hij wel naar de eigen subfolder schrijven.
2. Het leuke van Delphi is dat je een exe gewoon ergens neer kunt zetten en hij doet het. Ideaal met een USB stick. Het is toch een kick als je je eigen exe kunt maken, die je op je USB stick naar de bibliotheek meeneemt en die dan precies zo kunt gebruiken als je wilt.
Met de mooiste VisualBasic programmas die ik gemaakt heb kan dit niet!!
Maar goed, dit is dan ook weer de typische Microsoft architectuur.
Als je een app op een duim neerzet moet hij allerlei data juist naar de eigen folder schrijven.
Standaard kun je zeggen: Een ap schrijft data naar de eigen folder, behalve als hnij in de programsfodler staat
Oplossing:
(Er is natuurlijk ook een oplossing waarbij de gebruiker via opties zelf instelt wat de datafolder is, maar die behandel ik hier niet want is te ingewikkeld voor de 50 plus computer gebruiker)
Je kunt een var datafolder:string gebruiken.
En je hoeft die folder maar eenmaal te initialiseren.
In pseudocode doe je dit op de volgende manier:
IF AppFolder in ProgramsFolder
THEN datafolder is subfolder van AppData folder
ELSE datafolder is subfolder van AppFolder
IF datafolder niet bestaat
THEN forceer het maken van datafolder
Dit leidt zonder al te veel problemen tot:
Code:
unit unitDataFolder;
{ * * * * * * * * * * * * * * * * * * * * * * * * * *
Dutch Homelands Software; Delphi Library
written in april 2007, by gbuisman
to please microsoft = Vista
datafolder is a subfolder to the app
when app not in the Programs Folder
app best in a folder of its own
datafolder is in user\Application Data folder
when app in Programs Folder
var datafolder is set in initialization section
* * * * * * * * * * * * * * * * * * * * * * * * * * }
interface
uses dialogs;
var datafolder:string;
procedure initDataFolder(var datafolder:string);
implementation
uses SysUtils, Forms
, shellapi
, Windows
, SHLOBJ;
function getSpecialFolder(n:integer):string;
//inner code is cut'N'paste from someplace
var
PIDL : PItemIDList;
Buffer : array[0..MAX_PATH] of Char;
begin
//SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, PIDL); = desktop
SHGetSpecialFolderLocation(0, n, PIDL);
SHGetPathFromIDList (PIDL, Buffer);
result:= string(Buffer);
end;
function getAppDataFolder:string;
var
programsFolder,
appfolderpath,
appfoldername:string;
begin
//1. check if app in programsfolder
programsFolder:=getSpecialFolder(38);//38 = CSIDL_PROGRAM_FILES
appfolderpath:=extractfiledir(Application.ExeName);// uses SysUtils
//showmessage('programsFolder = ' + programsFolder + #13#10 +
// 'appfolderpath = ' + appfolderpath + #13#10 +
// 'Copy(appfolderpath,1,length(programsFolder)) = ' + Copy(appfolderpath,1,length(programsFolder)));
if strComp(pchar(programsFolder),pchar(Copy(appfolderpath,1,length(programsFolder))))=0
then
begin
appfoldername:=Copy(appfolderpath,length(programsFolder) + 1 ,MAX_PATH);
result:=getSpecialFolder(26) { = CSIDL_APPDATA (0x001a)}
+ appfoldername;
//showmessage('appfoldername = ' + appfoldername + #13#10 +
// 'result = ' + result);
end
else
begin
result:=appfolderpath + '\data';
//showmessage('result = ' + result);
end;
end;
procedure initDataFolder(var datafolder:string);
begin
datafolder:= getAppDataFolder;
IF NOT DirectoryExists(datafolder) THEN
begin
IF NOT (ForceDirectories(datafolder))then
begin
showmessage('application cannot run cause failed to create' + #13#10
+ datafolder + #13#10 + 'thank you');
Application.Terminate;
end;
end;
end;
initialization
initDataFolder(datafolder);
showmessage('datafolder = ' + datafolder);//comment this line!
end.
Bookmarks