Trying to delete a resource from an exe

Trying to delete a resource from an exe,

I'm using this:

procedure KillResource(exeFullPath, ResName, ResType: pchar);
var update : dword;
begin
  update := BeginUpdateResource(exeFullPath, false);
  if update <> 0 then
    try
      UpdateResource(update, ResType, ResName, 0, nil, 0);
    finally
      EndUpdateResource(update, false);
    end;
end;



I want to delete version info and manifest, so I call it like this:

       KillResource(pchar(FileMod), makeintresource(1), makeintresource(24));

       KillResource(pchar(FileMod), makeintresource(1), RT_VERSION);

filemod is the path to my exe

it doesn't work, WHY :S


500 points for this one, thx!
Marc582Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

2266180Commented:
probably because you're not using the correct language?
open the file with some resouerce editor (reshacker, xn resource editor, etc) and see what's the language of the resource. you will need to use that exact same language in order to delete (or do anything with) the resource.
0
Marc582Author Commented:
ok I'll try, but maybe you could give me a fix of my procedure, so it can detect automatically the correct language cuz I have no idea how
0
2266180Commented:
see this demo: http://www.ciuly.com/delphi/win32api/resources/enumNameLang/index.html
it's for icons but it's very easy to adapt to your scenario.
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

ziolkoCommented:
I've played a bit with updating resources some time ago and from what I remember if you trying to update resources of module that is in use it will fail but no errors will be returned by API calls.
so try to update resources of exe that is not in use.

when it comes to lang id try neutral settings:

function MAKELANGID(p, s: Word):DWORD;
begin
  Result := (s shl 10) or p;
end;

MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)

ziolko.
0
Marc582Author Commented:
nothing is working, please help me,

I've tried to redo the function with the example of madshi (http://help.madshi.net/madResUnit.htm),

procedure MadKillResource(exeFullPath, bmpResName: PWideChar);
var update : dword;
begin
  update := BeginUpdateResourceW(exeFullPath, false);
  if update <> 0 then
    try
      UpdateResourceW(update, PWideChar(RT_GROUP_ICON), bmpResName, 0, nil, 0);
    finally
      EndUpdateResourceW(update, false);
    end;
end;


then

MadKillResource('C:\calc.exe', 'SC');

that doesn't work :@, and even if I replace the "false" of  BeginUpdateResourceW with "true", it does nothing (it should delete all resource...)

also, I tried with neutral language, and also tried with the language of my calc.exe (I saw it with the help of xn resource editor)

but it doesn't work too! :S:S
0
Marc582Author Commented:
ok with GetLastError, I get Error 87
0
ziolkoCommented:
87 means incorrect paramter

this works for me (Project2 is simple delphi app):

procedure TMyForm.Button2Click(Sender: TObject);
var UpdHandle: THandle;
    p: Pointer;
begin
  UpdHandle := BeginUpdateResource('Project2.exe', False);
  if UpdHandle <> 0 then
    try
      UpdateResource(UpdHandle, RT_GROUP_ICON, 'MAINICON', MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), p, 4);
    finally
      EndUpdateResource(UpdHandle, False);
    end;
end;

ziolko
0
Marc582Author Commented:
your code doesn't delete the resource, it create mainicon and adds 4 byte ...
0
Russell LibbySoftware Engineer, Advisory Commented:
Its all about the language ID....

Assuming you are running a US version of Windows, then the following works fine:

procedure KillResource(ExeFile: String; ResType, ResName: PChar; LangID: Word = 0);
var  hUpdate:       THandle;
begin

  // Open file for resource updating
  hUpdate:=BeginUpdateResource(PChar(ExeFile), False);

  // Check handle
  if (hUpdate = 0) then
     // Raise error
     RaiseLastWin32Error
  // Remove resource
  else if UpdateResource(hUpdate, ResType, ResName, LangID, nil, 0) then
  begin
     // End the update
     if not(EndUpdateResource(hUpdate, False)) then RaiseLastWin32Error;
  end
  else
     // Raise error
     RaiseLastWin32Error

end;

var  dwIndex:       Integer;
     wLangID:       Word;
