Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"ignoring" P/Invoke when running on Mono

I have a WinForms Application that I want to run at Mono at some point. However, it is using some P/Invoke against user32.dll, which will cause an obvious problems.

However, this is not a critical functionality, just some flavor stuff. So I would like to ignore it when running Mono.

I know I could just use an #if directive, but then I have to offer two different assemblies, which is bad. I know I can check on Runtime if I am running in Mono, but that won't help me removing the declarations to the functions.

So I wonder: Is there a way where I can say "If running Mono, ignore this completely"? If it helps: The P/Invoke stuff is in a separate .cs file and implemented as a Partial Class.

The source code in question is here: http://pastie.org/588940
It is part of my Main Form, overriding the WndProc message to add an item to the system menu. (Some other stuff snipped). My problem is that while the WndProc stuff is easy, I do not know what to do with the two private extern declarations - can I put them into another (static) class that I just never call on Mono? Or would that be russian roulette?

like image 331
Michael Stum Avatar asked Aug 19 '09 19:08

Michael Stum


3 Answers

Checking the runtime seems like a viable solution. Is there any reason you would like to remove the P/Invoke function declarations if running under Mono even if they are never used?

like image 34
Darin Dimitrov Avatar answered Sep 24 '22 07:09

Darin Dimitrov


Why not encapsulate the platform-dependent stuff in an interface, then have some way of getting the "right" implementation for the current platform. Then the calling code can use it blithely, and you can gradually fill in bits to run on Mono as and when you want. I would at least hope that if you never even load the class containing the P/Invoke bits, you should be okay...

EDIT:

I don't see why this approach shouldn't work, although you may not even need the factory. Here's what I'd do:

MainForm.cs:

PlatformServicesFacade.InitializeSystemMenu();

IPlatformServices.cs:

public interface IPlatformServices
{
    void InitializeSystemMenu();
}

MonoPlatformServices.cs:

public class MonoPlatformServices : IPlatformServices
{
    // Prevent early type initialization
    static WindowsPlatformServices() {}

    public void InitializeSystemMenu()
    {
        // Maybe log what you would have done?
    }
}

WindowsPlatformServices.cs:

public class WindowsPlatformServices : IPlatformServices
{
    // Prevent early type initialization
    static WindowsPlatformServices() {}

    public const Int32 SystemMenuAboutSWikiId = 1000;
    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
    [DllImport("user32.dll")]
    private static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, 
                                          Int32 wFlags, Int32 wIDNewItem,
                                          string lpNewItem);

    public void InitializeSystemMenu()
    {
        const Int32 MF_SEPARATOR = 0x800;
        const Int32 MF_BYPOSITION = 0x400;

        IntPtr systemMenuPtr = GetSystemMenu(Handle, false);
        InsertMenu(systemMenuPtr, 5, MF_BYPOSITION | MF_SEPARATOR, 0, "");
        InsertMenu(systemMenuPtr, 6, MF_BYPOSITION, SystemMenuAboutSWikiId, 
                   "About SWiki...");
    }
}

PlatformServicesFacade.cs:

public class PlatformServicesFacade
{
    private static readonly IPlatformServices services;

    static PlatformServiceFacade()
    {
        services = RunningOnWindows() ? new WindowsPlatformServices()
            : (IPlatformServices) new MonoPlatformServices();
    }

    public static void InitializeSystemMenu()
    {
        services.InitializeSystemMenu();
    }
}

I think that should work... if it doesn't, please tell us what's going wrong :)

like image 128
Jon Skeet Avatar answered Sep 22 '22 07:09

Jon Skeet


Some Environment property probably has this info, for example System.Environment.OSVersion.Platform. Or use if (Type.GetType("Mono.Runtime") != null)

See "How to detect the execution platform?" and "How can I detect if am running in Mono?": http://www.mono-project.com/FAQ:_Technical

like image 31
Axl Avatar answered Sep 26 '22 07:09

Axl