About "Callback" Function

xiaoxiao2021-03-06  40

1 What is a callback?

There is always a certain interface between the software module. From the call mode, they can be divided into three categories: synchronous call, callback, and asynchronous calls. Synchronous call is a blocking call, the call party must wait for the other party to return, it is a one-way call; the callback is a two-way call mode, that is, the called party is called when the interface is called. The other party's interface; asynchronous calls are a mechanism for similar messages or events, but its calling direction is just in contrast, and the interface is actively informing the client when receiving a message or something happens. Interface). The relationship between the callback and asynchronous calls is very close, usually we use the callback to realize the registration of asynchronous messages, and notifications of messages through asynchronous calls. Synchronous calls are the simplest, and the callback is often the basis of asynchronous calls, so we focus on the implementation of the callback mechanism in different software architectures.

For different types of languages ​​(such as structural language and object language), platform (Win32, JDK), or Corba, DCOM, WebService, customer and service, in addition to synchronization, there is a certain asynchronous notification mechanism, Let the service party (or interface provider) can actively inform the customer in some cases, while the callback is a simplest way to achieve asynchronous.

For a general structured language, callback can be achieved by callback function. The callback function is also a function or process, but it is a special function that is implemented by the calling party for use by the caller.

In the object-oriented language, the callback is implemented by an interface or abstract class. We make the class that implements this interface into a callback class, and the callback class is a callback object. For object languages ​​that are compatible with C or Object Pascal, it is also provided with the characteristics of the callback object, the callback method, but also compatible with the callback function mechanism of the process language.

The message mechanism of the Windows platform can also be regarded as an application of the callback, and we register the message processing function (ie the callback function) through the system provided, so that the purpose of receiving, processing the message. Since the API of the Windows platform is built with C language, we can think it is also a special case of the callback function.

For distributed component agent CORBA, there are various ways, such as callback, event service, notification service, etc. Event service and notification services are standard services for CORBA to handle asynchronous messages, and they are responsible for the processing, distribution, maintenance of messages. For some simple asynchronous processing, we can be implemented by a callback mechanism.

Below we focus on comparing representative language (C, Object Pascal) and architecture (CORBA) to analyze the implementation of the callback, the specific functions.

2 Power in the process language (c)

2.1 function pointer

The callback is implemented by a function pointer in the C language. By transmitting the address of the callback function to the modified function to achieve the callback. Therefore, to achieve a callback, you must first define a function pointer, please see the example below:

Void func (char * s); // Function prototype VOID (* pfunc) (char *); // function pointer

It can be seen that the definition of the function is very similar to the definition of the function pointer.

Generalization, in order to simplify the variable definition of the function pointer type, improve the readability of the program, we need to customize the function pointer type.

TypeDef void (* pcb) (char *);

The callback function can be called like a normal function, but only it is called a callback function when it is passed as a parameter to the called function.

Example of the modulous function:

Void getCallback (PCB Callback) {/ * do Something * /} User When calling the above function, you need to implement a PCB type callback function: void fcallback (char * s) {/ * do something * /} then, You can directly pass the FCallback as a variable to getCallback, getCallback (fcallback); if different values ​​are given to this parameter, the caller will call a function of different addresses. The assignment can occur when running, so that you can realize dynamic binding.

2.2 Parameter transfer rules

So far, we only discuss the function pointer and callback without paying attention to the compiler specification of ANSI C / C . Many compilers have several invoking specifications. For example, in Visual C , you can add _cDecl, _stdcall, or _pascal in front of the function type, indicate its call specification (default to _cDecl). C Builder also supports _fastcall call specification. Call specification affects the given function name generated by the compiler (from right to left or from left to right), stack cleaning responsibility (caller or called by caller) and parameter transfer mechanism (stack, CPU register, etc.) .

It is important to see that the call specification is part of the function type; the address cannot be assigned to the function pointer with an incompatible call specification. E.g:

// The modified function is parameter in int, with INT to return value __stdcall int callee (int);

// The call function is the function pointer as the parameter Void Caller ("__CDECL INT (* PTR) (int));

// In Phase P, I illegally operated illegal operation __cdecl int (* p) (int) = callee; // error

The types of pointers P and Callee () are not compatible because they have different call specifications. Therefore, it is not possible to assign the address of the caller to the pointer P, although the two have the same return value and the parameter column.

2.3 Application Examples

Among the C language standard library functions, the callback function is used to let the user customize the process. Such as common rapid sort functions, secondary search functions, etc.

Quick Sort Function Prototype:

