"VB really can't think of the series." Every time I see the master's things to the wonderful place, I will shoot the case: "Wow, I can't think of it!". After many this kind of emotion, I found that as long as we move your brains, we can have something that I can't think of others. So I thought that I would like to share these things and share it with everyone, I hope to throw bricks to introduce more people who can't think about it. This series of articles visible: http://www.9cbs.net/develop/list_article.asp?author=adambear
VB really can't think of a series: VB pointer Sunflower Collection function pointer Keywords: VB, HCAK, pointer, function pointer, efficiency, array, object, sorting difficulty: Intermediate requirements: familiar with VB, understand basic sorting algorithms, will use VC better.
Introduction: I don't know what I feel after practicing this series of "VB pointer sunflower book". Is it feeling that the Collection is too high-minded, and less powerful moves. So, today this article will tell less, more move. However, please start learning from the internal strength method of the famous door, otherwise it will practice Jiuyin to practice into the nine-yin bone claw. Today, we focus on the actual application of function pointers. Next article, on the problem of strings, listen to the recommendations of 9CBS on the netizens on 9CBS, I don't want to write "VB string full Raiders", about the structure of BSTR, about calling API timing strings in Unicode and ANSI In the event of a conversion problem, please refer to the sixth chapter "Strings" in "Win32 API Programming With Visual Basic" in the MSDN's Partial Books. Today, let us forget the string, focus on the processing of the function pointer.
First, the function pointer addressof gets a function pointer within a VB, we can pass this function pointer to the API that needs to be called, which is to allow external programs to call functions inside the VB. However, the application of the function pointer in the VB is far from the application of C, because only how to pass on how to pass the function pointer to the API to achieve callback, do not point out a lot of magical functions, because VB is not encouraged With pointers, the function pointer is no exception. First let us use the way of use of the function pointer to classify. 1, callback. This is the most basic and most important feature. For example, the sub-derived technology introduced in the VB document, its core is two API: Setwindowlong and CallWindowProc. We can make the setWindowlong this API to replace the original window function pointer to its own function pointer and save the original window function pointer. Such a window message can be sent to our own function, and we can always call the previous window pointer to call the original window function with CallWindowProc to call the original window function. In this way, we can processed hookd messages without destroying the original window function. Specific processing, we should be very familiar, VB documents are also very clear. Here you need to pay attention to the CallWindowProc this API, which we will see it. Here we call callback to allow "external calls inside the function pointer". 2, inside the program. For example, in C we can pass the C function pointer as a parameter to a C function that requires a function pointer, such as the C library function QSort, which is still told, its statement is as follows: #define int (__cdecl * compare) (Const Void) * Elem1, const void * elem2) Void Qsort (void * base, size_t num, size_t width, compare pfNCompare); it requires a Compare type function pointer to compare two variables, so the sort function can call this function pointer To compare different types of variables, QSORT can sort different types of variable arrays. We said that this application is "function pointer from internal calls". 3, call the external function Maybe you will ask, use the API not to call the external function? Yes, but sometimes we still need to directly obtain a pointer to external functions. For example, if the DLL we need is dynamically loaded through loadLibrary, then get the function portal pointer we need, and then call the external function through this function pointer, this dynamically loaded DLL technology allows us to more flexibly call external functions. We call this way "From the internal call external function pointer" 4, it is not to say, that is, we can also control "function pointers from the external call". No, such as we can load multiple DLLs, pass the function pointers in one of the DLLs to another DLL. The "inside" and "outside" above are relatively (DLL actually still in the process), such classification helps us to talk about problems, please remember my classification, because later articles will also Use this classification to analyze the problem.
The function of the function pointer is not more than four ways. However, it is flexible in actual use. For example, in C inherits and polymorphism, the interface in the COM is a clever application called VTable function. Using a function pointer, you can make the process of processing more efficient and flexible. In addition to the first way, in the VB documentation, there is no introduction to other means, and it is clear that the function pointer that does not support "Basic to Basic" (that is, the second way to say), in fact, by certain Hack, the above four methods can be achieved. Today, let's take a look at how to implement the second way, because it is relatively simple, let's start with simple start. As for how to call external function pointers in VB, how to implement various function pointers in VTable interface function pointer jump tables, because this will involve COM internal principles, I will be detailed in detail. In fact, VB's documentation does not say wrong, VB does not support "Basic to Basic" function pointer, but we can achieve around a bend, that is, first from "Basic to API", then use the first way " Call internal function pointer "to" API to BASIC ", so that it has reached the second way from" Basic to Basic "purpose, this technology we can call it" forced callback ", only VB will have This weird technology. Speaking a bit winding, but think about the CallWindowProc in the window subtype, we can use CallWindowProc to force the external operating system to call our original saved window function pointer, and we can use it to force call us. Function pointer. Oh, before, I have to say less principle, how to talk about, now we will start learning the move! Consider our QSort that we support multi-key comparison in VB. Complete source code See this text support code, just give the function pointer application related code. 'Of course, CopyMemory doesn't have any anything. Declare Sub CopyMemory Lib "kernel32" Alias _ "RTLmoveMemory" (Byval Source As Long, _ Byval Numbytes As long) 'Hey, look at how CallWindowProc declaration is compared. Declare Function Compare Lib "user32" Alias _ "CallWindowProcA" (ByVal pfnCompare As Long, ByVal pElem1 As Long, _ ByVal pElem2 As Long, ByVal unused1 As Long, _ ByVal unused2 As Long) As Integer 'NOTE: ByVal xxxxx As Long, Remember! This is a standard pointer declaration method. 'Statement Needs to Compare Array Elements PUBLIC TYPE TEMPLOYEE NAME AS STRING SALARY AS CURRENCY END TYPE
'Let's take a look at our comparison function' first, press the salary, then compare Function CompareSaramE (Elem1 as temployee, _ unused1 as long, _ unused1 as long, _ unused2 as long) AS integer Dim Ret as integer Ret = SGN (ELM) AS INTEGER DIM RET AS Integer Ret = SGN ( Elem1.Salary - Elem2.Salary) If Ret = 0 then Ret = StrComp (Elem1.Name, Elem2.Name, vbTextCompare) End If CompareSalaryName = Ret End Function 'press Comparative name, salary then compare Function CompareNameSalary (elem1 As TEmployee _ ELEM2 AS TEMPLOYEE, _ Unused1 As long, _ unused2 as long) AS INTEGER DIM RET AS INTEGER RET = STRComp (elem1.name, elem2.name, vbtextcompare) if Ret = 0 THEN RET = SGN (Elem1.salary - Elem2 .Salary) end if comparenamesaSaSaSaSaSaSalary = RET END FUNCTION
Finally, let's take a look at our declaration of our ultimate QSort. SUB Qsort (Byval Arrayptr As Long, Byval Ncount As ", arrayptr above the first element of the first element required to sort arrays, Ncount is the number of elements of arrays, NeleMsize is every Element size, PFNCompare is our comparison function pointer. This statement is extremely similar to QSort in the C library function. Like C, we can pass the Basic's function pointer to the Basic's QSort function. The use method is as follows: DIM Employees (1 to 10000) AS TemPloyee 'assumes that the following calls are assigned to the Employees array. Call initArray () 'can now call our QSort to sort. Call Qsort (Employees), Ubound (Employees), _ lenb (Employees (1)), Addressof ComparesaTaMe), or first name, then Press Salary Call Qsort (Varptr (Employees (1)), Ubound (Employees), _ lenb (Employees (1)), Addressof ComparenamesaSaSaSaSaSaSaSaSaSalary, how do you already see the mystery here? As a quiz, can you now give the method of using a function pointer in QSORT? For example, we now have to compare the number I element of the array and the size of the JU elements by calling the function pointer. That's right, of course, to use the previous declaration of Compare (actually the CallWindowProc) API to force callbacks. The specific implementation is as follows: SUB Qsort (byval ncount as long, _ byval nlevute as ion, byval pfncompare as long) DIM I as long, J AS long 'here omitted the specific implementation of the rapid sorting algorithm, only Compare the method of two elements. IF Compare (PFNCompare, ArrayPtr (i - 1) * Nlemsize, _ arrayptr (j - 1) * Nlemsize, 0, 0)> 0 Then 'If the i-i element is quering than the jth element These two elements. End if End Sub
The move is over, do you understand? Let me simply explain the meaning of Compare above, which is very secreted using the CallWindowProc this API. This API needs five parameters. The first parameter is a normal function pointer. This API can call this function pointer immediately, and pass the last four long-type parameters of this API to the function pointed to this function pointer. That's why our comparison function must have four parameters, because the CallWindowProc This API requests the function pointer to which the pointer must comply with the WndProc function. WndProc is as follows: LRESULT (Callback * WPARAM, LRESULT, HWND, UINT, WPARAM, LPARAM above can correspond to the LONG type in VB, because the long type can be used as a pointer! Let's take a look at the workflow. When we use Addressof CompareSarame as a function pointer parameter to call QSort, QSort's PFNCompare is assigned to the function pointer of the Concord CompareSaSaME. At this time, call COMPARE to force the PFNCompare, which is equivalent to calling the following VB statement: Call CompareSaRyName (ArrayPtr (i - 1) * Nlemsize, _ arrayptr (j - 1) * NELEMSIZE, 0, 0) this is not Can the parameter type do not match the error? Is the first two parameters of CompareSaRaryName not TemPloyee type? Indeed, call in VB is not linen, because the type of VB does not allow such calls. However, this call is the callback of the API, and the VB cannot check the parameter type of the API callback function is a normal long value type or a structural pointer, so we can say that we will bypass the VB pair function parameters. Type check, we can declare this long-type parameter into any type of pointer, we declare what, VB thinks. Therefore, we should carefully use this technology, as the above will eventually pass it to the parameter "ArrayPtr (i - 1) * NELemsize" is just an address, VB will not check this address, it is always When this address is used as a TEMPLOYEE type pointer, if you accidentally use "ArrayPtr I * Nlemsize", then when I is the last element, we will cause memory to access the error, so we want to handle it in C. The pointer pays attention to the boundary problem. The smart application of the function pointer is already visible, but the methods described here have great limitations. Our functions must have four parameters, cleaner practices write a DLL in VC or Delphi, make More in compliance with the requirements of the API to achieve similar features similar to the CallWindowProc. I followed the internal implementation of CallWindowProc, it is necessary to do many work related to window messages, which are redundant in our application. In fact, enforcing the forced callback API only needs to put the latter parameters, and then Call first parameters, but several assembly instructions. It is precisely because of the limitations of CallWindowProc, we cannot use it to call external function pointers to implement the third function pointer call mode of the above.
To achieve the third way, Matt Curland masters provide a nightmare average HACK way, we have to construct an iUnknown interface in VB, add a new entrance after the three entrances of the vTable interface of the iunknown interface, in the new entrance Insert the machine code in the entrance, this machine code is to process the THIS pointer, and finally call us to the function pointer, this function pointer is not the same as the internal or external. I will talk about this method when we discuss the internal principles of COM. In addition, the sorting algorithm is a problem of seeing the benevolence, I originally thought that this article provides the best algorithm in this article, which is good, but it is impossible to have "best" in any case. This article provides a rapid sorting method implemented by various pointer techniques, which should be much faster than the same functionality, and more memory is much more. However, this has passed the rapid sorting algorithm that I have optimized, or I can't compare with shellsort, because the shellsort implementation is simple. From the theory of algorithm, Qsort should be better than shellsort average performance, but in VB, this is not necessarily (see this document, which also provides VBPJ a column of matching code shellsort, very good, this article is taken from This shellsort). However, it should be pointed out whether it is rapid sorting or shellsort here, it can also be greatly improved because they need a lot of copymemroy to copy data in realization (this is one of the shortcomings of the pointer in VB). In fact, we have a better way, that is, HACK's array structure, which is the SafeArray in COM automation, and we can place the pointer of each array element in the SafeArray in a long type, we can place the pointer of each array element in SafeArray. No copyMemroy, we only need to exchange elements in the long-type group to reach the purpose of switching the SafearRay array element pointer in real time. The data is not moved, and the movement is just a pointer, you can imagine that this is fast. In the next article, I will introduce this method in the "VB Pointer Sunflower Collection). Postscript: I am learning, so I am happy.