I. background
C # And the new technical solution Web Service are developed using a new language in the development of a new project. However, in the new project, some old modules need to be used, it is generally written in C, C ++, or Delphi. There are three available methods for developers to use the old module: first, rewrite the C or C ++ functions with C # completely, so that the entire project code is more unified and easy to maintain. However, although Microsoft and some books say how C # is close to C ++, it is still a very painful thing to rewrite, especially the pointer and memory operations in C ++; 2. encapsulate C or C ++ functions into com. It is convenient to call COM in C, only the conversion between the C or C ++ type and the com type needs to be processed during encapsulation, but it also has some trouble. In addition, the com needs to be registered, which may cause confusion when the number of registrations is too large; 3. encapsulate C or C ++ functions into a dynamic link library. The encapsulation process is simple and does not work much. Therefore, I decided to use the method of loading the dynamic link library to implement it. As a result, the question of how to call a custom dynamic link library in C # emerged. I searched for related topics online, I found an article calling the system API, but it does not explain how to solve this problem, and there is no detailed description on msdn. Based on this, I decided to start from a simple step by step to see if I could achieve my goal.
(Note: I am afraid of the trouble of rewriting here. The code I rewrite is a variable-length encryption algorithm function. There are more than 600 lines of code, and I am not familiar with the algorithm itself, there are too many pointer and memory operations in the algorithm. To ensure the algorithm is correct, the most feasible method is to move less code. Otherwise, as long as there is a slight error, it cannot be sure that the algorithm is compatible with the previous one)
Ii. Technical Implementation
Next let's take a look at how to gradually implement dynamic library loading and type Matching:
For the definition of function export in the dynamic link library, you can refer to the macro definition below:
# Define libexport_api extern "C" _ declspec (dllexport)
The first step is to start with a simple call and define a simple function, which only implements an integer addition sum:
Libexport_api int mysum (int A, int B) {return a + B ;}
C # define the import definition:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. auto, callingconvention = callingconvention. stdcall)] public static extern int mysum (int A, int B );
}
Call the test in C:
Int isum = refcomm. mysum (2, 3 );
Run the command and check that isum is 5. The call is correct. The first step is the completion of the test. It indicates that the custom dynamic link library function can be called in C.
Step 2: I have defined the string operation function (for simplicity, the previous function name is used) and the returned result is a string:
Libexport_api char * mysum (char * a, char * B) {sprintf (B, "% s", a) return ;}
C # define the import definition:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. auto, callingconvention = callingconvention. stdcall)] public static extern string mysum (string a, string B );
}
Call the test in C:
String strdest = "";
String strtmp = refcomm. mysum ("12345", strdest );
The strtmp value is 12345, but the strdest value is null.
When I modify the dynamic link library implementation, the returned result is string B:
Libexport_api char * mysum (char * a, char * B) {sprintf (B, "% s", a) return B ;}
Modify C # import definition and change string B to ref mode:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. auto, callingconvention = callingconvention. stdcall)] public static extern string mysum (string a, ref string B );
}
Call the test again in C:
String strdest = "";
String strtmp = refcomm. mysum ("12345", ref strdest );
The strtmp and strdest operations are incorrect. They contain invisible characters.
Modify the C # import definition and change charset from auto to ANSI:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. ANSI, callingconvention = callingconvention. stdcall)] public static extern string mysum (string a, string B );
}
Call the test again in C:
String strdest = "";
String strtmp = refcomm. mysum ("12345", ref strdest );
The strtmp value is 12345, but the strdest value is not assigned. The second step implements the function return string, but the output fails in the function exit parameter.
Modify C # import definition again, and change string B to reference (REF ):
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. ANSI, callingconvention = callingconvention. stdcall)] public static extern string mysum (string a, ref string B );
}
The call fails during running and cannot be continued.
Step 3: Modify the dynamic link library implementation and Change B to a double pointer:
Libexport_api char * mysum (char * a, char ** B) {sprintf (* B), "% s", a) return * B ;}
C # import definition:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. ANSI, callingconvention = callingconvention. stdcall)] public static extern string mysum (string a, ref string B );
}
Call the test in C:
String strdest = "";
String strtmp = refcomm. mysum ("12345", ref strdest );
The strtmp and strdest values are "12345" in the running result. The call is correct. The third step outputs the correct output result of function exit parameters.
Step 4: Modify the dynamic link library implementation to output Integer Parameters:
Libexport_api int mysum (int A, int B, int * c) {* c = a + B; return * C ;}
C # import definition:
Public class refcomm
{
[Dllimport ("libencrypt. DLL ", entrypoint =" mysum ", charset = charset. ANSI, callingconvention = callingconvention. stdcall)] public static extern int mysum (int A, int B, ref int C );
}
Call the test in C:
Int C = 0;
Int isum = refcomm. mysum (2, 3, ref C );
Run the command to check whether isum and C are both 5. The call is correct.
After the experiments in the above steps, I have basically mastered how to define the dynamic library function and how to define the import in C #. With this foundation, I soon implemented the call of the variable-length encryption function in C, so far.
Iii. Conclusion
In C #, call C ++ to compile the dynamic link library function. to export the parameter output, use a pointer. For strings, use a double pointer, for the C # import definition, you need to use the reference (REF) definition.
For function return values, the C # import definition must be consistent with the c ++ dynamic library function Declaration definition. Otherwise, function call may fail.
When defining the import, pay attention to the charset and callingconvention parameters. Otherwise, the call fails or the result is abnormal.
During running, the dynamic link library is placed in the directory of the C # program. Here I am a dynamic link library of C #, and the two dynamic link libraries are run in the same directory.