333
asked on
BPW dll & Delphi2
Hello
I try to load dll, writen in BP for Win 1.5, from my Delphi app. The code looks like this:
type
TMin = function (X, Y: Integer): Integer;far;
procedure TForm1.Button1Click(Sender : TObject);
var
LH:THandle;
M:TMin;
I:Integer;
begin
LH:=LoadLibrary('test.dll' );
if LH<32 then begin
ShowMessage('Error');
exit;
end;
@M:=GetProcAddress(LH,'Min ');
i:=M(2,1);
FreeLibrary(LH);
end;
It works fine, if it is Delphi dll, but if i try load BPW dll, LoadLibrary returns 0. Did anybody know how to do this or it's impossible because of some 16 & 32 bit stuff or something?
Thanx
AP
I try to load dll, writen in BP for Win 1.5, from my Delphi app. The code looks like this:
type
TMin = function (X, Y: Integer): Integer;far;
procedure TForm1.Button1Click(Sender
var
LH:THandle;
M:TMin;
I:Integer;
begin
LH:=LoadLibrary('test.dll'
if LH<32 then begin
ShowMessage('Error');
exit;
end;
@M:=GetProcAddress(LH,'Min
i:=M(2,1);
FreeLibrary(LH);
end;
It works fine, if it is Delphi dll, but if i try load BPW dll, LoadLibrary returns 0. Did anybody know how to do this or it's impossible because of some 16 & 32 bit stuff or something?
Thanx
AP
hi 333!
lately i was in need of a call to GetFreeSystemResources - 16bit func in USER.EXE; inter helped me with a nice piece of code which i put into a unit. i post it here so you haven't to spoil your points for the already answered question:
unit FreeRes;
{ Get free system resources in Windows 95.
For reasons unknown outside of Microsoft, the Win32 API
does not define the GetFreeSystemResources function.
The only way to get this information is to call a 16-bit
function in USER.EXE. You can try messing around with thunking,
but there's an easier way in Windows 95. (I don't know how
to do this in NT, though.)
This information comes from "Windows 95 System Programming Secrets"
by Matt Pietrek.
This unit provides the GetFreeSystemResources function
for Windows 95. See the Windows 3.1 API documentation
to learn more about this function.
Copyright © 1996 Tempest Software
You may use this software as part of an application program
without fee or royalty. Use this software at your own risk.
As free software, it is offered without guarantee.
}
interface
const
Gfsr_SystemResources = 0;
Gfsr_GdiResources = 1;
Gfsr_UserResources = 2;
function GetFreeSystemResources(Sys Resource: Word): Word;
implementation
uses SysUtils, Windows;
{ Undocumented Kernel32 calls. }
function LoadLibrary16(LibraryName: PChar): THandle; stdcall; external kernel32 index 35;
procedure FreeLibrary16(HInstance: THandle); stdcall; external kernel32 index 36;
function GetProcAddress16(Hinstance : THandle; ProcName: PChar): Pointer; stdcall; external kernel32 index 37;
procedure QT_Thunk; cdecl; external kernel32 name 'QT_Thunk';
{ Use global variables, so QT_Thunk does not trash them. }
var
hInst16: THandle;
GFSR: Pointer;
{ QT_Thunk needs a stack frame. }
{$StackFrames On}
{ Thunking call to 16-bit USER.EXE. The ThunkTrash argument
allocates space on the stack for QT_Thunk. }
function GetFreeSystemResources(Sys Resource: Word): Word;
var
ThunkTrash: array[0..$20] of Word;
begin
{ Prevent the optimizer from getting rid of ThunkTrash. }
ThunkTrash[0] := hInst16;
hInst16 := LoadLibrary16('user.exe');
if hInst16 < 32 then
raise Exception.Create('Cannot load USER.EXE');
{ Decrement the usage count. This doesn't really free the
library, since USER.EXE is always loaded. }
FreeLibrary16(hInst16);
{ Get the function pointer for the 16-bit function in USER.EXE. }
GFSR := GetProcAddress16(hInst16, 'GetFreeSystemResources');
if GFSR = nil then
raise Exception.Create('Cannot get address of GetFreeSystemResources');
{ Thunk down to USER.EXE. }
asm
push SysResource { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
end;
end.
i hope this helps a little bit, maybe you can adapt this.
regards,
Black Death.
lately i was in need of a call to GetFreeSystemResources - 16bit func in USER.EXE; inter helped me with a nice piece of code which i put into a unit. i post it here so you haven't to spoil your points for the already answered question:
unit FreeRes;
{ Get free system resources in Windows 95.
For reasons unknown outside of Microsoft, the Win32 API
does not define the GetFreeSystemResources function.
The only way to get this information is to call a 16-bit
function in USER.EXE. You can try messing around with thunking,
but there's an easier way in Windows 95. (I don't know how
to do this in NT, though.)
This information comes from "Windows 95 System Programming Secrets"
by Matt Pietrek.
This unit provides the GetFreeSystemResources function
for Windows 95. See the Windows 3.1 API documentation
to learn more about this function.
Copyright © 1996 Tempest Software
You may use this software as part of an application program
without fee or royalty. Use this software at your own risk.
As free software, it is offered without guarantee.
}
interface
const
Gfsr_SystemResources = 0;
Gfsr_GdiResources = 1;
Gfsr_UserResources = 2;
function GetFreeSystemResources(Sys
implementation
uses SysUtils, Windows;
{ Undocumented Kernel32 calls. }
function LoadLibrary16(LibraryName:
procedure FreeLibrary16(HInstance: THandle); stdcall; external kernel32 index 36;
function GetProcAddress16(Hinstance
procedure QT_Thunk; cdecl; external kernel32 name 'QT_Thunk';
{ Use global variables, so QT_Thunk does not trash them. }
var
hInst16: THandle;
GFSR: Pointer;
{ QT_Thunk needs a stack frame. }
{$StackFrames On}
{ Thunking call to 16-bit USER.EXE. The ThunkTrash argument
allocates space on the stack for QT_Thunk. }
function GetFreeSystemResources(Sys
var
ThunkTrash: array[0..$20] of Word;
begin
{ Prevent the optimizer from getting rid of ThunkTrash. }
ThunkTrash[0] := hInst16;
hInst16 := LoadLibrary16('user.exe');
if hInst16 < 32 then
raise Exception.Create('Cannot load USER.EXE');
{ Decrement the usage count. This doesn't really free the
library, since USER.EXE is always loaded. }
FreeLibrary16(hInst16);
{ Get the function pointer for the 16-bit function in USER.EXE. }
GFSR := GetProcAddress16(hInst16, 'GetFreeSystemResources');
if GFSR = nil then
raise Exception.Create('Cannot get address of GetFreeSystemResources');
{ Thunk down to USER.EXE. }
asm
push SysResource { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
end;
end.
i hope this helps a little bit, maybe you can adapt this.
regards,
Black Death.
ASKER
BlackDeath,
thanx for code.
I changed functions LoadLibrary, FreeLibrary and GetProcAddress to LoadLibrary16, FreeLibrary16 and GetProcAddress16. Now dll loads, GetProcAddress16 returns not nil, but at line
i:=M(2,1);
i get the 'Access violation at address...' error. What's wrong?
thanx for code.
I changed functions LoadLibrary, FreeLibrary and GetProcAddress to LoadLibrary16, FreeLibrary16 and GetProcAddress16. Now dll loads, GetProcAddress16 returns not nil, but at line
i:=M(2,1);
i get the 'Access violation at address...' error. What's wrong?
hm.
try to declare your variables
LH:THandle;
M:TMin;
I:Integer;
global, not local.
did you turn the stackframes on {$W+} ?
Black Death.
try to declare your variables
LH:THandle;
M:TMin;
I:Integer;
global, not local.
did you turn the stackframes on {$W+} ?
Black Death.
ASKER
Black Death,
yes i've tryed it in different ways, I also changed integer to longint but the error still the same. Maybe there is something in my BPW code?
library test;
function Min(X, Y: longint): longint;export;
begin
if X < Y then Min := X else Min := Y;
end;
exports
Min index 1;
begin
end.
yes i've tryed it in different ways, I also changed integer to longint but the error still the same. Maybe there is something in my BPW code?
library test;
function Min(X, Y: longint): longint;export;
begin
if X < Y then Min := X else Min := Y;
end;
exports
Min index 1;
begin
end.
you still use your old call.
look at this part of the unit:
{ Thunk down to USER.EXE. }
asm
push SysResource { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
the function call in your app should be similar:
push your parameters to the stack, load the pointer to your function into the edx-reg, *_CALL QT_THUNK_* and retrieve the result from the ax-reg.
this should work.
Black Death.
look at this part of the unit:
{ Thunk down to USER.EXE. }
asm
push SysResource { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
the function call in your app should be similar:
push your parameters to the stack, load the pointer to your function into the edx-reg, *_CALL QT_THUNK_* and retrieve the result from the ax-reg.
this should work.
Black Death.
ach, noch was:
i don't know bpw to well - but i think it must be possible to declare the func in your dll with convention "stdcall", "safecall", "cdecl" or "pascal".
in the first three cases, the parameters are handed over from right to left; with pascal it is from left to right (in sequence of declaration). i suggest you use "stdcall".
~~~~
the func and the call in your app should look somehow like this:
function CallMin(X, Y: Integer): Integer;
var
ThunkTrash: array[0..$20] of Word;
begin
{ Prevent the optimizer from getting rid of ThunkTrash. }
ThunkTrash[0] := hInst16;
hInst16 := LoadLibrary16('test.dll');
if hInst16 < 32 then
raise Exception.Create('Cannot load TEST.DLL');
{ Decrement the usage count. }
FreeLibrary16(hInst16);
{ Get the function pointer for the 16-bit function. }
GFSR := GetProcAddress16(hInst16, 'Min');
if GFSR = nil then
raise Exception.Create('Cannot get address of Min');
{ Thunk down to TEST.DLL. }
asm
push Y
push X { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
end;
.
i := CallMin(2, 1);
.
regards,
Black Death.
i don't know bpw to well - but i think it must be possible to declare the func in your dll with convention "stdcall", "safecall", "cdecl" or "pascal".
in the first three cases, the parameters are handed over from right to left; with pascal it is from left to right (in sequence of declaration). i suggest you use "stdcall".
~~~~
the func and the call in your app should look somehow like this:
function CallMin(X, Y: Integer): Integer;
var
ThunkTrash: array[0..$20] of Word;
begin
{ Prevent the optimizer from getting rid of ThunkTrash. }
ThunkTrash[0] := hInst16;
hInst16 := LoadLibrary16('test.dll');
if hInst16 < 32 then
raise Exception.Create('Cannot load TEST.DLL');
{ Decrement the usage count. }
FreeLibrary16(hInst16);
{ Get the function pointer for the 16-bit function. }
GFSR := GetProcAddress16(hInst16, 'Min');
if GFSR = nil then
raise Exception.Create('Cannot get address of Min');
{ Thunk down to TEST.DLL. }
asm
push Y
push X { push arguments }
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov Result, ax { save the result }
end;
end;
.
i := CallMin(2, 1);
.
regards,
Black Death.
ASKER
Yes!!!
It works!!!
Thanx BlackDeath.
Some comments to you:
1. I think that is not possible to declare the BPW func with 'stdcall' etc. (at least i can't do this (there was compiler error like 'begin expected')). But it works like stdcall.
2. Maybe it's just a mistake in your code, but FreeLibrary must be after GetProcAddress16.
So, thanx again and post your comment as answer, i'll give you the points.
AP
It works!!!
Thanx BlackDeath.
Some comments to you:
1. I think that is not possible to declare the BPW func with 'stdcall' etc. (at least i can't do this (there was compiler error like 'begin expected')). But it works like stdcall.
2. Maybe it's just a mistake in your code, but FreeLibrary must be after GetProcAddress16.
So, thanx again and post your comment as answer, i'll give you the points.
AP
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Slash/d003303