B.3 Some CopyMemory Examples

only for RuBoard - do not distribute or recompile

B.3 Some CopyMemory Examples

When looking at the following examples, note the distinction between passing an argument by reference ( ByRef ) versus passing an argument by value ( ByVal ). Remember, when you pass an argument ByVal , you are passing the actual value. When you pass an argument ByRef (also designated by the absence of the ByRef keyword, since this is Visual Basic's default method of parameter passing), you are really passing a pointer to that value. Keep this in mind as you look at the following examples.

B.3.1 Example 1

 Private Type SomeUDT     Field1 As String * 256     Field2 As String * 256     Field3 As String * 256 End Type Public Sub CopyUDT(  )          Dim udtA As SomeUDT 'This is a user-defined type     Dim udtB As SomeUDT          udtA.Field1 = "Bill Purvis"     udtA.Field2 = "Chris Mercier"     udtA.Field3 = "Kelly Christopher"     CopyMemory udtB, udtA, Len(udtB) End Sub 

This example shows a nice way to a copy a user-defined type. This is much more efficient than doing the following:

 udtB.Field1 = udtA.Field1 udtB.Field2 = udtA.Field2 udtB.Field3 = udtA.Field3 

Examine the call to CopyMemory for a moment. Notice that both UDTs are passed by reference. In fact, UDTs will always be passed by reference. This is enforced by the compiler itself. So, essentially , there is nothing to remember here. If you forget that UDTs are always passed by reference, the compiler will remind you. Also, note that this example works because the members of the UDT are fixed-length strings. If they were not, chances are this code would cause a protection fault.

B.3.2 Example 2

In the previous example, we had direct access to both the source and destination variables (both UDTs were declared locally). But many times throughout the course of this book, we have had only the raw address to some value. This was the case in Chapter 8, when we created a data handler. The shell called the IDataObject::GetData method in our component and passed a pointer to a FORMATETC structure and a pointer to a STGMEDIUM structure:

 Public Sub IDataObject_GetData(ByVal pFmtEtc As FORMATETC, _                                 ByVal pmedium as STGMEDIUM)     Dim fmtEtc As FORMATETC          CopyMemory fmtEtc, ByVal pFmtEtc, Len(fmtEtc) . . . 

In this example, we are copying a FORMATETC structure from the address pFmtEtc into a local instance that we can directly address within the function. As you can see, fmtEtc , our local instance of FORMATETC, is passed to CopyMemory by reference. Remember that all UDTs are always passed by reference, so this is why we do this.

Our source parameter to CopyMemory , however, is being passed ByVal . Why? Think about this CopyMemory copies a specified amount of data from one address to another address. Well, the value of pFmtEtc is an address itself. It is the address from which we want to copy. So if we did this as:

 'This is wrong CopyMemory fmtEtc, pFmtEtc, Len(fmtEtc) 

we would be passing the address of an address! In other words, a pointer to a pointer. We want CopyMemory to copy data from the address specified by pFmtEtc ; therefore we pass it ByVal .

B.3.3 Example 3

This example is the exact opposite of Example 2 (as far as the direction of the copy). In this example, a pointer to some address far, far away is being passed into the function. The function then copies an Integer value to that address:

 Public Function Foo(ByVal pInteger As Long)     Dim nValue As Integer     nValue = 1138     CopyMemory ByVal pInteger, nValue, 2 End Function 

There are several things to note in this example. The first is that the parameter to the function is a pointer to an integer. Any address is always 4-bytes wide on a 32-bit machine. An Integer is 2-bytes wide. The moral of this story? It's really stupid to go around passing pointers to integers because they are bigger than the datatype itself. So keep in mind that this is just an example, okay?

Our destination in this example is pInteger . It is an address, so it needs to be passed ByVa l, as was stated in Section B.3.2. But nValue is passed by reference. Why? Well, nValue equals 1138. If we passed nValue ByVal , this would tell CopyMemory to copy 2 bytes from the address 1138 to the location pointed to by pInteger . Who knows what value is at the address 1138? This is not what we want. We want to copy the actual value, 1138, to the location pInteger ; therefore, it is passed by reference. This tells CopyMemory to copy 2 bytes of data from the address of nValue (which contains 1138) to the address pInteger .

Typically, though, you should not have to use any of the pointer functions when you are working with your day-to-day code. Consider, the SetWindowText API function:

 BOOL SetWindowText( HWND hWnd, LPCTSTR lpString); 

Parameter two is a pointer to a string, yet in Visual Basic this function is declared as follows :

 Public Declare Function SetWindowText _      Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, _      ByVal lpString As String) As Long 

Even though the function requires a pointer, we can pass a string to it directly from VB. This is because VB really handles passing the address of the string to the API function for us.

Even API calls that require UDTs, like GetWindowRect , allow us to pass a UDT directly to the function. This is because, once again, VB handles passing the address to the UDT for us. And this is the case for 99.9% of the coding you will do.

The point is, if you find yourself using these pointer functions, chances are, you are doing so unnecessarily. Nothing is worse for a developer than having to look at miles and miles of convoluted code. These pointer functions are only useful in the extreme cases where there is no other way to achieve the desired results. Consider the PROPSHEETPAGE structure (in IDL):

 typedef [public] long LPCSTRVB; typedef struct {           DWORD dwSize;           DWORD dwFlags;           HINSTANCE hInstance;           LPCSTRVB pszTemplate;           HICON hIcon;           LPCSTRVB pszTitle;           DLGPROC pfnDlgProc;           LPARAM lParam;           LPFNPSPCALLBACK pfnCallback;           long pcRefParent;           LPCTSTRVB pszHeaderTitle;           LPCTSTRVB pszHeaderSubTitle;     } PROPSHEETPAGE; 

The pszTitle member of this structure is really a Long valuean address. Without StrPtr , there is no way at all to provide the address of a string to populate this structure. This is a valid reason to use the function. This structure also contains a member called lParam , which is also a 4-byte value. By using ObjPtr , we can store the address of our object in this parameter. When this structure is passed back to us in a callback procedure, we are able to retrieve the reference and gain access back to our object. It's a very handy and very appropriate use of ObjPtr . And it's very rare, too, so you probably won't use it more than once or twice.

only for RuBoard - do not distribute or recompile

Visual Basic Shell Programming
Visual Basic Shell Programming
ISBN: B00007FY99
Year: 2000
Pages: 128

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net