Link to home
Start Free TrialLog in
Avatar of 333
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
Avatar of d003303
d003303

if your posted code is compiled in D2/3/4, i.e. a 32bit application, you cannot load 16bit libraries like this. You will have to use a mechanism called "flat thunking" to access routines in a 16bit module. I don't know exactly how that direction of thunking works, I only did it the other way round (generic thunking), called 32bit functions from a 16bit app.

Slash/d003303
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(SysResource: 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(SysResource: 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.
Avatar of 333

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?
hm.

try to declare your variables

 LH:THandle;
 M:TMin;
 I:Integer;

global, not local.
did you turn the stackframes on {$W+} ?

Black Death.


Avatar of 333

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.
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.
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.
Avatar of 333

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
ASKER CERTIFIED SOLUTION
Avatar of BlackDeath
BlackDeath

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial