Форум: "WinAPI";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];
ВнизFreeLibrary Найти похожие ветки
← →
ZHK © (2004-06-21 10:31) [0]Здравствуйте, Господа.
Попал в затруднительную ситуацию. Тупею. :-) Вот кусок кода:
procedure TForm1.Button3Click(Sender: TObject);
var
DialogCount:TDialogCount;
DialogName:TDialogName;
DialogDescription:TDialogDescription;
DialogExecute:TDialogExecute;
SetDatabaseList:TSetDatabaseList;
LH:THandle;
SQL:TStrings;
begin
// Form6.Execute;
LH:=LoadLibrary("dll\sql1\SQL1.dll");
@DialogCount := GetProcAddress(LH,"DialogCount");
@DialogName := GetProcAddress(LH,"DialogName");
@DialogDescription := GetProcAddress(LH,"DialogDescription");
@DialogExecute := GetProcAddress(LH,"DialogExecute");
@SetDatabaseList := GetProcAddress(LH,"SetDatabaseList");
if Assigned(SetDatabaseList) then
SetDatabaseList(PostgreSQLConnectionForm.ListBox1.Items);
SQL:=TStringList.Create;
if Assigned(DialogExecute) then
begin
DialogExecute(0,SQL);
if SQL.Count>0 then
RichEdit1.Lines.Assign(SQL);
end;
SQL.Free;
FreeLibrary(LH);
{
А вот тут-то и возникает ошибка Invalid Floating Point Operation.
При необходимости могу прислать полный проект DLL-ки. Мое мыло - eug_elizarov@mail.ru
}
end;
Кто чем может. :-)
← →
Игорь Шевченко © (2004-06-21 10:33) [1]где-то stdcall забыл объявить ?
← →
ZHK © (2004-06-21 10:51) [2]Да я его и не объявлял. Но ведь парни пишут, что для делфи это необязательно? Или как?
← →
ZHK © (2004-06-21 10:53) [3]А, собственно, и не помогло. :-(
← →
Игорь Шевченко © (2004-06-21 11:15) [4]
> Да я его и не объявлял. Но ведь парни пишут, что для делфи
> это необязательно? Или как?
Вот если бы ты привел объявления функций в DLL и в своей программе, наверное, было бы проще диагностировать ошибку...
← →
ZHK © (2004-06-21 11:44) [5]Вот библиотека:
library SQL1;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library"s USES clause AND your project"s (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
SysUtils,
Classes,
Billing in "Billing.pas" {Form1},
SQLTypes in "..\SQLTypes.pas";
{$R *.res}
const
DCount=1;
var
DialogNames:array[0..DCount-1] of String=("Âûáîðêà áèëëèíãà ïî íîìåðó àáîíåíòà"#0);
DialogDescriptions:array[0..DCount-1] of String=("Âûáîðêà áèëëèíãà ïî íîìåðó àáîíåíòà"#0);
DatabaseList:String;
function DialogsCount:Integer; stdcall;
begin
Result:=DCount;
end;
function DialogName(IndexOfDialog:Integer):PChar; stdcall;
begin
if (IndexOfDialog>=0) and (IndexOfDialog<DCount) then
begin
ReallocMem(Result,Length(DialogNames[IndexOfDialog]));
Move(DialogNames[IndexOfDialog][1],Result^,Length(DialogNames[IndexOfDialog]));
end
else
Result:=Nil;
end;
function DialogDescription(IndexOfDialog:Integer):PChar; stdcall;
begin
if (IndexOfDialog>=0) and (IndexOfDialog<DCount) then
begin
ReallocMem(Result,Length(DialogDescriptions[IndexOfDialog]));
Move(DialogDescriptions[IndexOfDialog][1],Result^,Length(DialogDescriptions[IndexOfDialog]));
end
else
Result:=Nil;
end;
function DialogExecute(Index:Integer;SQL:TStrings):Boolean; stdcall;
var
Form:TSQLForm;
DL:TStrings;
begin
case Index of
0:Form:=TForm1.Create(Nil)
else
Exit;
end;
DL:=TStringList.Create;
DL.Text:=DatabaseList;
Form.SetTableNames(DL);
DL.Free;
Result:=Form.Execute(SQL);
Form.Free;
end;
procedure SetDatabaseList(DatabaseNames:TStrings); stdcall;
begin
DatabaseList:=DatabaseNames.Text;
end;
exports
DialogsCount index 1,
DialogName index 2,
DialogDescription index 3,
DialogExecute index 4,
SetDatabaseList index 5;
begin
end.
А вот объявления типов в программе:
type
TDialogCount=function:Integer; stdcall;
TDialogName=function (IndexOfDialog:Integer):PChar; stdcall;
TDialogDescription=function (IndexOfDialog:Integer):PChar; stdcall;
TDialogExecute=function (Index:Integer;SQL:TStrings):Boolean; stdcall;
TSetDatabaseList=procedure (DatabaseNames:TStrings); stdcall;
← →
Думкин © (2004-06-21 11:51) [6]А комментарий вверху для красоты?
← →
Игорь Шевченко © (2004-06-21 11:57) [7]ShareMem
← →
ZHK © (2004-06-21 12:00) [8]Не-а, ShareMem тоже не катит...
← →
Думкин © (2004-06-21 12:04) [9]> [8] ZHK © (21.06.04 12:00)
В коде во всяком случае у тебя его нет, равно как и есть ыверенность его нет в программе основной, тем более расположенном так как указано в комментарии.
← →
Anatoly Podgoretsky © (2004-06-21 12:05) [10]Где и как его включил,
← →
ZHK © (2004-06-21 12:15) [11]
library SQL1;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library"s USES clause AND your project"s (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
ShareMem,
SysUtils,
Classes,
Billing in "Billing.pas" {Form1},
SQLTypes in "..\SQLTypes.pas";
Очевидно, что сделал что-то не так. Подскажите...
← →
Игорь Шевченко © (2004-06-21 12:24) [12]
> ShareMem must be the
> first unit in your library"s USES clause AND your project"s
> (select
> Project-View Source) USES clause
← →
ZHK © (2004-06-21 13:11) [13]Дык я ж его первым и поставил... А ошибка то не ушла... Да. И в модуле, где библиотека вызывается, он тоже первым стоит...
← →
Игорь Шевченко © (2004-06-21 13:15) [14]
> И в модуле, где библиотека вызывается, он тоже первым стоит...
Надо в .dpr
← →
Anatoly Podgoretsky © (2004-06-21 13:19) [15]Ты приведи сначала свои USES
← →
ZHK © (2004-06-21 13:26) [16]В library я уже выше привел, а в модуле вот такой:
unit SQLInput;
interface
uses
ShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls;
← →
panov © (2004-06-21 13:29) [17]см. Игорь Шевченко © (21.06.04 13:15) [14]
Нужно в файл проекта добавить первым в uses.
← →
Anatoly Podgoretsky © (2004-06-21 13:33) [18]ZHK © (21.06.04 13:26) [16]
Тебя же просилм все USES, не надо это делать по кускам.
← →
ZHK © (2004-06-21 13:56) [19]
> Anatoly Podgoretsky © (21.06.04 13:33) [18]
> ZHK © (21.06.04 13:26) [16]
> Тебя же просилм все USES, не надо это делать по кускам.
Наверное я что-то не понял. Все uses со ВСЕХ ВХОДЯЩИХ В ПРОЕКТ МОДУЛЕЙ?
← →
Игорь Шевченко © (2004-06-21 14:01) [20]uses от .dpr покажи :)
← →
ZHK © (2004-06-21 14:17) [21]
program SQLShell;
uses
Forms,
Windows,
MainUnit in "MainUnit.pas" {PostgreSQLConnectionForm},
Connection in "..\Useful\PGQuery\Connection.pas",
ResOut in "ResOut.pas" {ResOutForm},
SQLInput in "SQLInput.pas" {Form1},
TextForm in "TextForm.pas" {Form2},
DatabaseSel in "DatabaseSel.pas" {Form3},
Logged in "Logged.pas" {Form4},
Options in "Options.pas" {Form5},
LoadHd in "LoadHd.pas" {LoadHead},
SQLSelector in "SQLSelector.pas" {Form6},
LoadPages in "LoadPages.pas";
← →
Игорь Шевченко © (2004-06-21 14:24) [22]
>
> program SQLShell;
>
> uses
ShareMem,> Forms,
> Windows,
← →
ZHK © (2004-06-21 14:27) [23]А сейчас уже это выглядит вот так:
program SQLShell;
uses
ShareMem,
Forms,
Windows,
MainUnit in "MainUnit.pas" {PostgreSQLConnectionForm},
Connection in "..\Useful\PGQuery\Connection.pas",
ResOut in "ResOut.pas" {ResOutForm},
SQLInput in "SQLInput.pas" {Form1},
TextForm in "TextForm.pas" {Form2},
DatabaseSel in "DatabaseSel.pas" {Form3},
Logged in "Logged.pas" {Form4},
Options in "Options.pas" {Form5},
LoadHd in "LoadHd.pas" {LoadHead},
SQLSelector in "SQLSelector.pas" {Form6},
LoadPages in "LoadPages.pas";
После всех перетрубаций первый вызов функций загруженной библиотеки успешен, повторный вызов - приводит к ошибке Access violation...
А вообще вызов преобразился следующим образом:
procedure TForm1.Button3Click(Sender: TObject);
var
SQL:String;
begin
// Form6.Execute;
if LH=INVALID_HANDLE_VALUE then
begin
LH:=LoadLibrary("dll\sql1\SQL1.dll");
@DialogCount := GetProcAddress(LH,"DialogCount");
@DialogName := GetProcAddress(LH,"DialogName");
@DialogDescription := GetProcAddress(LH,"DialogDescription");
@DialogExecute := GetProcAddress(LH,"DialogExecute");
@SetDatabaseList := GetProcAddress(LH,"SetDatabaseList");
@DialogGetSQL := GetProcAddress(LH,"DialogGetSQL");
end;
if Assigned(SetDatabaseList) then
SetDatabaseList(PChar(PostgreSQLConnectionForm.ListBox1.Items.Text));
if Assigned(DialogExecute) then
if DialogExecute(0) then
begin
SQL:=String(DialogGetSQL(0));
RichEdit1.Lines.Text:=Trim(SQL);
end;
end;
и добавился тип:
TDialogGetSQL=function (Index:Integer):PChar;
← →
Игорь Шевченко © (2004-06-21 14:33) [24]
> TDialogGetSQL=function (Index:Integer):PChar;
stdcall не надо ?
← →
ZHK © (2004-06-21 14:40) [25]Надо, только не в этом дело. Я понял. :-) Я ж говорю - тупею.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
FH:THandle;
I:Integer;
begin
if CmdFileName<>"" then
begin
FH:=FileCreate(CmdFileName);
for I:=0 to Length(Cmd)-1 do
begin
FileWrite(FH,Z[1],1);
FileWrite(FH,Cmd[I][1],Length(Cmd[I]));
end;
FileClose(FH);
end;
if LH<>INVALID_HANDLE_VALUE then
begin
FreeLibrary(LH);
LH:=INVALID_HANDLE_VALUE;
//Вот этой строчки-то и не было.
end;
end;
То есть окно, закрываясь, выгружало библиотеку, а повторная загрузка - не производилась. Понятно, что обращаясь к несуществующей функции ошибка-то и происходила. :-) А ShareMem, насколько я понял, необходим только для правильной работы со строками. Если использовать PChar, как я это делал, то он не обязателен. Спасибо за помощь!
← →
Игорь Шевченко © (2004-06-21 14:43) [26]
> ShareMem, насколько я понял, необходим только для правильной
> работы со строками
И с классами, которые используют строки, например TStringList
← →
evvcom © (2004-06-22 00:07) [27]И еще:
const
INVALID_HANDLE_VALUE = DWORD(-1);
тогда как
LoadLibrary
If the function fails, the return value is NULL.
И изначально LH где-то нужно инициализировать в INVALID_HANDLE_VALUE. Лучше этого не делать и проверять на незагруженность библиотеки, сравнивая с 0, а не с -1.
← →
ZHK © (2004-06-22 09:16) [28]Спасибо, я знаю, чему равно значение INVALID_HANDLE_VALUE. А DWORD(-1) на самом деле не -1, а максимальное значение DWORD. Конечно же, это не совсем корректно, я согласен, но я не думаю что при моей жизни я когда нибудь достигну максимального значения хэндла, потому спокоен за этот код. А что до инициализации, то это делается просто:
var
LH:THandle=INVALID_HANDLE_VALUE;
Это спасает от многого.
← →
panov © (2004-06-22 11:12) [29]>ZHK © (22.06.04 09:16) [28]
var
LH:THandle=INVALID_HANDLE_VALUE;
Это спасает от многого.
var
LH:THandle=0;
if LH=0 then LoadLibrary(...)
спасает значительно лучше...
← →
evvcom © (2004-06-22 12:53) [30]
> на самом деле не -1, а максимальное значение DWORD
В двоичной арифметике - это одно и то же.
И все же внимательнее чти [27] и [29]
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.03 c