[m-rev.] diff: implement io__set_environment_variable in C#

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Nov 14 23:21:59 AEDT 2003


Hi Pete,

I see you've been making great progress on the C# conversion --
thanks!

On 14-Nov-2003, Peter Ross <pro at missioncriticalit.com> wrote:
> Implement io__set_environment_variable in C#.
> 
> library/io.m:
> 	Call mercury.runtime.PInovke._putenv to set the environment
> 	variable.
> 
> runtime/mercury_dotnet.cs.in:
> 	Use pinvoke to call the Posix function _putenv.

_putenv() is not a Posix function.  The Posix function is named putenv().
The name _putenv() is, AFAIK, unique to Windows.

> 	This is defined in the runtime, rather than io.m because at a
> 	later date we will need to use configure to select the correct
> 	putenv for different platforms.

For .NET, it would be nicer to use run-time configuration, so that the
same binaries will work on different target platforms.

> +++ runtime/mercury_dotnet.cs.in	14 Nov 2003 10:52:52 -0000
...
> +class PInvoke {
> +    [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
> +    public static extern int _putenv(string env);
> +}

Because the name "_putenv" is Win32-specific, it shouldn't be used
in the interface here.  It would be better to have a public method
whose name does not depend on the OS.

Regarding runtime configuration, I mean something like this.
First, define separate classes for each API (Win32, Posix, etc.):

	class Win32 {
	    [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
	    public static extern int _putenv(string env);
	}

	class Posix {
	    [System.Runtime.InteropServices.DllImport("libc.so")]
	    public static extern int putenv(string env);
	}

Then, define a wrapper method which tries each one in turn,
until it finds one that doesn't throw an exception:

	class PInvoke {
	    public static int putenv(string env) {
	        try {
		    return Win32._putenv(env);
		} catch (...) {
		    return Posix.putenv(env);
		}
	    }
	}

This should work because calling an DllImport method whose library
can't be found should result in an exception.

This can be made more efficient by caching the results:

	class PInvoke {
	    enum API { Win32, Posix, Unknown };
	    static API supported_API = API.Unknown;
	    public static int putenv(string env) {
	        switch (supported_API) {
		case API.Win32:
		    return Win32._putenv(env);
		case API.Posix:
		    return Posix.putenv(env);
		default:
		    int result;
	            try {
		        result = Win32._putenv(env);
			supported_API = API.Win32;
		    } catch (...) {
		        try {
			    result = Posix.putenv(env);
			    supported_API = API.Posix;
			}
		    }
		    return result;
	    }
	}

This is all assuming that .NET implementations resolve DllImport declarations
lazily.  If they are resolved eagerly, then the references to msvcrt.dll
and libc.so might cause problems, because in most cases one of these two
files won't be around.   In that case, we might have to put the Win32 and
Posix classes in separate assemblies, and use reflection to dynamically
load those assemblies rather than having any direct references to them.
But hopefully that won't be needed.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list