Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.02.07;
Скачать: [xml.tar.bz2];




Вниз

Объясните в чём ошибка (надеюсь не в ДНК ;) 


Fellomena   (2002-01-21 11:30) [0]

Всем привет !
Кто может объяснить почему не получается грузить иконки из dll, хотя загрузка строк происходит нормально,
что бы понятно всё было, привожу весь код:

************************************************ rc file start *********************************************
STRINGTABLE
BEGIN
21, "MyTheardString"
END
************************************************ rc file end *********************************************

Компилю его и получаю RES файл, далее пишу dll:

************************************************ DLL code start *********************************************
library RsDll3;

{$R mystrings.RES}
begin
end.
************************************************ DLL code end ***********************************************

Компилирую - получаю *.dll файл, далее в файле проекта:

************************************************ Project code start *****************************************
...
uses
...
var
Form1: TForm1;
hDLL : THandle;
...
implementation
procedure TForm1.Button1Click(Sender: TObject);
begin
hDll:=LoadLibraryEx("RsDll3.dll",0,LOAD_LIBRARY_AS_DATAFILE); {гружу библиотеку, как файл-ресурсов (ENTERY POIT отсутствует, как я поняла)}
if hDll <> 0 then Form1.Caption:=IntToStr(hDll) + " Loaded !!!";
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeLibrary(hDll);
FreeLibrary(hDll2);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
buf1: array [0..100] of Char;
begin
// вывод текста из RsDll3.dll
LoadString(hDll,21,@buf1,99); {указываю handle dll, загруженной в АП моей проги, где 21 - имя строки}
ShowMessage(String(buf1)); // всё работает нормально !!!
end;
...
************************************************ Project code end *******************************************

Далее делаю следующее: создаю новый rc файл (по правилам вроде - Resource Workshop-овские файлы раздраконила и посмотрела как надо,
на всякий случай):


************************************************ rc file start *********************************************
ICON1 ICON barsdi.ico
ICON2 ICON folder.ico
************************************************ rc file end *********************************************

Компилирую, получаю myicons.RES, далее DLL:


************************************************ DLL code start *********************************************
library RsDll2;
{$R myicons.RES}
begin
end.
************************************************ DLL code end ***********************************************

Получаю RsDll2.dll, далее в файле проекта:

************************************************ Project code start *****************************************
...
uses
...
var
Form1: TForm1;
hDLL2 : THandle;
...
implementation

procedure TForm1.Button3Click(Sender: TObject);
begin
hDll2:=LoadLibraryEx("RsDll2.dll",0,LOAD_LIBRARY_AS_DATAFILE);
if hDll2 <> 0 then Form1.Caption:=IntToStr(hDll2) + " Loaded 2 !!!"; // загрузка проходит нормально
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
и пробую следующие варианты - ничего не работает (иконка не меняется)
//Icon.Handle:=LoadIcon(hDll2, "ICON1");
//Form1.Icon.Handle:=LoadIcon(FindResource(hDll2, "ICON1", RT_ICON), "ICON1");
//Icon.Handle:=LoadResource(hDll2, FindResource(hDll2, "ICON1", RT_ICON));
ShowMessage(IntToStr(LoadIcon(hDll2, "ICON1"))); // LoadIcon возвращает null 8(
end;
...
************************************************ Project code end *****************************************

Я пробовала ещё несколько вариантов из SDK но ничего толкового не вышло, при Application.Icon.Handle:=LoadIcon(hDll2, "ICON!");
приложению присваевается иконка, предназначенная по умолчанию для такого типа приложений системой (это и понятно, если LoadIcon
возвращает null).
Объясните почему строковые ресурсы грузытся, а RT_ICON отказывается ?
И на кой ляд нужен этот грёбаный hInstance если есть Handle, однозначно определяющий окно/модуль/процесс да вообще всё что угодно ?
И если dll с ресурсами грузится в АП мого процесса (вернее процесс грузит dll ;) то почему я не могу указать в качестве hInstance
hInstanse моего приложения, ведь по идее оно содержит в себе то что мне надо... ???
Одним словом, мастера, разъясните ситуацию plz...



