在Mono上运行时“忽略”P / Invoke

时间:2009-08-19 19:37:44

标签: c# .net mono pinvoke

我有一个WinForms应用程序,我希望在某些时候在Mono上运行。但是,它正在对user32.dll使用一些P / Invoke,这将导致明显的问题。

然而,这不是一个关键的功能,只是一些风味的东西。所以我想在运行Mono时忽略它。

我知道我可以使用#if指令,但是我必须提供两个不同的程序集,这很糟糕。我知道如果我在Mono中运行,我可以检查运行时,但这不会帮助我删除函数的声明。

所以我想知道:有没有办法可以说“如果运行Mono,完全忽略它”?如果有帮助:P / Invoke内容在一个单独的.cs文件中,并作为Partial Class实现。

有问题的源代码在这里:http://pastie.org/588940
它是我的主窗体的一部分,覆盖WndProc消息以将项添加到系统菜单。 (其他一些东西被剪掉)。我的问题是虽然WndProc的东西很简单,但我不知道如何处理这两个私有的extern声明 - 我可以把它们放到另一个(静态)类中,我从不在Mono上调用它吗?或者那是俄罗斯轮盘赌?

4 个答案:

答案 0 :(得分:8)

为什么不在平台中封装依赖于平台的东西,然后有一些方法来获得当前平台的“正确”实现。然后调用代码可以轻松地使用它,并且您可以根据需要逐渐填充位以在Mono上运行。我至少希望如果你从未加载包含P / Invoke位的类,你应该没问题......

编辑:

我不明白为什么这种方法不起作用,尽管你可能甚至不需要工厂。这就是我要做的事情:

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();
    }
}

认为应该有用......如果没有,请告诉我们出了什么问题:)

答案 1 :(得分:4)

某些Environment属性可能包含此信息,例如System.Environment.OSVersion.Platform。或者使用if(Type.GetType(“Mono.Runtime”)!= null)

请参阅“如何检测执行平台?”和“如何检测我是否在Mono中运行?”:http://www.mono-project.com/FAQ:_Technical

答案 2 :(得分:2)

检查运行时似乎是一个可行的解决方案。如果在Mono下运行,你是否有任何理由要删除P / Invoke函数声明,即使它们从未被使用过?

答案 3 :(得分:2)

我认为你最好的选择是来自Mono球员的M/Invoke。它仍然很新(仅在Mono SVN中)。但我确信他们会喜欢帮助将它变成Mono发行版:)