Solved

BPW dll & Delphi2

Posted on 1998-09-02
9
400 Views
Last Modified: 2010-04-03
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
0
Comment
Question by:333
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
9 Comments
 
LVL 4

Expert Comment

by:d003303
ID: 1338510
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
0
 
LVL 1

Expert Comment

by:BlackDeath
ID: 1338511
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.
0
 
LVL 2

Author Comment

by:333
ID: 1338512
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?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Expert Comment

by:BlackDeath
ID: 1338513
hm.

try to declare your variables

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

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

Black Death.


0
 
LVL 2

Author Comment

by:333
ID: 1338514
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.
0
 
LVL 1

Expert Comment

by:BlackDeath
ID: 1338515
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.
0
 
LVL 1

Expert Comment

by:BlackDeath
ID: 1338516
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.
0
 
LVL 2

Author Comment

by:333
ID: 1338517
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
0
 
LVL 1

Accepted Solution

by:
BlackDeath earned 10 total points
ID: 1338518
fine, i'm glad it works.
have a nice day,

Black Death.

0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Suggested Courses
Course of the Month2 days, 18 hours left to enroll

622 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question