|
EDais :: Tutorials :: Using C++ DLL's in VB :: Chapter 5 Using the Win32 API in a C++ DLL At this point I'm assuming a little more knowledge of basic C++ syntax however I'll try to keep things as simple as possible so even without knowledge of C++ it can still be followed, a knowledge of the GDI API would be very useful though.
Again here we're returning a long representing the functions outcome.
Remember again that the condition has to go within parenthesis here and the "return" keyword actually quits the routine.
You'll see here that I've added curly braces after the "if" condition in the same way as round a function, this is because we're going to put more than one line within the block. VB does the same thing with If statements:
Or if multiple things need doing:
In C++ though this premise extends to most block structure such as loops however they must remain round method blocks.
Now we'll need an API "RECT" type to hold the area to draw in. Now, unlike VB we don't need to add definitions to the API declarations to use them, instead C++ uses what's known as header files which contain all the declarations for us. By default our DLL project was created with some of these headers already included including all the common GDI API's, however if you require use of a specific API then you can find the header that it's contained within by searching on the MSDN for the Method/Type name and looking for the header requirement at the bottom of the page. This is the requirement for the FillRect() API which we'll be using in a second: You'll see there that the header we need is "Windows.h" however if you then look at the top of the .cpp file you've been writing your code in you'll see the line:
The "#include" means insert everything from the following file here so in this case it's going to insert the contents of the file "stdafx.h" at the top of the project. If you have a look in file view for the project and open up stdafx.h then you'll see amongst other things the lines:
So we've already got the header file declared and don't need to re-include it.
You must get the parameters in the correct order, you can find the ordering of the parameters either by looking in the MSDN or by opposite clicking on the "RECT" keyword and going to it's definition where you'll find:
It may look a bit nasty but you can pretty much ignore the last line, which just set's up some aliases for the type depending on how it's being used. The important bit is the ordering of the elements within the type (In case you were unsure, this is the same as a UDT in VB) in this case left, top, right, bottom so this is how we must pass the elements to C++. You can also manually fill the type as follows if you choose as we would in VB:
We've already got the API declared so let's go ahead and call the FillRect() API to fill this DC with the selected colour. One thing to note here is that the second parameter of the call is actually a pointer to a rectangle structure so we must pass a pointer to our RECT structure rather than the structure itself, we do this by prefixing the variable name with an ampersand character:
We must now kill the brush object to prevent memory leaks which is done in exactly the same was as in VB:
Finally we'll not need to bother with the rest of the routine so just return 1 now to let the user know it was a success:
Let's have a look at the code so far:
So far so good, indeed you can actually test the routine now if you wish, just skip to the end of the chapter and grab the declaration and sample code for VB then call the function with both colours the same and you should get the picture box being filled with the solid colour.
We must remember to kill these when we're done tough, I quite often add the clean-up code as soon as I've created the objects so as to not forget but if you're following this tutorial then it shouldn't be a problem. Now we'll need a couple of variables to hold which brush we started the line on and which brush we should be drawing this checker in. There may be other ways of accomplishing this but this is how I've done this in the past before so I'll stick with it here too:
Finally we'll declare a RECT structure that we'll just re-use to set the area to fill:
Ok, let's set up the base loop structure now that will handle the drawing. The outer loop will iterate horizontally and deal with the first brush for the line, while the inner loop will iterate vertically and deal with which brush to draw each checker with.
Nothing too new apart from the loops have a "+=" in which simply means add the following value to this value, it's shorthand for addition to the same variable i.e:
Can also be written as:
It's also quicker this way since the compiler is optimised to deal with these faster than in the first statement.
However it's a bit clunky so I've stuck to the original method. The modulus version works as follows: 0 Mod 2 = 0 So at first we start off at 0, then add one and modulus divide by 2 to get 1, the next iteration adds 1 again to get 2 then modulus divides by 2 to get 0 so the number is swapped back and fourth. At this point, each time the inner loop runs, the ThisBrush variable is going to store the opposite brush than the first one used on the last line (Or 0 if it's the first iteration of the loop) so we'll just have to deal with swapping the brushes on this line only and not what happens on the next.
This simply set's the top left of the fill area to the current (X,Y) coordinate and sets the bottom left position to this coordinate offset by the size both horizontally and vertically. Now we must fill this checker with the current brush colour so we'll need to make a call to FillRect():
More strange syntax here again, this time there's a question mark in there too which means the same as an Iif() (Immediate-if) statement in VB. The syntax is:
However I usually put the condition in parenthesis to set it apart from the rest of the statement and adhere to C++'s normal if syntax.
So we've filled this checker now, all we need to do to finish this inner loop off is to swap the checker colour:
This uses the same syntax as in the outer loop when swapping the first brush for the line.
And return a value indicating success:
And that's all there is to it, after 5 and a half pages we have a finished checker routine, so let's see if it works in VB. First off add the function name to the function definition list so VB will be able to see it, then head over to VB and we'll add the new function header. The function header in C++ looks as follows:
So let's work our way through the header and write the corresponding VB version. "int" means it returns a Long as we know it ends in "As Long" and the function name is "CheckerDC" so we know it starts off with "Private Declare Function CheckerDC"
To demonstrate the routine at work we can simply add a picture box to the form then add this code:
When you run the application, you should have a PhotoShop-style transparency grid being drawn for you, if not then go back and check your code to make sure everything's working, if you get an error then run through all the checks in the previous chapters which should iron out the problems and you can also download my code and compare that to your own. I've included a couple of appendices at the end as a quick reference to some things you may need, all of this and a lot more is in the help files though |