为什么我从程序集<baz>的类型<bar>中得到一个虚假的TypeLoadException“Method <foo>没有实现”?</baz> </bar> </foo>

时间:2013-05-01 17:59:30

标签: c# c++-cli cefsharp

我正在将现有的基于VS2008的C ++ / CLI项目(更具体地说,CefSharp)升级到VS2012,同时面临一些挑战。为避免依赖VS2008进行编译,我已将项目升级为目标.NET Framework 4.0。

一切都很好,项目编译正确,但是当我运行它并尝试创建一个WebView实例时,我得到以下TypeLoadException:

方法'CefSharp.Wpf.WebView'中的方法'SetCursor'来自程序集'CefSharp.Wpf,Version = 1.25.0.35385,Culture = neutral,PublicKeyToken = null'没有实现。“:”CefSharp .Wpf.WebView“

显然,我已经非常仔细地研究了WebView.h和WebView.cpp。他们的内容是(相关部分):

public ref class WebView sealed : public ContentControl, IRenderWebBrowser
{
public:
    virtual void SetCursor(CefCursorHandle cursor);
}

实施:

void WebView::SetCursor(CefCursorHandle cursor)
{
    SafeFileHandle^ handle = gcnew SafeFileHandle((IntPtr)cursor, false);
    Dispatcher->BeginInvoke(DispatcherPriority::Render,
        gcnew Action<SafeFileHandle^>(this, &WebView::SetCursor), handle);
}

CefCursorHandle定义如下:

#define CefCursorHandle cef_cursor_handle_t

...和cef_cursor_handle_t定义如下:

#define cef_cursor_handle_t HCURSOR

即。一个windef.h结构。

接口(IRenderWebBrowser)btw。定义这样的方法。

public interface class IRenderWebBrowser : IWebBrowser
{
public:
    void SetCursor(CefCursorHandle cursor);
}

有一次,我认为这个问题与“const”和“non-const”问题有关,但是从例子中可以看出,没有涉及const说明符。 : - (

我在这里失踪的明显问题是什么?我浏览了this post,但它并没有真正帮助我。

我还考虑过多个/旧版本的程序集可能会挂在某处,所以我尝试碰撞程序集版本只是为了确保正确的程序集已加载 - 它就是这样。我也在装配上看了ILSpy,方法肯定在那里。但是,它的方法签名是:

public unsafe void SetCursor(HICON__* cursor)

是否与不安全的部分有关,或者它的参数(HICON __ *)无法从C#/ CLR上下文中获取? (我正在尝试从C#程序集中实例化类型。)我必须承认C ++ / CLI并不是我的专业领域,但......: - )

任何?

(如果有人想更仔细地查看详细信息,请随时在https://github.com/perlun/CefSharp/克隆/调查项目 - 这些内容存在于vs2012分支上。)

2 个答案:

答案 0 :(得分:0)

跟进:我试图在C#中实现IRenderWebBrowser接口,只是为了试验:

public unsafe class Foo : IRenderWebBrowser
{
    public void SetBuffer(int width, int height, void* buffer)
    {
        throw new NotImplementedException();
    }

    // ...and so forth.
}

现在,编译它(在启用/ unsafe标志之后)让我更深入地了解(可能)造成这种情况的原因:

1>Y:\git\ataranto.CefSharp\CefSharp.Wpf.Example\MainWindow.xaml.cs(167,31,167,38): error CS0122: 'HICON__' is inaccessible due to its protection level
1>Y:\git\ataranto.CefSharp\CefSharp.Wpf.Example\MainWindow.xaml.cs(167,21,167,30): error CS0051: Inconsistent accessibility: parameter type 'HICON__*' is less accessible than method 'CefSharp.Wpf.Example.Foo.SetCursor(HICON__*)'
1>Y:\git\ataranto.CefSharp\CefSharp.Wpf.Example\MainWindow.xaml.cs(182,45,182,52): error CS0122: 'CefRect' is inaccessible due to its protection level
1>Y:\git\ataranto.CefSharp\CefSharp.Wpf.Example\MainWindow.xaml.cs(182,21,182,44): error CS0051: Inconsistent accessibility: parameter type 'CefRect*' is less accessible than method 'CefSharp.Wpf.Example.Foo.SetPopupSizeAndPosition(CefRect*)'

如果C#/托管世界无法访问HICON__,那么类型中存在这些方法的事实很可能使CLR有点“混淆”至少说,使得类型无法实例化管理环境。在C ++ / CLI中是否有任何方法可以指定方法是公共的(实现有问题的接口),但“从CLR隐藏”(以避免愚蠢的TypeLoadExceptions等)?

答案 1 :(得分:0)

让我们希望这可以帮助别人......结果证明我的怀疑是对的,看似。因为类型是非托管(并且托管世界无法访问),所以C ++编译器将CefCursorHandle / HICON结构创建为组件中的内部 CLR结构,其中WebView是声明。这使得该方法基本上是不可调用的(具有内部参数的公共方法=&gt;无法从C#调用),并且当尝试从C#实例化类型时,CLR似乎对此进行了禁止...

将参数类型更改为IntPtr,使代码按预期工作。 “void *”也是一个选项,它有时可以更容易在C ++端使用。

(在这些情况下,这些方法不需要在C#/管理方面使用,因此使用IntPtr / void *不是问题。如果实际使用它们,正确的编组将是一个更好的主意比这更好。)