Void Qsort (Void * Base, Size_t Nlem, Size_t Width, INT (_USERENTRY * FCMP) (const void *, const void *); two-point search function prototype: void * bsearch (const void * key, const void * base, size_t NELEM, SIZE_T WIDTH, INT (_USERENTRY * FCMP) (const void *, const void *);

Where FCMP is a variable of a callback function.

A specific example is given below:

#include #include

INT Sort_Function (const void * a, const void * b); int List [5] = {54, 21, 11, 67, 22};

INT main (void) {INT X;

Qsort ((void *) list, 5, sizeof (List [0]), sort_function; for (x = 0; x <5; x ) Printf ("% I / N", list [x]); return 0 }

INT Sort_Function (const void * a, const void * b) {return * (int *) a - * (int *) b;}

2.4 Delphi DEPHI DEPHI in the object-oriented language is the same as C , in order to maintain compatibility with process language PASCAL, it retains the previous structured characteristics while introducing an object-oriented mechanism. Therefore, there are two distinct modes of the callback, one is a structured function callback mode, one is an object-oriented interface mode.

2.4.1 callback function

Tune function type definition:

TYPE TCALCFUNC = Function (A: Integer; B: Integer): Integer;

Customize the implementation of the function according to the format of the callback function, such as

Function add (A: Integer; Integer): IntegerBegin Result: = A B; End; Function Sub (A: Integer; B: Integer): IntegerBegin Result: = A-B;

Callback

Function Calc (CALC: TCALCFUNC; A: Integer; B: Integer): Integer: INTEGER

Below, we can call these two functions in our program.

C: = Calc (add, a, b); // c = a bc: = CALC (SUB, A, B); // c = a-b

2.4.2 Tune Object

What is the callback object, which occasion is it used? First, let's compare it with the callback function, the callback function is a prototype that defines the function, and the function body is subjected to a dynamic application mode implemented by the third party. To achieve a callback function, we must clearly know how to: This function requires those parameters, returning what type of value. Similarly, a callback object is also an abstract class (ie, an interface) that defines the object interface, but there is no specific implementation. To implement a callback object, we must know: What methods do it need to implement, and what parameters in each method, what is the value needs to be returned.

Therefore, in the application mode of the callback object, we will use the interface. The interface can be understood as a class defined but not implemented, which can only be implemented by other classes by inheritance. The interfaces and COM interfaces in Delphi are similar, and all interfaces are inherited with IINTERFACE (equivalent to IUNKNOW) and to implement three basic methods queryinterface, _addref, and _Release.

Define an interface

TYPE ISHAPE = Interface (Iinterface) Procedure Draw; End

Implement a callback class

type TRect = class (TObject, IShape) protected function QueryInterface (const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public procedure Draw; end;

type TRound = class (TObject, IShape) protected function QueryInterface (const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public procedure Draw; end;

Use a callback object

Procedure myDraw; var shape: ishape; beginshape.draw; end; If the incoming object is TRECT, then draw a rectangle; if true, it is round. Users can also implement the ISHAPE interface according to their intentions, draw their own graphics:

MyDraw (TRECT.CREATE); MyDraw (Tround.create);

2.4.3 Torp Method

Callback Method can be seen as part of the callback object, and Delphi has the concept of callback method for Windows messages. In some cases, we don't need to implement the entire object in accordance with a given request, and as long as one of them can be implemented, this is what we will use the callback method.

The definition of the callback method is as follows:

TNOTIFYEVENT = procedure (sender: TOBJECT) OF Object; Tmyevent = Procedure (Sender: Tobject; EventId: Integer) OF Object;

TNOTIFYEVENT is the most commonly used callback method, form, and a lot of events in Delphi. If you click on events, shutdown events, TNOTIFYEVENT. The variable of the callback method is generally defined by the event attribute, such as the definition of the Create event of TCUSTOMForm:

Property Oncreate: TNotifyEvent Read Foncreate Write Foncreate Stored Isform

We can customize the event processor by assigning values ​​to event attribute variables.

User-defined objects (objects containing callback methods):

Type tcallback = class procedure clickfunc (sender: Tobject); end; procedure tcallback.clickfunc (sender: TOBJEC); Begin ShowMessage; END;

Form object:

TYPE TCUSTOMFRM = Class (TFORM) Public Procedure RegisterClickFunc (CB: Procedure (Sender: Tobject) OF Object); END;

Procedure TCUSTOMFRM..REGISTERCLICKFUNC (CB: TnotifyEvent); begin self.Onclick = Cb; end;

Instructions:

Var FRM: TCUSTOMFRM; Begin FRM: = tcustom; frM.registerClickFunc (TCALLBACK.CREATE (). clickfunc);

3 Application of callback in distributed calculation (CORBA)

3.1 Tune Interface Model

There are many kinds of Corba's messaging mechanism, such as callback interface, event service, and notification service. The principle of the callback interface is simple, CORBA customers and servers have dual roles, ie servers are also customer customers.

The reverse call of the callback interface is often performed simultaneously. If the callback interface is called multiple times, the callback interface becomes an asynchronous interface. Therefore, the callback interface often serves as an event registration in CORBA. When the client calls the registration function, the customer function is the callback function. In this call, the function is to achieve an asynchronous mechanism.

From the CORBA specification, we know that a CORBA interface has different performance forms in the server and the client. In the client generally uses the pile (STUB) file, the server is used to the frame (Skeleton) file, the interface size is defined by IDL . The introduction of the callback function makes the server and the client need to achieve a certain pile and framework. Below is the realization model of the callback interface: 3.1.1 Example

The following is given an interface file that uses a callback. The server needs to implement the framework of the Server interface, the client needs to implement the Callback framework:

Module CB {Interface Callback; Interface Server;

Interface Callback {Void Onevent (in long source, in long msg);}; interface server {long registercb (in callback cb); void unregisterCB (in long hcb);

The client first calls the server interface registcb by synchronizing, and is used to register the callback interface Callback. After receiving the request, the server will retain the interface reference. If some event needs to be notified to the client, the client's Onevent function is called, so that the other party will process in time.

Visual C function call mode

We know that there are several call methods to class, Pascal. C-type C is default unless special declarations. The two are different. Here we use examples:

1. __cdecl: C and C Default call mode example: Void INPUT (INT & M, INT & N); / * Equivalent to void __cdecl INPUT (INT & M, INT & N); * / The following is the corresponding assembly code: 00401068 Lea Eax , [EBP-8]; Take the [EBP-8] address (EBP-8), save the EAX 0040106B Push Eax; then press the 0040106C LEA ECX, [EBP-4]; take the [EBP-4] address (EBP- 4), save the ECX 0040106F PUSH ECX; then press the address (0040100A); then call the input function 00401075 Add ESP, 8; recovery stack From the process of calling the input function from the above: Before calling this function, press EBP-8, then press EBP-4, then call function input, and finally the Input function call is completed, use the ESP 8 recovery stack. It can be seen that the default function modification _cdecl in the C language is called, and the parameter stack is performed by the main call function and the stack is restored. Let's take a look at: What is address EBP-8 and EBP-4? In the VIEW of the VC, select Rebug Windows, then select Registers, display register variable, and then enter the value of EBP-8 and EBP-4 value (or directly input EBP-8 and -4) below the Memory below. Look at what the value is actually stored in these two addresses, it is actually the address of the variable N (EBP-8), M's address (EBP-4), which can be seen: in the main call function The stack and the order is from right to left. In addition, since the argument is a reference to the corresponding variable, it is also proved that the address (similar to pointer) is actually referenced. Summary: In C or C language calls, the default function modification _cdecl is made by the main call function, and the stack is restored. The stack order of the arguments is from right to left, and finally the stack recovery is made by the master function. Since the main adjustment function management stack, the changeable function can be implemented. In addition, the naming modification method is to add a next line (_) before the function. 2. WinAPI (actually Pascal, Callback, _stdcall) example: Void WinAPI INPUT (INT & M, INT & N); look at the compiletable code of the corresponding call: 00401068 LEA EAX, [EBP-8] 0040106B PUSH EAX0040106C LEA ECX, [EBP-4] 0040106F PUSH ECX00401070 Call @ ilt 5 (0040100A) From the process of calling the input function from the above: Before calling this function First, the stack EBP-8, then press EBP-4, then call the function input, after calling the function INPUT, no corresponding stack recovery work (call to other functions, so I don't list) the following The compilation code of the function itself: (actually this function is not big, but the assembly example is still big, everyone can only look at the front and after, the intermediate code is not related to this example)

39: void WINAPI Input (int & m, int & n) 40: {00401110 push ebp00401111 mov ebp, esp00401113 sub esp, 48h00401116 push ebx00401117 push esi00401118 push edi00401119 lea edi, [ebp-48h] 0040111C mov ecx, 12h00401121 mov eax, 0CCCCCCCCh00401126 rep Stos DWORD PTR [EDI] 41: Int S, I; 42: 43: While (1) 00401128 MOV Eax, 10040112D Test Eax, EAX0040112F JE Input 0C1H (004011D1) 44: {45: Printf ("/ NPLEase Input The first Number M: "); 00401135 Push Offset String" / NPLEASE INPUT The First Number M "... (004260B8) 0040113A Call Printf (00401530) 0040113F Add ESP, 446: Scanf ("% D ", & M); 00401142 MOV ECX , dword ptr [ebp 8] 00401145 push ecx00401146 push offset string "% d" (004260b4) 0040114B call scanf (004015f0) 00401150 add esp, 847: 48: if (m <1) continue; 00401153 mov edx, dword ptr [ EBP 8 ] 00401156 cmp dword ptr [edx], 100401159 jge Input 4Dh (0040115d) 0040115B jmp Input 18h (00401128) 49: printf ( "/ nPlease input the first number n:"); 0040115D push offset string "/ nPlease input the first number n "... (0042608c) 00401162 call printf (00401530) 00401167 add esp, 450: scanf ("% d ", & n); 0040116A mov eax, dword ptr [ebp 0Ch] 0040116D push eax0040116E push offset string" % D "(004260B4) 00401173 Call scanf (004015f0) 00401178 Add ESP, 851: 52: IF (n <1) Continue; 0040117B MOV ECX, DWORD PTR [EBP

0ch] 0040117E CMP DWORD PTR [ECX], 100401181 JGE INPUT 75H (00401185) 00401183 JMP INPUT 18H (00401128) 53:54: for (i = 1, s = 0; i <= n; i ) 00401185 MOV DWORD PTR [EBP-8], 10040118c MOV DWORD PTR [EBP-4], 000401193 JMP Input 8EH (0040119E) 00401195 MOV EDX, DWORD PTR [EBP-8] 00401198 Add EDX, 10040119B MOV DWORD PTR [EBP-8], EDX0040119E MOV EAX, DWORD PTR [EBP 0CH] 004011A1 MOV ECX, DWORD PTR [EBP-8] 004011A4 CMP ECX, DWORD PTR [EAX] 004011A6 JG INPUT 0A3H (004011B3) 55: S = S I; 004011A8 MOV EDX , DWORD PTR [EBP-4] 004011AB Add Edx, DWORD PTR [EBP-8] 004011AE MOV DWORD PTR [EBP-4], EDX004011B1 JMP INPUT 85H (00401195) 56: IF (m> = s) 004011B3 MOV EAX, DWORD PTR [EBP 8] 004011B6 MOV ECX, DWORD PTR [EAX] 004011B8 CMP ECX, DWORD PTR [EBP-4] 004011BB JL Input 0afh (004011BF) 57: Break; 00401 1BD JMP INPUT 0C1H (004011d1) 58: Else59: Printf ("M

Obviously, the stack is restored. Due to the 32-bit C , the variable address is 4 bytes (INT is also 4 bytes), so two addresses are 8 bytes. It can be seen that the stack is responsible for the stack in the main modulation function, and is responsible for restoring the stack in the called function. Therefore, the changeable function cannot be achieved because the called function cannot know the number of stacks in advance, but can be done in the main adjustment function, because the number of parameters is determined by the main adjustment function. Let's take another look, the two addresses of EBP-8 and EBP-4 actually store what values, the EBP-8 address is N, and EBP-4 is stored at the value of M. The description is also from right to left stack, perform parameter delivery. Summary: Responsible in the main adjustment function, responsible for popping the parameters in the stack in the called function and is responsible for restoring the stack. Therefore, the variable-gate function cannot be realized, and the parameter transmission is from right to left. In addition, the naming modification method is to add a downline (_) before the function, there is a symbol (@) after the function name, and the number of items accounting in the parameter in the parameter list (10), such as: Void INPUT (INT & M, INT & N), is modified: _input @ 8 For most API functions, the window message handler is used in callback, so before calling, the Motor will press the stack first, then the API function restores the stack. Such as: Push Edx Push EDI PUSH EAX PUSH EBX CALL GETDLGITEMTEXTA You can think about what these registers are stored?

Reference: The MSDN example is a Win32 Console disassembly code under Debug mode under VC6.0.

: After adding WNETGETUSER or WNETGETCONNECTION, Compile occurs, when link, LINK: ERROR LNK2001: Unresolved External Symbol ... Fatal Error LNK1120: 1 Unresolved Externals ..

Reply:

This error indicates that VC cannot find WnetGetUser functions when links, like this error is generally due to certain .lib files. You can choose "Project | Settings", add the required .lib files you need at the Object / Library Modules section of the Link tab. If you don't know which file is you want, you can use the Search tool to find the specified symbol in the VC's lib directory, for example, WnetGetuser in MPR.LIB. In the help of MSDN Library, each API function indicates the header files, library files, and applicable operating systems required for each API function. VC generally uses the MFC class library to program, in which case WinMain has been encapsulated in the MFC class library (in AppModul.cpp), you can't see it when programming. For MFC programs, general initialization work is not done in WinMain, but in CWINAPP: InitInstance.

转载请注明原文地址:https://www.9cbs.com/read-52490.html

New Post(0)