edsynergy wrote:
> Here is a small function that extracts a string from a resource dll.
> Works fine when the resource is there, and I get an EResNotFound When
> one is not found. However when the code in the exception clause is run
> (on EResNotFound do Result:= blank;) it immetiately gives an AV. In
> fact it dos'nt matter what code I put in the exception I get the AV
> I cant see what the problem is 
> 
> Best wishe Ed.
> 
> function TformMainTasks.SetAnchorText(const ResString:string):string;
> var
>   ls:Tstringlist;
>   ms:TresourceStream;
>   h:Thandle;
> begin
> 
> try
>   h := LoadLibrary(pchar('strings.dll'));

Do not type-cast a string literal to PChar. The compiler already 
recognizes when a PChar is required. It only needs a hint like that when 
overload resolution might pick the wrong function. LoadLibrary isn't 
overloaded.

>   try
>     ms:=TresourceStream.Create(h,ResString, RT_RCDATA);
>     if ( Assigned(ms)) then

That conditional will never fail. The constructor of a class will never 
return nil. If there is a problem allocating an object, you'll get an 
exception, in which case no value gets assigned to the variable at all.

>       begin
>         try
>           ls:= TstringList.Create;
>           ms.Position:= 0;
>           ls.LoadFromStream(ms);
>           Result:= ls.Text;
>         finally
>           ls.Free;
>           // free resources
>         end;  // try/finally
>       End
>     Else Result:= blank;
>   except
>   on EResNotFound do Result:= blank;
>   end;  // try/except
> finally
>   ms.Free;
>   FreeLibrary(h);
> 
>       // free resources
> end;  // try/finally

Never ignore a compiler warning. In your code, you should have gotten 
warnings in the "finally" blocks suggesting that ls, ms, and h might not 
be initialized. The problem stems from misusing the try-finally block. A 
try-finally sequence should always have this structure:

AcquireResource;
try
   UseResource;
finally
   ReleaseResource;
end;

In your code, you enter the try-finally block and *then* you acquire a 
handle to the DLL, and it's even later before you acquire a 
TResourceStream object. You mustn't enter a try-finally block until 
you've successfully acquired the thing that the try-finally block is 
meant to protect.

Try this code instead:

function TFormMainTasks.SetAnchorText(const ResString: string): string;
var
   ls: TStringList;
   ms: TResourceStream;
   h: THandle;
begin
   h := LoadLibrary('strings.dll');
   Win32Check(h <> 0);
   try
     try
       ms := TResourceStream.Create(h, ResString, RT_RCDATA);
       try
         ls := TStringList.Create;
         try
           ls.LoadFromStream(ms);
           Result := ls.Text;
         finally
           ls.Free;
         end;
       finally
         ms.Free;
       end;
     except
       on EResNotFound do
         Result := blank;
     end;
   finally
     FreeLibrary(h);
   end;
end;

-- 
Rob

Reply via email to