/*
ProgEx11 Can Compile As C Or C++ Program
We've reached the point where we can finally leave the C runtime functions
and start playing with the Win32 Api in both C and PowerBASIC. Why don't
we dabble at that for awhile, then fool around some with C++ isms.
A good understanding of memory addressing and C asciiz string minipulation
is a big help in working with the Win 32 Api because it is entirely C based.
Windows was largely created before C++ became very mature, so it extensively
uses techniques such as we've been exploring in the past ten C program
examples.
Lets start with a Win Api function now - one that really isn't needed in
PowerBASIC because PowerBASIC has a built in function for this functionality,
that is, obtaining the current directory. Below is the Win32 Api's
GetCurrentDirectory() function. We'll try to use it.
GetCurrentDirectory
The GetCurrentDirectory function retrieves the current directory for the
current process.
DWORD GetCurrentDirectory
(
DWORD nBufferLength, // size, in characters, of directory buffer
LPTSTR lpBuffer // pointer to buffer for current directory
);
Parameters
nBufferLength Specifies the length, in characters, of the buffer for the
current directory string. The buffer length must include
room for a terminating null character.
lpBuffer Pointer to the buffer for the current directory string.
This null-terminated string specifies the absolute path to
the current directory.
Return Values
If the function succeeds, the return value specifies the number of characters
written to the buffer, not including the terminating null character.
If the function fails, the return value is zero. To get extended error
information, call GetLastError.
If the buffer pointed to by lpBuffer is not large enough, the return value
specifies the required size of the buffer, including the number of bytes
necessary for a terminating null character.
------------------
The above help documentation from Microsoft is typical of all Win Api
functions and to my way of thinking is excellent. First comes the name of
the function and a very brief description of what it does. Following that is
a listing of the function, its return values and parameters.
If you've followed my discussions up to this point of C memory buffers,
allocating memory, and so forth, the above decsciption should make some sense
to you. What this function will do for you is return a string of characters
that represents the full path of the current directory, but before it can do
that it requires that you provide it with both a memory buffer into which it
can write the characters, and information on the size of that buffer. Given
this information it will either return the desired string to you plus its
length, or the length it needs if the buffer you supplied to it isn't large
enough.
*/
#include <windows.h> //this program won't work in Linux because of windows.h!!!
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
DWORD dwReturn; //Declare needed variables
char szBuffer[MAX_PATH]; //Allocate (easily) a buffer
//using MAX_PATH equate
dwReturn = GetCurrentDirectory(MAX_PATH,szBuffer); //Call Api Function
printf("MAX_PATH = %u\n", MAX_PATH); //Output results...
printf("dwReturn = %u\n", (unsigned int)dwReturn);
printf("szBuffer = %s\n", szBuffer);
printf("szBuffer = %u\n", (unsigned int)szBuffer);
printf("&szBuffer[0] = %u\n", (unsigned int)&szBuffer[0]);
getchar();
return EXIT_SUCCESS;
}
/* --output--
MAX_PATH = 260
dwReturn = 41
szBuffer = C:\Code\Dev-Cpp\Projects\CPrimer\ProgEx11
szBuffer = 2293328
&szBuffer[0] = 2293328
*/
/*
As you can see, when you follow the rules everything works out as predictably
as it should.
Here are some important little details that may or may not have occurred to
you. Note that there are two parameters to this function and of course a
return value. The first parameter could be described as an 'input' parameter
in that we put a value 'in' there for the function to retrieve internally for
its use. Of course, that parameter was the size of the buffer we were giving
it. However, the second parameter could very well be described as an
'output' parameter if we were to continue with the same naming logic as with
the first. We do put 'in' an address of a buffer for the function to use,
but the most important result we want from the function is returned to us
through this second parameter rather than through a function return value.
This is the case throughout the Win Api. Data is in the vast majority of
cases returned through output parameters of functions rather than through
function return values. Generally speaking, return values are used to return
success/failure codes or simple TRUE/FALSE values indicating whether the
function succeeded or failed.
The other point worth mentioning here is that we obtained the necessary
buffer to hold the character array in the easiest way possible; we simply
declared an uninitialized array at the top of the function large enough to
hold any string the operating system could throw at us. This largest size
might be Windows operating system dependent so an equate 'MAX_PATH' was used
in place of a hard coded number. We could have used malloc as with the last
example to obtain the memory, but in many cases its just easier to declare an
uninitialized array as done here and let the compiler allocate the memory
automatically at run time. There are cases however where this won't work;
then one must use malloc. However, if it will work as it does here one would
be foolish to do it the harder way.
Finally, note that our declaration of szBuffer looked like this...
char szBuffer[MAX_PATH];
szBuffer is indeed an array variable. C uses square brackets for array
variables and parentheses for enclosing function arguments. However, when we
placed szBuffer in the function call we just used the szBuffer term without
the brackets. This is because, as we've mentioned several times previously,
an array variable without the brackets is a pointer to the base address of
the allocation for the array, i.e., szBuffer = &szBuffer[0] (remember that
the '&' symbol is an operator in C that returns the address of whatever it is
prepended to and is analogous to Basic's Varptr() function - see ProgEx03).
And since GetCurrentDirectory() specifies a pointer parameter passing
mechanism - we need to pass the base address of the memory allocation to the
function.
Lets now turn to PowerBASIC and see how all this works there.
*/