Solved

BPW dll & Delphi2

Posted on 1998-09-02
9
375 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
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
Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

 
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

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

831 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