C# &引用;忽视;在Mono上运行时的P/Invoke

C# &引用;忽视;在Mono上运行时的P/Invoke,c#,.net,mono,pinvoke,C#,.net,Mono,Pinvoke,我有一个WinForms应用程序,我想在Mono上运行。但是,它对user32.dll使用了一些P/Invoke,这将导致明显的问题 然而,这不是一个关键的功能,只是一些味道的东西。所以我想在运行Mono时忽略它 我知道我可以只使用#if指令,但是我必须提供两个不同的程序集,这很糟糕。我知道如果我在Mono中运行,我可以在运行时检查,但这不会帮助我删除函数的声明 所以我想知道:有没有一种方法可以让我说“如果运行Mono,完全忽略它”?如果有用的话:P/Invoke文件位于一个单独的.cs文件中,

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

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

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

所以我想知道:有没有一种方法可以让我说“如果运行Mono,完全忽略它”?如果有用的话:P/Invoke文件位于一个单独的.cs文件中,并作为一个分部类实现

这里有问题的源代码:

它是我的主窗体的一部分,覆盖WndProc消息以向系统菜单添加项。(其他一些东西被剪掉了)。我的问题是,虽然WndProc的东西很简单,但我不知道如何处理这两个私有的外部声明——我可以将它们放入另一个我从未调用过的(静态)类中吗?或者那是俄罗斯轮盘赌?

为什么不将依赖于平台的东西封装在一个接口中,然后用某种方法为当前平台获得“正确”的实现呢。然后调用代码可以轻松地使用它,并且您可以逐渐填充位,以便在需要时在Mono上运行。我至少希望,如果您从未加载包含P/Invoke位的类,那么您应该可以

编辑:

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

MainForm.cs:

PlatformServicesFacade.InitializeSystemMenu();
IPlatformServices.cs:

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

    public void InitializeSystemMenu()
    {
        // Maybe log what you would have done?
    }
}
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...");
    }
}
MonoPlatformServices.cs:

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

    public void InitializeSystemMenu()
    {
        // Maybe log what you would have done?
    }
}
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...");
    }
}
WindowsPlatformServices.cs:

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

    public void InitializeSystemMenu()
    {
        // Maybe log what you would have done?
    }
}
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();
    }
}

我想这应该行得通。。。如果没有,请告诉我们出了什么问题:)

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

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


请参阅“如何检测执行平台?”和“我如何检测我是否在Mono中运行?”:

我认为您最好的选择是Mono人员。它仍然很新(仅在Mono SVN中)。但我相信他们会很乐意帮助将其纳入Mono发行版:)

我只想确保它们不会被调用并随机崩溃我的应用程序。只是不要将它们公开-将它们包装在一个函数中,该函数将检查应该调用哪个平台特定的变体。顺便说一句,你知道Swiki已经是Wiki软件的名称了,对吗?只是在注册之后,现在它得到了一些点击率。我正在考虑将其重命名为1.0。谢谢。我的问题更多的是关于“如何将外部方法的声明放入运行时执行的条件块中?”我想是这样:)但是P/Invoke是我只想在没有其他方法的情况下使用的东西之一,即使是在最小程度上。