Fellomena   (2002-01-21 11:33) [1]

в первом примере TForm1.FormClose() - не из той сказки - sorry



IronHawk   (2002-01-21 11:41) [2]

Удали *.ехе файл и перекомпиль ...



Юрий Федоров   (2002-01-21 11:43) [3]

Единственное, что можно сказать наверняка :
в случае загрузки иконки их библиотеки нужно использовать не
hInstance, а Handle, который вернула LoadLibrary



Fellomena   (2002-01-21 11:52) [4]

2 IronHawk: а в чём прикол ? Разве при Ctrl+F9 не происходит полного перекомпелирования (новой сборки)?

2 Юрий Федоров: кто бы мне объяснил зачем вообще используют hInstance ? (HWND, ProcessID, Handle - с этим уже всё понятно 8)



Виктор Щербаков   (2002-01-21 12:08) [5]

Если внимательно почитать SDK:
"The LoadIcon function loads the specified icon resource from the executable (.EXE) file associated with an application instance.", то увидим, что LoadIcon не обязана грузить иконки из dll. :)



Fellomena   (2002-01-21 12:14) [6]

Виктор Щербаков: я допускаю, что ф-ия LoadIcon действительно грузит иконки только из exe файлов (хотя dll - по структуре от exe-ка отличается мало), ведь и ф-ия LoadResource не дала результата 8(



Геннадий   (2002-01-21 12:18) [7]

Интересно, а почему не создается экземпляр TIcon?
hinstance - это декскриптор приложения



Fellomena   (2002-01-21 12:37) [8]

2 Генадий:
Давайте быть повнимательнее к терминам:
Handle - дескриптор процесса (!);
hInstance - дескриптор модуля (!!!) - чувтсвуете разницу ?

А зачем мне TIcon создавать, ведь когда у меня в программе есть:
{$R myicons.RES}
то я просто делаю:
Icon.Handle:=LoadIcon(hInstance, "ICON1");
И всё работает, т.е. иконка благополучно изменяется.



Геннадий   (2002-01-21 12:58) [9]

hInstance - это именно декскриптор приложения, поэтому и является глобальной перменной.
И еще, почему обязательно все это дело из библиотеки грузить, зачем лишние движения?
По-моему проще из ресурса
{$R myicons.RES}



Fellomena   (2002-01-21 13:04) [10]

2 Генадий: не согласна - hInstance дескриптор модуля, и поэтому является глобальной переменной - тоже аргумент ;)

НАРОД: разъясните ситуацию !

Проще-то оно проще, но мне из dll интереснее - надо 8)



Виктор Щербаков   (2002-01-21 13:04) [11]

Во получилось...
Пишем в dll функцию.

function GetDllInst: Integer; stdcall;
begin
Result := hInstance;
end;

Из exe-шника её вызываем и подставляем возвращаемое ей значение в первый параметрти LoadIcon.



Fellomena   (2002-01-21 13:09) [12]

2 Виктор Щербаков:
спасибо - красивое решение 8)
Но моей задачей было использовать dll только в качестве хранилища ресурсов,- без ф-ий.

Вопрос в тему:
В С++ после создания RES файла можно линкером откомпилить его в dll с ключом /NOENTERY и тогда dll становится просто хранилищем ресурсов и не имеет точки входа.
Аналог в Delphi есть ?
И есть ли выигрышь при таком подходе ?
Ведь когда я гружу dll с помощью параметра LOAD_LIBRARY_AS_DATAFILE - ф-ии, даже если они перечисленны в exports dll будут недоступны...



Fellomena   (2002-01-21 14:25) [13]

Жду интересных идей...



gek   (2002-01-21 14:33) [14]

