Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.007 c
14-18963
VEG
2001-12-15 21:35
2002.02.07
Проблема при разработке графического компонента.


4-19025
Art
2001-11-18 18:06
2002.02.07
Как использовать ShellExecute?????


1-18891
Alex Uskov
2002-01-21 16:24
2002.02.07
Программирование ScanDisk-а


1-18801
UserL
2002-01-24 08:08
2002.02.07
TToolBar


1-18818
Filat
2002-01-24 16:08
2002.02.07
Как закрыть перед выходом из программы *.ini с использованием RxFormStorage?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский