Solved

BPW dll & Delphi2

Posted on 1998-09-02
9
363 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
  • 5
  • 3
9 Comments
 
LVL 4

Expert Comment

by:d003303
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 1

Expert Comment

by:BlackDeath
Comment Utility
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 2

Author Comment

by:333
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
fine, i'm glad it works.
have a nice day,

Black Death.

0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
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…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

728 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

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now