Попробуй здесь посмотреть
http://imc.misa.ac.ru/alexander/devel/tips/shell.htm#s5



DK   (2002-01-21 14:42) [15]

2Fellomena (21.01.02 14:25)
(Я уже где-то это писал, но меня не заметили :( )
К DLL обращаться не надо. функция вытаскивает все иконки из укзанного файла. Привожу текст всего юнита:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ShellAPI;

type
TForm1 = class(TForm)
IconList: TListView;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure FillIcons(FileName: string; IconBox: TListView);
var
I, M: Integer;
FIcon: TIcon;
begin
FIcon := TIcon.Create;
IconBox.LargeImages.Clear;
M := ExtractIcon(hInstance, PChar(FileName), $FFFFFFFF);
for I := 0 to M - 1 do begin
FIcon.Handle := ExtractIcon(hInstance, PChar(FileName), I);
IconBox.LargeImages.AddIcon(FIcon);
with IconBox.Items do begin
Add;
Item[I].Caption := IntToStr(I);
Item[I].ImageIndex := I;
end;
end;
FIcon.Destroy;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
FillIcons(Edit1.Text, IconList);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
IconList.LargeImages := TImageList.Create(IconList);
IconList.LargeImages.Width := 32;
IconList.LargeImages.Height := 32;
end;

end.




nikkie   (2002-01-21 15:25) [16]

>Fellomena
у меня на NT все работает...

проверил на win98 - не работает. загрузил через LoadLibrary вместо LoadLibraryEx - работает.



paul_shmakov   (2002-01-22 02:52) [17]

хотелось бы разъяснить, что такое HANDLE и HINSTANCE (он же HMODULE), а то чувствуется некоторое непонимание их различий.

HINSTANCE
------------------
главное отличие в том, что HINSTANCE - это адрес модуля в адресном пространстве нашего процесса. это может быть адрес самого нашего exe-шника (возвращается функцией GetModuleHandle(nil)), адреса загруженных dll (возвращаются, например, вызовами LoadLibrary("kernel32.dll") или GetModuleHandle("kernel32.dll")). в любом случае это именно адрес.
по значению HINSTANCE (HMODULE) можно одназначно идентифицировать некий, загруженный а адресное пространство процесса, модуль.
значение HINSTANCE имеет смысл только в пределах одного процесса - в другом процессе по этому адресу может быть загружено что-то другое.

кстати, тип HINSTANCE в windows.pas назван HINST, т.к. имя HINSTANCE уже занято под глобальную переменную.

HANDLE
-------------
HANDLE (дескриптор) - тоже предназначен для идентификации. но только не модулей, а объектов ядра системы. у каждого процесса есть таблица дескрипторов, а HANDLE - это индекс в таблице дескрипторов процесса. т.е. это всего лишь какое-либо простое значение (в англоязычной литературе говорят opaque) вроде 1, 2, 10, 15; а не адрес.
так как у каждого процесса таблица дескрипторов своя, то и значение HANDLE имеет смысл только в пределах одного процесса - если передать это значение другому процессу, то для него оно будет бесполезно (если такая функциональность все же нужна, то см. DuplicateHandle).

Заключение
------------------
таким образом, HANDLE и HINSTANCE предназначены совершенно для разных целей и идентифицируют абсолютно разные объекты. так уж получилось, что представляются они 4-х байтовым целым (DWORD), и поэтому их легко спутать или сконвертировать одно в другое. хотя, это абсолютно неверно. масло в огонь еще подливает функция GetModuleHandle, которая возвращает HINSTANCE, но содержит подстроку "Handle" в своем названии. ее следовало бы назвать GetModuleInstance.

так и Вы, Fellomena, ошибочно пишете:

var
hDLL2 : THandle; // должно быть HMODULE, а не THandle
begin
...
hDll2 := LoadLibraryEx(...);
...


надеюсь немного помог



Fellomena   (2002-01-22 10:24) [18]

2 DK: угу, этот способ я вчера выискала, по ссылке gek-а 8)

