Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access C global variable 'errno' from C#

Is it possible to access the "errno" variable in C# when P/Invoking? This is similar to Win32 GetLastError().

like image 806
joemoe Avatar asked Mar 21 '10 02:03

joemoe


People also ask

Can global variables be initialized in C?

In C language both the global and static variables must be initialized with constant values. This is because the values of these variables must be known before the execution starts. An error will be generated if the constant values are not provided for global and static variables.

What is the best way to declare and access a global variable?

The clean, reliable way to declare and define global variables is to use a header file to contain an extern declaration of the variable. The header is included by the one source file that defines the variable and by all the source files that reference the variable.

Can I use a global variable from another file C?

Every C file that wants to use a global variable declared in another file must either #include the appropriate header file or have its own declaration of the variable. Have the variable declared for real in one file only.


3 Answers

I'm fairly sure that there is a way, but it probably is a bad idea. How would you guarantee that the runtime has not called some CRT function during its internal processing that has affected the errno?

For the same reason, you should not call GetLastError directly either. The DllImportAttribute provides a SetLastError property so the runtime knows to immediately capture the last error and store it in a place that the managed code can read using Marshal.GetLastWin32Error.

I think the most robust thing you could do in this case is make a C DLL that performs both the actual C work and the capture of the errno. (Note that just writing a wrapper around the errno capture would still have the concerns mentioned above.)

like image 117
Jason Kresowaty Avatar answered Oct 03 '22 01:10

Jason Kresowaty


Yes, it is possible - GetLastError does exactly that. However, as binarycoder pointed out, you should not do this directly - instead, set SetLastError on your DllImport to have this performed and cached automatically (and to avoid multithreading problems or runtime-invoked functions modifying the errno value) - then, on invoking the P/Invoked function, check it's return status, and if it's showing an error condition - throw Win32Exception, which reads the value of last error automatically. Yes, even on Mono on Linux.

like image 21
skolima Avatar answered Oct 02 '22 23:10

skolima


The solution is to use SetLastError on DllImport. This will make the runtime save the last error so it can be accessed from Marshal.GetLastWin32Error.

There are two problems with calling GetLastError directly:

  • The runtime might do sometime after the PInvoke returns before you are able to get the last error
  • Multiple .NET threads can reside on the same native thread. This can result in 2 .NET threads doing PInvokes, native libraries not knowing any better, would then overwrite the last error. So thread A in .NET getting thread B's last error (potentially).
like image 35
earlNameless Avatar answered Oct 02 '22 23:10

earlNameless