C # How to define parameters when importing DLL is a headache. Especially for pointer-type parameters, I have some immature experience on this issue.
Take the getcomputername function as an example.
The function prototype is as follows:
Bool getcomputername (<br/> lptstr lpbuffer, <br/> lpdword lpnsize <br/> );
This lpbuffer is the next string pointer. In fact, no matter what type of pointer, Windows is a 32-bit unsigned integer, that is, an internal address, A function uses a pointer to write data to the memory space pointed to by the pointer.
When we call C #, we also need to pass a pointer to it and correspond to an allocated space.
The following code is used:
Using system. runtime. interopservices; <br/> [dllimport ("kernel32.dll")] <br/> static extern bool getcomputername (intptr P, ref int lpnsize ); <br/> // allocate space <br/> intptr P = marshal. allochglobal (128); <br/> // console. writeline (p); the pointer content is the memory address <br/> int Len = 128; </P> <p> getcomputername (p, ref Len ); </P> <p> // console. writeline (P ); the same as the previous content </P> <p> // The following is the key <br/> // P points to an unmanaged space that needs to be converted into a hosted space. string <br/> string STR = marshal. ptrtostringansi (p); </P> <p> console. writeline (STR );
In fact, C ++ calls are essentially the same. They all need to allocate space and pass the space address to the function. Only C # runs in the hosting environment, so reading the data allocated to the space must be specially processed. The simpler method is to use stringbuilder. Basically, it is the same as above, except that C # does a lot of work for you.
[Dllimport ("kernel32.dll")]
Static extern bool getcomputername (stringbuilder lpbuffer, ref int lpnsize );
The same is true for struct. The following struct is an example.
Bool getversionex (<br/> lposversioninfo lpversioninformation <br/>); </P> <p> typedef struct _ osversioninfo {<br/> DWORD dwosversioninfosize; <br/> DWORD dwmajorversion; <br/> DWORD dwminorversion; <br/> DWORD dwbuildnumber; <br/> DWORD dwplatformid; <br/> tchar szcsdversion [128]; <br/>} osversioninfo;
A parameter is a pointer to a struct. A function will fill all fields of the struct, and write different data to different locations in the memory space.
[Dllimport ("kernel32.dll", entrypoint = "getversionex")] <br/> static extern bool getversionex (intptr P); </P> <p> intptr Pv = marshal. allochglobal (148); <br/> marshal. writeint32 (PV, 148); <br/> If (getversionex (PV) <br/> console. writeline ("OK"); <br/> console. writeline ("majorversion:" + marshal. readint32 (PV, 4); <br/> console. writeline ("buildnumber:" + marshal. readint32 (PV, 12); <br/> console. writeline (marshal. ptrtostringansi (intptr) (Pv. toint32 () + 20); <br/>
According to the struct definition, there are 5 DWORD and a 128-bit char array. Therefore, we need to allocate 148-bit space to this struct. The first field of the struct is the size of the struct. We use marshal. writeint32 (PV, 148); size of the written struct (this is also a feature of the structure used by Windows API, that is, the size of most structs must be specified before being passed to the function .), Then execute the function. If the function returns normally, you can read data from the corresponding position according to the struct definition.
Marshal. readint32 (PV, 4); read the second integer majorversion, Marshal. readint32 (PV, 12); the fourth is buildnumber, Marshal. ptrtostringansi (intptr) (Pv. toint32 () + 20); the value after the five integers is csdversion.
I just want to analyze the mechanism. If I have learned the compilation, I will understand it very well.
The following is a common practice:
[Structlayout (layoutkind. sequential)] <br/> public struct osversioninfo <br/>{< br/> Public int osversioninfosize; <br/> Public int majorversion; <br/> Public int minorversion; <br/> Public int buildnumber; <br/> Public int platformid; <br/> [financialas (unmanagedtype. byvaltstr, sizeconst = 128)] <br/> Public String versionstring; <br/>}</P> <p> [dllimport ("kernel32.dll ", entrypoint = "getversionex")] <br/> static extern bool getversionex (ref osversioninfo osinfo); </P> <p> osversioninfo info = new osversioninfo (); <br/> // specify the size of the struct <br/> info. osversioninfosize = marshal. sizeof (typeof (osversioninfo); </P> <p> If (getversionex (ref info) <br/> console. writeline ("OK ");