OK here is the Quick but Lame Tutorial on DirectX COM interface and RapidQ
First make sure you know the abbreviations: API - application programming interface. How you talk with the operating system to get it to do what you program asks.
DLL - Dynamic Link Library an EXTERNAL file that contains machine code. Your program can use DLL to run Windows API. DLLs load in the same process space (memory area) as your program. You cannot compile a DLL into your program.
COM - Component Object Model. You never get a straight answer from M$. Basically, this is a standard to improve DLL. Once a COM is made it is standard and new versions will work with older programs. They are suited for C++ coding. It kind of turns DLLs into object oriented programming.
GUID - Globally Unique identifier. A 16-bye code that identifies a specific COM object. That is DirectDraw (one little piece of DirectX) has a GUID that is for a DirectDraw version. That way all new versions are known from old ones and other pieces of DirectX. You might remember the QOLEOBJECT example in which Microsoft Word has a GUID "{000209FE-0000-0000-C000-000000000046}" that thing has 16 bytes of hexadecimal codes.
POINTER - a variable that holds the memory address (location in computer memory) of a variable, User defined TYPE, a SUB, Func, etc. etc. A pointer tells you WHERE in memory your variable is. The contents of the memory address tells you WHAT the variable value is. RapidQ does not give you all pointers (see below) DIM a AS INTEGER DIM lp AS LONG A = 5 Lp = VARPTR(a) 'lp is now the pointer, it does not = 5!!! But a memory address.
The BASICs of DirectX ___________________ DirectX uses the COM interface. It is not the same as "OLE automation", which also uses a COM interface but with a different format.
Instead of calling one or many individual SUB/Func like this: Declare Function GetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long Declare Function GetForegroundWindow Lib "user32" Alias "GetForegroundWindow" () As Long Declare Function GetDC Lib "user32" Alias "GetDC" (hwnd As Long) As Long ..... on and on
You are going to have one a (or few) simple calls Here is the only call you need to start DirectDraw:
Declare Function DirectDrawCreate Lib "ddraw.dll" ALIAS "DirectDrawCreate" (ByVal lpGUID As Long, ByVal lplpDD As Long, ByVal pUnkOuter As Long) As Long
Wow, that was easy! Wrong....
What happens is this Function returns a POINTER TO A STRUCTURE, that can be used to IMPLEMENT the INTERFACE. This is explained later. Here is how you run it:
'test.bas......................................... $DEFINE LPDIRECTDRAW LONG ' variables of "LPxxxx" are pointers $DEFINE LPDIRECTDRAWSURFACE LONG 'use LONG for 32-bit windows $DEFINE IDirectDraw LPDIRECTDRAW $DEFINE HRESULT LONG 'handle for a return value $DEFINE DD_OK 0 'this checks if it ran OK 'The API to create our DirectDraw "OBJECT" Declare Function DirectDrawCreate Lib "ddraw.dll" ALIAS "DirectDrawCreate"_ (ByVal lpGUID As Long, ByVal lplpDD As Long, ByVal pUnkOuter As Long) As Long
DIM result AS HRESULT DIM lpDD AS LPDIRECTDRAW 'our pointer lpDD = 0 'null it out result = DirectDrawCreate(0, @lpDD,0) 'get the pointer to the interface 'first parameter is 0, which is the default active display 'second parm passes the Pointer of lpDD using the '@' symbol to the FUNCTION 'last parameter must be 0 for 'future expansion' by windows
IF result <> DD_OK THEN ShowMessage "Create direct draw Failed" ELSE ShowMessage STR$(lpDD) END IF 'end of program..............................
This program actually runs and returns a large number in lpDD. This is the starting address of the INTERFACE. IF you run it, you cannot close down the directDraw interface because you are supposed to RELEASE it, so windows can use the memory Here is the c code: lpDD->Release(); You can't do it in RapidQ, yet. So if you run the program you just used up some memory...
With the line result = DirectDrawCreate(0, @lpDD,0) We now a POINTER TO A STRUCTURE, the pointer is lpDD !! But how do we start calling the DirectDraw functions? You need to declare the structure and then use that pointer to the stucture. You know what a structure is (use TYPE or STRUCT) TYPE MyType A AS LONG B AS LONG C AS LONG D AS LONG (etc....) END TYPE
In COM you would get the pointer of the structure, then the next variable (MyType.a) would hold the address of the next METHOD (like a SUB or FUNCTION), then the next variable holds the next METHOD address and so on. The important part is that this type is really a table of pointers to subs and functions. The code for a SUB or FUNCTION sits in some memory address space in the computer. The program knows where that code is by a pointer. Pointers are only numbers, and for Windows 32-bit, the pointer is of a LONG type. The pointer holds the memory address of the starting location of the code. So if you know the value of the pointer, you can "jump" that memory location and run the code in that "process space." Before you can run that code, the program must know how many, and what type of parameters there are to run the code.
For the example above, once you DIM some variable as MyType then you can start calling methods like this Result = MyType.a(x as integer, y as integer) You should see how this would work for lots of things in RapidQ like QFORM, QBUTTON, etc.
There is a command called BIND in RapidQ that should do this for you but IT DOES NOT WORK THIS way. Instead it keeps its own internal structure that you can't change. So there is a way to get it to work under rapidq but we need a DLL that can CALL the address and put the right number of parameters in the STACK.
Then what does the DirectDraw structure look like and how does the compiler know how to keep all those parameters straight?
All DIRECTX and Direct3D INTERFACES start with three methods. Implementing them in RapidQ would be something like this:
'Example above get the interface base address result = DirectDrawCreate(0, @lpDD,0) 'get the pointer to the interface
TYPE IUnknown EXTENDS QOBJECT PUBLIC: DIM lpDD AS LONG 'interface base pointer address 'the address is passed to lpDD DIM InterfaceOffset AS LONG 'call base address + offset FUNCTION QueryInterface(BYVAL lpIUnknown AS LONG, _ riid AS STRING * 16, ppvObj AS LONG) AS LONG InterfaceOffset = 0 CALLFUNC(lpDD+ InterfaceOffset, lpIUnknown, riid, ppvObj)
FUNCTION AddRef(BYVAL lpIUnknown AS LONG) AS LONG InterfaceOffset = 4 CALLFUNC(lpDD+ InterfaceOffset, lpIUnknown)
FUNCTION Release(BYVAL lpIUnknown AS LONG) AS LONG InterfaceOffset = 8 CALLFUNC(lpDD+ InterfaceOffset, lpIUnknown) END TYPE
So on and so on. The file DDRAW_001.INC shows the start of directX development in RQ. ...
|
|