Форум: "Основная";
Текущий архив: 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
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2002.02.07;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.006 c