Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Объясните в чём ошибка (надеюсь не в ДНК ;) [D6, Win95/98, WinME]


Страницы:   1 2

Fellomena ©   (2002-01-21 11:30:00) 

Всем привет !
Кто может объяснить почему не получается грузить иконки из 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...


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

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


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

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


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

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 11:42:00) [4]

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

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


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

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

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


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

>Fellomena
у меня NT4 SP5.

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

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

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


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

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)


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

хотелось бы разъяснить, что такое 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(...);
...


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


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

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

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


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

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.



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

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


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

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


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

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

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


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

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

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

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


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

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

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

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


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

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


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

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

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


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

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


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

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


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

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо