1

i am trying to store some settings in resource of my application but failed i dont want to use ini file or registry methods i am using this code

    var
    data :string;

  procedure WriteSettings(ServerFile: string; Settings: string);
    var
     ResourceHandle: THandle;
     pwServerFile: PWideChar;
    begin
     GetMem(pwServerFile, (Length(ServerFile) + 1) * 2);
     try
       StringToWideChar(ServerFile, pwServerFile, Length(ServerFile) * 2);
       ResourceHandle := BeginUpdateResourceW(pwServerFile, False);
       UpdateResourceW(ResourceHandle, MakeIntResourceW(10), 'SETTINGS', 0, @Settings[1], Length(Settings) + 1);
       EndUpdateResourceW(ResourceHandle, False);
     finally
       FreeMem(pwServerFile);
     end;
    end;
    function ReadSettings(ServerFile: string): string;
    var
      ServerModule: HMODULE;
      ResourceLocation: HRSRC;
      ResourceSize: dword;
      ResourceHandle: THandle;
      ResourcePointer: pointer;
    begin
      ServerModule := LoadLibrary(pchar(ServerFile));
      try
        ResourceLocation := FindResource(ServerModule, 'SETTINGS', RT_RCDATA);
        ResourceSize := SizeofResource(ServerModule, ResourceLocation);
        ResourceHandle := LoadResource(ServerModule, ResourceLocation);
        ResourcePointer := LockResource(ResourceHandle);
        if ResourcePointer <> nil then
        begin
          SetLength(Result, ResourceSize - 1);
          CopyMemory(@Result[1], ResourcePointer, ResourceSize);
          FreeResource(ResourceHandle);
        end;
      finally
        FreeLibrary(ServerModule);
      end;
    end;
  procedure TForm1.saveClick(Sender: TObject);
begin
    writesettings(paramastr(0),'true');  
end;
 procedure TForm1.ReadClick(Sender: TObject);
begin
   data:=readsettings(paramstr(0));  
end;

 begin
   if data='true' then checkbox1.checked:=true;
 end

but is nit storing the that i wrote to resource :( is there any other better options? any help please

steve0
  • 721
  • 3
  • 11
  • 19
  • `if data:='true' then checkbox1.checked:=true;`? Maybe you mean `if data='true' then checkbox1.checked:=true;`? – Andreas Rejbrand Jul 16 '10 at 16:44
  • yeah sorry for blunder mistake – steve0 Jul 16 '10 at 17:08
  • 6
    Do note that users with regular user rights will not be able to write files in the program files folder. So this won't work for them. And with UAC since Vista it wouldn't even work for admins unless they run your program with elevated rights. – Lars Truijens Jul 16 '10 at 17:13
  • hmm thanks for info sir ,but my program is not an installer . anyway i am trying this on my windows XP Sp3 but didnt worked :( – steve0 Jul 16 '10 at 17:19
  • 6
    listen to @Lars. You are doomed with this approach if you have any users who will ever want to run on Vista, Windows7, or later. You cannot modify any file in either of the "program files" folders, unless you ARE an installer. i.e. regular programs cannot write there unless UAC is turned off or you run as admin. IMO, you should follow published developer guidelines for storing settings. – Chris Thornton Jul 16 '10 at 17:23

2 Answers2

7

The documentation for BeginUpdateResource clearly states why your code doesn't work (emphasis added):

pFileName [in]

LPCTSTR

The binary file in which to update resources. An application must be able to obtain write-access to this file; the file referenced by pFileName cannot be currently executing. If pFileName does not specify a full path, the system searches for the file in the current directory.

You might have been able to deduce the cause of the error yourself if you were checking the API function's return value and calling GetLastError on failure, like the documentation advises.

You can store settings in a resource, but you can't store settings in a resource of the program whose settings you're trying to store. And now that we've established that you're not allowed to store settings in the program itself, you may as well just abandon the resource idea and use a more conventional method of storing settings in an external location, such as the registry, an INI file, or whatever. You might still wish to read a set of default settings from a resource if you find that the external location doesn't yet have any settings, as might happen after a fresh install.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
5

Having your program modify itself is a bad idea. As a couple people already pointed out, this will fail badly under Vista and Win7 in most cases. It's better not to fight the operating system. Windows already provides a couple different ways for your program to store its settings. You can drop an INI or other config file in some folder outside of Program Files, or you can store it in the Registry, which is probably the best option.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • 2
    By "some folder outside of Program Files", Mason Wheeler means "C:\Users\\AppData\Local\\\", the first part of which (up to and including "Local") should be obtained dynamically by means of the `SHGetFolderPath` function of the Windows API (http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx). – Andreas Rejbrand Jul 16 '10 at 17:53
  • 1
    Yes, basically. If you're on Vista or later, that's the right path too. Otherwise SHGetFolderPath will send you somewhere else. (Which is why it should be used instead of trying to hardcode the path.) – Mason Wheeler Jul 16 '10 at 18:15
  • 2
    "Having your program modify itself is a bad idea". Agreed. Furthermore, it's highly suspicious behavior and would probably be flagged as malware. Makes me wonder if DEP or similar may be preventing his code from working in the first place? Admittedly, I jumped into "bad idea" lecturing, without looking at the code much. – Chris Thornton Jul 16 '10 at 18:20