Callback example
Question
I have to call a function in my main prg from a DLL, and the only way to do
this seems to be to use callbacks. Does anyone have a source example of how
this can be done in Delphi?
Answer
A:
This is how I'm having a C++ DLL callback a Delphi procedure:
In Delphi:
----------
interface
var
callBackProc : TFarProc;
procedure delphiProc (const x: Pchar); export;
procedure setupDLL (p: pointer);
implementation
procedure setupDLL (p: Pointer); external 'MYDLL';
procedure delphiProc (const x: Pchar); { this is the procedure called back }
begin
...
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
...
callBackProc := makeProcInstance(@delphiProc, gInstance);
setupDLL (callBackProc);
...
end;
procedure TForm1.FormDestroy (Sender: TObject);
begin
...
freeProcInstance (callBackProc);
...
end;
In the C++ DLL:
---------------
static void CALLBACK (*saveProc)(char*);
void FAR _export pascal setupDLL (void CALLBACK (*func)(char*))
{
saveProc = func;
}
then, to call the Delphi proc from the C++ DLL, use:
(*saveProc)(msg); // where msg is a char*
You don't have to do the makeProcInstance or freeProcInstance where I've
shown them, you just need to make sure you do the makeProcInstance and setup
calls before the callback is used, and the freeProcInstance after the last
time the callback is used.
If your DLL is in Delphi, the code would be similar, except I don't remember
how to call a procedure in Delphi via a pointer to that procedure.
If your DLL is not in Delphi, make sure you keep aware of string/pchar
consistency.
A:
The syntax is the same. In the main prg you just add the keyword EXPORT to
each function you need to export, just as if in a .DLL. Near the end of the
.DPR file, just before the BEGIN keyword that defines the start of the main
program you add a section called EXPORTS where you list again the routine(s)
you want to make available for callbacks. The not so obvious but very important
step you must do is to compile the main prg with the compiler smart callbacks
option off. This is very important, as the routines in the main prg must be
able to access their own data.
Floating point trouble in DLLs
Question
Got problem using Floating point numbers in DLLs.
I wrote a DLL using C++. The function in C++ needed a float variable.
I send the Single variable in Delphi to the DLL Function.
I got a GPF error stating Invalid Opcode. Anyone can help?
Answer
A:
If you wrote both the DLL and the Delphi side, do not return floating point
values as the function return value. Instead, use a var parameter (a pointer or
reference parameter in C++)
to return values.
I am assuming that your DLL is compiled by M$ VC++. The reason
is that Borland and M$ use different ways of returning a floating point value.
Borland's C++ and Delphi might use the same way (in the Math Coprocessor stack)
but I'm not sure.
So, if you work with procedures instead of functions you should be OK.
BTW, do not use single or float precision. They may be changed by the
compiler. Use doubles.
VER.DLL functions
Question
Does anybody have any experience using the version-checking functions in
VER.DLL? The online help for this is clear as mud (to me at least). I'm
writing a simple setup routine (I have to write my own, because it does few
things I can't find in any of the available shareware installers) and need
to do version checking on a few shared DLLs.
Answer
A:
This isn't exactly what you are looking for, but it might be useful. I use
the version information in my "About" boxes, code is below. You may not have
to use the StringFileInfo block at all for simple version checking, but
instead get the info out of the root block (see the TVS_FIXEDFILEINFO
structure in the API help).
procedure TAboutBox.FormCreate(Sender: TObject);
var
VIHandle : LongInt;
VSize : LongInt;
VData : Pointer;
VVers : Pointer;
Len : Word;
FileName : String;
const
Prefix = '\StringFileInfo\040904E4\'; { Prejudiced to U.S. character set, if
I remember right }
function GetVerValue(Value : String) : String;
var
ItemName : String;
begin
ItemName := Prefix + Value + chr(0);
Result := '';
If VerQueryValue(VData,@ItemName[1],VVers,Len)
Then
If Len > 0
Then
Begin
If Len > 255
Then
Len := 255; { "Truncate" any long strings }
Move(VVers^, Result[1], Len);
Result[0] := Chr(Len);
End;
end;
begin
FileName := Application.EXEName + chr(0);
VSize := GetFileVersionInfoSize(@FileName[1], VIHandle);
If VIHandle <> 0
Then
Begin
GetMem(VData, VSize);
Try
If GetFileVersionInfo(@FileName[1], VIHandle, VSize, VData)
Then
Begin
{ At this point, I grab values from the StringFileInfo block,
but you could just as easily get values from the root
block using VerQueryValue }
ProductName.Caption := GetVerValue('ProductName');
Version.Caption := GetVerValue('ProductVersion');
Copyright.Caption := GetVerValue('LegalCopyright');
Comments.Caption := GetVerValue('FileDescription');
End;
Finally
FreeMem(VData, VSize);
End;
End;
end;
Uses in DLLs
Question
If I keep 'uses Forms;' in a formless DLL project, the compiled DLL file is
about 140kb. If I delete 'Forms' from the uses clause, it doesn't compile.
If I delete the whole uses clause, it compiles happily to about 2kb,
but occasionally the IDE complains about the lack of a uses clause.
Is it safe to have no uses clause?
The DLL at the moment is only an experiment, but I hope to use a DLL in my
program.
Answer
A:
You're not really following the proper syntax for a DLL. Here's
the way to do it right:
You need at least two files-- the library file and the source
code file:
Library file: mylib.dpr
library MyLib;
uses
MyCode in 'MYCODE.PAS';
exports
MyFunc index 1;
begin
end.
Source file: mycode.pas
unit MyCode;
interface
function MyFunc( MyParam: string ): string; export;
implementation
function MyFunc( MyParam: string ): string;
begin
Result := 'This was just an example!';
end;
end.
Follow this format and you can't miss... taken (loosely) from
the Delphi Developer's Guide from Borland Press/Sams Publishing.
CARDS.DLL
Question
I understand that every copy of windows comes with CARDS.DLL that
contains the cards as drawn in Microsoft card games. Does anybody
know function names of functions in this DLL ?
Answer
I'm afraid I don't know how the functions work and all, but I can give you
the names and ordinal numbers of the functions in the DLL:
0 Card Display Technology
5 CDTANIMATE
4 CDTTERM
3 CDTDRAWEXT
2 CDTDRAW
1 CDTINIT
A:
Thanks to Heath Ian Hunnicutt (heathh@cco.caltech.edu) for disassembling
CARDS.DLL and coming up with the basis for this documentation.
cards.h
#include "crd.h"
/*
* cdtInit: Initializes the cards module
*
* pdxCard: receives the width of the card
* pdyCard: receives the height of the card
* returns: success or failure
*/
BOOL FAR PASCAL cdtInit(int FAR *pdxCard, int FAR *pdyCard);
/*
* cdtDrawExt: Draw a card with specified extents (size)
*
* x, y: location to draw the card
* dx,dy: size to be drawn
* cd: card to be drawn
* mode: transfer mode
* returns: success or failure
*/
BOOL FAR PASCAL cdtDrawExt(HDC hdc, int x, int y, int dx, int dy,=20
int cd, int mode, DWORD rgbBgnd);
/*
* cdtDraw: Draw a card
*
* x, y: location to draw the card
* cd: card to be drawn
* mode: transfer mode
* returns: success or failure
*/
BOOL FAR PASCAL cdtDraw(HDC hdc, int x, int y, int cd, int mode,
DWORD rgbBgnd);
/*
* cdtTerm: terminates and cleans up the cards module
*/
void FAR PASCAL cdtTerm();
cdt.h
#define CLOADMAX 5
/* Command ids */
#define IDACLUBS 1
#define ID2CLUBS 2
#define ID3CLUBS 3
#define ID4CLUBS 4
#define ID5CLUBS 5
#define ID6CLUBS 6
#define ID7CLUBS 7
#define ID8CLUBS 8
#define ID9CLUBS 9
#define IDTCLUBS 10
#define IDJCLUBS 11
#define IDQCLUBS 12
#define IDKCLUBS 13
#define IDADIAMONDS 14
#define ID2DIAMONDS 15
#define ID3DIAMONDS 16
#define ID4DIAMONDS 17
#define ID5DIAMONDS 18
#define ID6DIAMONDS 19
#define ID7DIAMONDS 20
#define ID8DIAMONDS 21
#define ID9DIAMONDS 22
#define IDTDIAMONDS 23
#define IDJDIAMONDS 24
#define IDQDIAMONDS 25
#define IDKDIAMONDS 26
#define IDAHEARTS 27
#define ID2HEARTS 28
#define ID3HEARTS 29
#define ID4HEARTS 30
#define ID5HEARTS 31
#define ID6HEARTS 32
#define ID7HEARTS 33
#define ID8HEARTS 34
#define ID9HEARTS 35
#define IDTHEARTS 36
#define IDJHEARTS 37
#define IDQHEARTS 38
#define IDKHEARTS 39
#define IDASPADES 40
#define ID2SPADES 41
#define ID3SPADES 42
#define ID4SPADES 43
#define ID5SPADES 44
#define ID6SPADES 45
#define ID7SPADES 46
#define ID8SPADES 47
#define ID9SPADES 48
#define IDTSPADES 49
#define IDJSPADES 50
#define IDQSPADES 51
#define IDKSPADES 52
#define IDGHOST 53
#define IDFACEDOWN1 54
#define IDFACEDOWN2 55
#define IDFACEDOWN3 56
#define IDFACEDOWN4 57
#define IDFACEDOWN5 58
#define IDFACEDOWN6 59
#define IDFACEDOWN7 60
#define IDFACEDOWN8 61
#define IDFACEDOWN9 62
#define IDFACEDOWN10 63
#define IDFACEDOWN11 64
#define IDFACEDOWN12 65
#define IDFACEDOWNFIRST IDFACEDOWN1
#define IDFACEDOWNLAST IDFACEDOWN12
#define IDX 67
#define IDO 68
#define IDMAX IDDECK
/* internal IDs for animation */
#define IDASLIME1 678
#define IDASLIME2 679
#define IDAKASTL1 680
#define IDAFLIPE1 681
#define IDAFLIPE2 682
#define IDABROBOT1 683
#define IDABROBOT2 684
/* Red non-face card frame */
#define IDFRAME 999
#define FACEUP 0
#define FACEDOWN 1 /* for compatibility with old apps, use
IDFACEDOWNFIRST..IDFACEDOWNLAST */
#define HILITE 2
#define GHOST 3
#define REMOVE 4
#define INVISIBLEGHOST 5
#define DECKX 6
#define DECKO 7
crd.h
#include "cdt.h"
typedef int CD;
// CaRD struct, this is what a card be
typedef struct _crd {
unsigned cd : 15; // card # (1..52)
unsigned fUp : 1; // is this card up/down
PT pt; // upper-left corner of card
} CRD;
/* WARNING: Order of su's is assumed */
#define suClub 0
#define suDiamond 1
#define suHeart 2
#define suSpade 3
#define suMax 4
#define suFirst suClub
#define raAce 0
#define raDeuce 1
#define raTres 2
#define raFour 3
#define raFive 4
#define raSix 5
#define raSeven 6
#define raEight 7
#define raNine 8
#define raTen 9
#define raJack 10
#define raQueen 11
#define raKing 12
#define raMax 13
#define raNil 15
#define raFirst raAce
typedef int RA;
typedef int SU;
#define cdNil 0x3c
#define cIDFACEDOWN (IDFACEDOWNLAST-IDFACEDOWNFIRST+1)
#define SuFromCd(cd) ((cd)&0x03)
#define RaFromCd(cd) ((cd)>>2)
#define Cd(ra, su) (((ra)<<2)|(su))