2 nikkie: А на каком NT если не секрет ? На W2k у меня не пошло 8(

2 paul_shmakov: спасибо за исчерпывающий ответ, именно это мне и нужно было:
hDLL2 : THandle; // должно быть HMODULE, а не THandle

Таким образом, я была права в своих высказываниях о HANDLE и HINSTANCE - я понимала их именно так, как сказал paul_shmakov, но
проблема заключалась в том, что я не знала, что
hDll2 := LoadLibraryEx(...);
вернёт HMODULE, а не Handle 8(

Всем огромное спасибо за дисскуссию !!! В споре рождается истина 8)



nikkie   (2002-01-22 11:24) [19]

>Fellomena
у меня NT4 SP5.

я жутко извиняюсь, но как замена THandle на HMODULE могла помочь? и то и другое - long, так что хоть горшком называй...

после замены THandle на HMODULE на Win98 по-прежнему не работает.

>paul_shmakov
>hDLL2 : THandle; // должно быть HMODULE, а не THandle
это поправка терминологическая, а не функциональная? или я чего-то не понимаю?



Fellomena   (2002-01-22 11:31) [20]

2 nikkie: у меня, к сожалению, нет возможности прямо сейчас проверить работоспособность кода 8(
Но если paul_shmakov рекомендовал данный вариант кода, то, как я думаю, он его проверил наверняка...

У кого help под рукой - гляньте что возвращает LoadLibraryEx (LoadLibrary возвращает, на сколько я помню указатель на точку входа в dll)



Виктор Щербаков   (2002-01-22 11:42) [21]

Надо было заменить LoadLibraryEx на LoadLibrary.
В этом случае работает (проверял на Win9x и на Win2k).

А как переменную объявлять - THandle, HMODULE или просто integer - без разницы. Всё равно LoadLibrary (и LoadLibraryEx) вернет целое число, смысл которого - HINSTANCE загруженной библиотеки.



paul_shmakov   (2002-01-22 15:06) [22]

2 Fellomena
Но если paul_shmakov рекомендовал данный вариант кода, то, как я думаю, он его проверил наверняка...

спасибо за доверие, но боюсь, что Вас разочарую. я говорил о том, что легко запутаться в HANDLE и HMODULE (HINST) и, например, написать такой код:

var
hMod: THandle;
begin
hMod := LoadLibrary(...); // или hMod := GetModuleHandle(...);
...
CloseHandle(hMod); // !!! ошибка !!! хотя переменная и имеет
// тип THandle, но на самом деле содержит
// значение HMODULE

и, естественно, компилятор это проглотит, т.к. и THandle, и HMODULE имеют тип DWORD.

я просто увидел споры насчет того, что такое THandle и HINST (HMODULE). вот и написал теорию.

к Вашей конкретной проблеме это, к сожалению, не относится. если Вы и замените THandle на HMODULE, то это будет правильно идеалогически, но ошибки не исправит.



Иван Шихалев   (2002-01-22 17:15) [23]

Я уже клал в кладовку IconExtractor. Там код точно работающий.



Иван Шихалев   (2002-01-22 18:52) [24]

http://delphi.mastak.ru/cgi-bin/download.pl?get=1004556220&n=2




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.02.07;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.79 MB
Время: 0.065 c
1-18888           Vaddya                2002-01-23 12:03  2002.02.07  
Создание ярлыка


4-19016           IgorBIK               2001-12-09 19:28  2002.02.07  
Как вывести потоковый звук?


6-18931           krimer                2001-11-10 17:52  2002.02.07  
pomoghite gde tut oshibka


3-18770           Вика                  2002-01-14 08:02  2002.02.07  
IB 5.6 , как сделать экпорт/импорт части таблицы через дискету?


14-18962          yuger                 2001-12-17 16:39  2002.02.07  
Как правильно организовать Trial версию программы?