begin

  // The language needs to be set correctly
  wLangID:=(SUBLANG_ENGLISH_US shl 10) or LANG_ENGLISH;

  // Remove the resources
  KillResource('c:\calc.exe', MakeIntResource(24), MakeIntResource(1), wLangID);
  KillResource('c:\calc.exe', RT_VERSION, MakeIntResource(1), wLangID);
  KillResource('c:\calc.exe', RT_GROUP_ICON, 'SC', wLangID);
  for dwIndex:=1 to 6 do KillResource('c:\calc.exe', RT_STRING, MakeIntResource(dwIndex), wLangID);

end;

------------

Note: this WILL delete the resource from the exe file, this WILL NOT make the executable smaller.

Russell

0
Marc582Author Commented:
> Note: this WILL delete the resource from the exe file, this WILL NOT make the executable smaller.

why this, I don't see the point...
0
Russell LibbySoftware Engineer, Advisory Commented:
>> Note: this WILL delete the resource from the exe file, this WILL NOT make the executable smaller.

> why this, I don't see the point...

There are a number of valid reasons for adding / modifying resources in a seperate exe; there are very few for deleting them. (eg, remove the dialog resources and the app won't run). The most common reason is to reduce exe size, thus I wanted it to be clear that this does not change the exe size.
0
Marc582Author Commented:
it reduce about 45 kb without altering exe, what are you saying?....
0
ziolkoCommented:
>>your code doesn't delete the resource, it create mainicon and adds 4 byte ..

nope, it deletes main icon from exe

ziolko.
0
2266180Commented:
>> Its all about the language ID....

I'm glad finally someone else is getting to my initial conclusion :D
0
ziolkoCommented:
yup, my mistake correct langid is required

ziolko.
0
Russell LibbySoftware Engineer, Advisory Commented:
Ok, I am going to give this one more shot...

The code below shows how to easily deal with the whole language issue. The exe/dll is loaded and the resource groups / values / and language setting for each value are loaded up. The base object then allows you to simply call remove on the desired type/name, and it handles the rest. You should note that example code is also provided with the source.

Now, back to the whole other (unspoken) question about exe size...

The BeginUpdateResource/EndUpdateResource are used to add / modify / delete resources from a PE file. When deleting a resource, the API's do not restructure the remaining resources around the now available space. In the case of calc.exe, its 114,688 bytes before you remove resource, and its 114,688 AFTER you remove the resources. No space is reclaimed when removing the resources.

Russell

--------

unit Resources;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  Resources
//   Author      :  rllibby
//   Date        :  02.07.2008
//   Description :  Source code for PE resource enumeration and misc handling
//
////////////////////////////////////////////////////////////////////////////////
interface

{ Example usage:

var  lpResources:   TPEResources;
     dwIndex:       Integer;
begin

  // Testing code
  if (CopyFile('c:\windows\system32\calc.exe', 'c:\calc.exe', False)) then
  begin
     // Create resource object list
     lpResources:=TPEResources.Create('c:\calc.exe');
     try
        // Remove the resource
        lpResources.Remove(RT_MANIFEST, MakeIntResource(1));
        lpResources.Remove(RT_VERSION, MakeIntResource(1));
        lpResources.Remove(RT_GROUP_ICON, 'SC');
        for dwIndex:=1 to 6 do
        begin
           lpResources.Remove(RT_STRING, MakeIntResource(dwIndex));
        end;
     finally
        // Free object
        lpResources.Free;
     end;
  end;

end;

}

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes;

////////////////////////////////////////////////////////////////////////////////
//   Data types
////////////////////////////////////////////////////////////////////////////////
type
  TResNameID        =  packed record
     Name:          PChar;
     ID:            PChar;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Updated list of predefined resource types
////////////////////////////////////////////////////////////////////////////////
const

  // Missing predefined types
  RT_HTML           =  MakeIntResource(23);
  RT_MANIFEST       =  MakeIntResource(24);

  // Maximum predefined value
  RT_MAX_PREDEFINE  =  24;

  // List of predefined types with associated name
  RT_PREDEFINED:    Array [0..RT_MAX_PREDEFINE] of TResNameID  =
                    (
                       (Name: '#0';               ID: MakeIntResource(0)),
                       (Name: 'Cursor';           ID: RT_CURSOR),
                       (Name: 'Bitmap';           ID: RT_BITMAP),
                       (Name: 'Icon';             ID: RT_ICON),
                       (Name: 'Menu';             ID: RT_MENU),
                       (Name: 'Dialog';           ID: RT_DIALOG),
                       (Name: 'String';           ID: RT_STRING),
                       (Name: 'Fonts';            ID: RT_FONTDIR),
                       (Name: 'Font';             ID: RT_FONT),
                       (Name: 'Accelerator';      ID: RT_ACCELERATOR),
                       (Name: 'Data';             ID: RT_RCDATA),
                       (Name: 'Message Table';    ID: RT_MESSAGETABLE),
                       (Name: 'Group Cursor';     ID: RT_GROUP_CURSOR),
                       (Name: '#13';              ID: MakeIntResource(13)),
                       (Name: 'Group Icon';       ID: RT_GROUP_ICON),
                       (Name: '#15';              ID: MakeIntResource(15)),
                       (Name: 'Version';          ID: RT_VERSION),
                       (Name: 'Dialog';           ID: RT_DLGINCLUDE),
                       (Name: '#18';              ID: MakeIntResource(18)),
                       (Name: 'Plug And Play';    ID: RT_PLUGPLAY),
                       (Name: 'VXD';              ID: RT_VXD),
                       (Name: 'Animated Cursor';  ID: RT_ANICURSOR),
                       (Name: 'Animated Icon';    ID: RT_ANIICON),
                       (Name: 'Html';             ID: RT_HTML),
                       (Name: 'Manifest';         ID: RT_MANIFEST)
                    );

////////////////////////////////////////////////////////////////////////////////
//   PE Resource objects
////////////////////////////////////////////////////////////////////////////////
type

  // Resource object
  TPEResource       =  class(TObject)
  private
     // Private declarations
     FName:         PChar;
     FType:         PChar;
     FLanguages:    TList;
  protected
     // Protected declarations
     procedure      Load(Module: HMODULE);
     function       GetLanguages(Index: Integer): Word;
     function       GetLanguageCount: Integer;
  public
     // Public declarations
     constructor    Create(AModule: HMODULE; AName, AType: PChar);
     destructor     Destroy; override;
     property       Languages[Index: Integer]: Word read GetLanguages;
     property       LanguageCount: Integer read GetLanguageCount;
     property       ResName: PChar read FName;
     property       ResType: PChar read FType;
  end;

  // Resource group object
  TPEResourceGroup  =  class(TObject)
  private
     // Private declarations
     FType:         PChar;
     FResources:    TList;
  protected
     // Protected declarations
     procedure      Clear;
     procedure      Load(Module: HMODULE);
     procedure      Remove(Obj: TObject);
     function       GetResources(Index: Integer): TPEResource;
     function       GetResourceCount: Integer;
     function       GetResTypeName: String;
  public
     // Public declarations
     constructor    Create(AModule: HMODULE; AType: PChar);
     destructor     Destroy; override;
     function       Find(ResourceName: PChar): TPEResource;
     property       ResType: PChar read FType;
     property       ResTypeName: String read GetResTypeName;
     property       Resources[Index: Integer]: TPEResource read GetResources;
     property       ResourceCount: Integer read GetResourceCount;
  end;

  // Resource container
  TPEResources      =  class(TObject)
  private
     // Private declarations
     FLibFileName:  String;
     FGroups:       TList;
  protected
     // Protected declarations
     procedure      Clear;
     procedure      Load(LibFileName: String);
     function       GetGroupCount: Integer;
     function       GetGroups(Index: Integer): TPEResourceGroup;
  public
     // Public declarations
     constructor    Create(LibFileName: String);
     destructor     Destroy; override;
     function       Find(ResourceType, ResourceName: PChar): TPEResource;
     function       GroupByType(ResourceType: PChar): TPEResourceGroup;
     procedure      Remove(ResourceType, ResourceName: PChar);
     property       Groups[Index: Integer]: TPEResourceGroup read GetGroups;
     property       GroupCount: Integer read GetGroupCount;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   GetResourceTypeName(ResourceType: PChar): String;
function   GetResourceName(ResourceName: PChar): String;
function   IsIntResource(ResourceTypeOrName: PChar): Boolean;
procedure  KillResource(ExeFile: String; ResType, ResName: PChar; LangID: Word = 0);
function   ResAlloc(ResourceTypeOrName: PChar): PChar;
procedure  ResFree(ResourceTypeOrName: PChar);
function   ResCompare(ResourceTypeOrName1, ResourceTypeOrName2: PChar): Boolean;

implementation

//// Callback functions ////////////////////////////////////////////////////////
function EnumResLangProc(Module: HMODULE; lpszType, lpszName: PChar; wIDLanguage: Word; lParam: Pointer): BOOL; stdcall;
begin

  // Resource protection
  try
     // Cast lParam as resource object and add language
     TPEResource(lParam).FLanguages.Add(Pointer(wIDLanguage));
  finally
     // Keep enumerating
     result:=True;
  end;

end;

function EnumResNameProc(Module: HMODULE; lpszType, lpszName: PChar; lParam: Pointer): BOOL; stdcall;
begin

  // Resource protection
  try
     // Create new resource and add to list
     TPEResourceGroup(lParam).FResources.Add(TPEResource.Create(Module, lpszName, lpszType));
  finally
     // Keep enumerating
     result:=True;
  end;

end;

function EnumResTypeProc(Module: HMODULE; lpszType: PChar; lParam: Pointer): BOOL; stdcall;
begin

  // Resource protection
  try
     // Create new resource group and add to list
     TPEResources(lParam).FGroups.Add(TPEResourceGroup.Create(Module, lpszType));
  finally
     // Keep enumerating
     result:=True;
  end;

end;

//// TPEResource ///////////////////////////////////////////////////////////////
procedure TPEResource.Load(Module: HMODULE);
begin

  // Enumerate the languages
  EnumResourceLanguages(Module, FType, FName, @EnumResLangProc, Integer(Self));

end;

function TPEResource.GetLanguageCount: Integer;
begin

  // Return count of languages
  result:=FLanguages.Count;

end;

function TPEResource.GetLanguages(Index: Integer): Word;
begin

  // Return the langauge at the specified index
  result:=Word(FLanguages[Index]);

end;

constructor TPEResource.Create(AModule: HMODULE; AName, AType: PChar);
begin

  // Perform inherited
  inherited Create;

  // Set defaults
  FLanguages:=TList.Create;
  FName:=ResAlloc(AName);
  FType:=ResAlloc(AType);

  // Load
  Load(AModule);

end;

destructor TPEResource.Destroy;
begin

  // Resource protection
  try
     // Free the list
     FLanguages.Free;
     // Free allocated memory
     ResFree(FName);
     ResFree(FType);
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

//// TPEResourceGroup //////////////////////////////////////////////////////////
function TPEResourceGroup.Find(ResourceName: PChar): TPEResource;
var  lpResource:    TPEResource;
     dwIndex:       Integer;
begin

  // Set default result
  result:=nil;

  // Find the desired resource
  for dwIndex:=0 to Pred(FResources.Count) do
  begin
     // Access the resource
     lpResource:=GetResources(dwIndex);
     // Check the resource  name
     if ResCompare(ResourceName, lpResource.ResName) then
     begin
        // Match was found, return resource
        result:=lpResource;
        // Done processing
        break;
     end;
  end;

end;

procedure TPEResourceGroup.Remove(Obj: TObject);
begin

  // Check assignment
  if Assigned(Obj) and (FResources.IndexOf(Obj) >= 0) then
  begin
     // Resource protection
     try
        // Remove from list
        FResources.Remove(Obj);
     finally
        // Free the object
        Obj.Free;
     end;
  end;

end;

procedure TPEResourceGroup.Load(Module: HMODULE);
begin

  // Enumerate the resources for this type
  EnumResourceNames(Module, FType, @EnumResNameProc, LongInt(Self));

end;

procedure TPEResourceGroup.Clear;
var  dwIndex:       Integer;
begin

  // Resource protection
  try
     // Walk the resource list
     for dwIndex:=0 to Pred(FResources.Count) do
     begin
        // Free the resource
        TPEResource(FResources[dwIndex]).Free;
     end;
  finally
     // Clear the list
     FResources.Clear;
  end;

end;

function TPEResourceGroup.GetResources(Index: Integer): TPEResource;
begin

  // Return the resource at the specified index
  result:=TPEResource(FResources[Index]);

end;

function TPEResourceGroup.GetResourceCount: Integer;
begin

  // Return the count of resources
  result:=FResources.Count;

end;

function TPEResourceGroup.GetResTypeName: String;
begin

  // Return the stringifed name
  result:=GetResourceTypeName(FType);

end;

constructor TPEResourceGroup.Create(AModule: HMODULE; AType: PChar);
begin

  // Perform inherited
  inherited Create;

  // Set defaults
  FResources:=TList.Create;
  FType:=ResAlloc(AType);

  // Load
  Load(AModule);

end;

destructor TPEResourceGroup.Destroy;
begin

  // Resource protection
  try
     // Clear
     Clear;
     // Free the list
     FResources.Free;
     // Free allocated memory
     ResFree(FType);
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

//// TPEResources //////////////////////////////////////////////////////////////
procedure TPEResources.Remove(ResourceType, ResourceName: PChar);
var  lpGroup:       TPEResourceGroup;
     lpResource:    TPEResource;
     dwIndex:       Integer;
begin

  // Try to get the group
  lpGroup:=GroupByType(ResourceType);

  // Check result
  if Assigned(lpGroup) then
  begin
     // Have the group lookup the resource name
     lpResource:=lpGroup.Find(ResourceName);
     // Check result
     if Assigned(lpResource) then
     begin
        // Resource protection
        try
           // Remove all resources using the language values
           if (lpResource.LanguageCount = 0) then
              // No language, kill resource
              KillResource(FLibFileName, lpResource.ResType, lpResource.ResName, 0)
           else
           begin
              // Walk the languages
              for dwIndex:=0 to Pred(lpResource.LanguageCount) do
              begin
                 // Kill the resource based on language id
                 KillResource(FLibFileName, lpResource.ResType, lpResource.ResName, lpResource.Languages[dwIndex]);
              end;
           end;
        finally
           // Have the group free the resource object
           lpGroup.Remove(lpResource);
        end;
     end;
  end;

end;

function TPEResources.GroupByType(ResourceType: PChar): TPEResourceGroup;
var  lpGroup:       TPEResourceGroup;
     dwIndex:       Integer;
begin

  // Set default result
  result:=nil;

  // Find the desired group
  for dwIndex:=0 to Pred(FGroups.Count) do
  begin
     // Access the group
     lpGroup:=GetGroups(dwIndex);
     // Check the group
     if ResCompare(lpGroup.ResType, ResourceType) then
     begin
        // Set group result
        result:=lpGroup;
        // Done processing
        break;
     end;
  end;

end;

function TPEResources.Find(ResourceType, ResourceName: PChar): TPEResource;
var  lpGroup:       TPEResourceGroup;
     dwIndex:       Integer;
begin

  // Try to get the group
  lpGroup:=GroupByType(ResourceType);

  // Check result
  if Assigned(lpGroup) then
     // Have the group lookup the resource name
     result:=lpGroup.Find(ResourceName)
  else
     // Set default result
     result:=nil;

end;

procedure TPEResources.Clear;
var  dwIndex:       Integer;
begin

  // Resource protection
  try
     // Walk the groups list
     for dwIndex:=0 to Pred(FGroups.Count) do
     begin
        // Free the group
        TPEResourceGroup(FGroups[dwIndex]).Free;
     end;
  finally
     // Clear the list
     FGroups.Clear;
  end;

end;

procedure TPEResources.Load(LibFileName: String);
var  hMod:          HMODULE;
begin

  // Attempt to load the library
  hMod:=LoadLibraryEx(PChar(LibFileName), 0, LOAD_LIBRARY_AS_DATAFILE);

  // Check module handle
  if (hMod = 0) then
     // Failed to load
     RaiseLastWin32Error
  else
  begin
     // Resource protection
     try
        // Enumerate the resource types
        EnumResourceTypes(hMod, @EnumResTypeProc, LongInt(Self));
     finally
        // Free the library
        FreeLibrary(hMod);
     end;
  end;

end;

function TPEResources.GetGroupCount: Integer;
begin

  // Return the count of groups
  result:=FGroups.Count;

end;

function TPEResources.GetGroups(Index: Integer): TPEResourceGroup;
begin

  // Return the group at the specified index
  result:=TPEResourceGroup(FGroups[Index]);

end;

constructor TPEResources.Create(LibFileName: String);
begin

  // Perform inherited
  inherited Create;

  // Set defaults
  FGroups:=TList.Create;
  FLibFileName:=LibFileName;

  // Load the library / exe file
  Load(LibFileName);

end;

destructor TPEResources.Destroy;
begin

  // Resource protection
  try
     // Clear
     Clear;
     // Free the list
     FGroups.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

//// Utility functions /////////////////////////////////////////////////////////
function ResCompare(ResourceTypeOrName1, ResourceTypeOrName2: PChar): Boolean;
begin

  // Check the name for integer value
  if IsIntResource(ResourceTypeOrName1) then
     // Can only match if the second value is an integer as well
     result:=(IsIntResource(ResourceTypeOrName2) and (ResourceTypeOrName1 = ResourceTypeOrName2))
  // Check second value
  else if IsIntResource(ResourceTypeOrName2) then
     // Can only match if the first value is an integer as well
     result:=(IsIntResource(ResourceTypeOrName1) and (ResourceTypeOrName1 = ResourceTypeOrName2))
  else
     // Case insensitive compare
     result:=(StrIComp(ResourceTypeOrName1, ResourceTypeOrName2) = 0);

end;

function GetResourceName(ResourceName: PChar): String;
begin

  // Check the resource type
  if IsIntResource(ResourceName) then
     // Format as #NUMBER
     result:=Format('#%d', [Word(Pointer(ResourceName))])
  else
     // Return type name
     result:=ResourceName;

end;

function ResAlloc(ResourceTypeOrName: PChar): PChar;
begin

  // Check for int resource name
  if IsIntResource(ResourceTypeOrName) then
     // Return as is
     result:=ResourceTypeOrName
  else
     // Allocate and copy
     result:=StrCopy(AllocMem(Succ(StrLen(ResourceTypeOrName))), ResourceTypeOrName);

end;

procedure ResFree(ResourceTypeOrName: PChar);
begin

  // Check for int resource name
  if not(IsIntResource(ResourceTypeOrName)) then
  begin
     // Free allocated memory
     FreeMem(ResourceTypeOrName);
  end;

end;

function GetResourceTypeName(ResourceType: PChar): String;
var  wType:         Word;
begin

  // Check the resource type
  if IsIntResource(ResourceType) then
  begin
     // Get actual word value
     wType:=Word(Pointer(ResourceType));
     // Determine if predefined
     if (wType <= RT_MAX_PREDEFINE) then
        // Get name from static table
        result:=RT_PREDEFINED[wType].Name
     else
        // Format as #NUMBER
        result:=Format('#%d', [wType]);
  end
  else
     // Return type name
     result:=ResourceType;

end;

function IsIntResource(ResourceTypeOrName: PChar): Boolean;
begin

  // Determine if the resource type / name is actually a word value
  result:=((LongWord(Pointer(ResourceTypeOrName)) shr 16) = 0);

end;

procedure KillResource(ExeFile: String; ResType, ResName: PChar; LangID: Word = 0);
var  hUpdate:       THandle;
begin

  // Open file for resource updating
  hUpdate:=BeginUpdateResource(PChar(ExeFile), False);

  // Check handle
  if (hUpdate = 0) then
     // Raise error
     RaiseLastWin32Error
  // Remove resource
  else if UpdateResource(hUpdate, ResType, ResName, LangID, nil, 0) then
  begin
     // End the update
     if not(EndUpdateResource(hUpdate, False)) then RaiseLastWin32Error;
  end
  else
     // Raise error
     RaiseLastWin32Error

end;

end.

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Marc582Author Commented:
thx a lot
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.