1

如果您不想阅读背景,请转到“问题”标签。

我首先发布了这个问题,试图找到一种将函数从 C++ 调用到 C# 的方法:如何从 Native 组件进行函数调用或触发事件到 C#/XAML 组件中?

这导致了被标记为答案的解决方案,我已经确认朋友可以解决堆栈溢出问题。

然后我按照解决方案的说明实现了以下两个回调类:

// C++ land
// This is the interface that defines all of the functions
// that this component can call on the C#/xaml side
[Windows::Foundation::Metadata::WebHostHidden]
public interface class ICallback
{
public:
    // begins the displaying of the progress bar and signals
    // the start of a new task
    virtual void BeginProgress(Platform::String ^ message);

    // completes a the progress started by the progress bar and returns the
    // result of the task done. Also has an optional message which can give
    // the user additional information if failure occured.
    virtual void CompleteProgress(int result, Platform::String ^ message);
};

// C# land
// used as a callback from the native component to here
// just delegates calls to the page
class Callback : ICallback
{
    // a reference to the page so we can dispatch UI events
    private ViewerPage m_page;

    public Callback(ViewerPage page)
    {
        m_page = page;
    }

    // just delegates to the page
    public void BeginProgress(String message)
    {
        m_page.BeginProgress(message);
    }

    public void CompleteProgress(int result, String message)
    {
        m_page.CompleteProgress(result, message);
    }
}
// the page then handles those calls as you would expect

问题:

我在本机组件初始化时设置回调,如下所示:

// ViewerPage.cs
private void DrawingSurfaceBackground_Loaded(object sender, RoutedEventArgs e)
{
        if (m_d3dBackground == null)
        {
            m_d3dBackground = new Direct3DBackground();

            // Set window bounds in dips
            m_d3dBackground.WindowBounds = new Windows.Foundation.Size(
                (float)Application.Current.Host.Content.ActualWidth,
                (float)Application.Current.Host.Content.ActualHeight
                );

            ... // more initialization stuff

            // hook up the callback
            m_d3dBackground.Callback = m_callback;

            ... // even more

        }
}

然后我将回调从 m_d3dBackground 传递给 Renderer 类,如下所示:

m_renderer->Initialize(Callback);

然后,渲染器会在适当的时候尝试调用回调,如下所示:

// let the user know we're starting the lengthiest one time operation of this application
// TODO: figure out the bug that keeps this from working
m_callback->BeginProgress("Loading Model");

这就是事情出错的时候。

例外

我得到一个 Platform::NullReferenceException。我可以确认调用的指针仍然是传递给 d3dBackground 对象的第一个指针。

这是异常发生时的堆栈跟踪:

堆栈跟踪

不幸的是,大多数记录都是并发乱码,所以没有多大帮助。

以下是成员变量,包括问题很大的 m_callback:

成员变量

最后,这里是 NullPointerException 发生位置的内存转储(确切位置突出显示):

记忆

我真的在这个问题上摸不着头脑,所以如果有人有任何直觉或提示,我将不胜感激。

谢谢阅读。

4

1 回答 1

0

好吧,我在这篇文章上点击提交后大约 3 分钟解决了这个问题。

问题是回调对象的 C# 版本看起来不像 C++ 编译器认为的那样 %100(根据 ICallback 的定义)。

问题?对 ViewerPage 的引用与编译器认为 BeginProgress() 所在的内存位置相同。

解决方案?将 ICallback 实现移动到 Page 类中,因为编译器会自动将成员变量移动到对象的开头,而不管它们在代码中的位置。

public partial class ViewerPage : PhoneApplicationPage
{
    private Callback m_callback;

    ... // rest of ViewPage class

    // used as a callback from the native component to here
    // just delegates calls to the page
    class Callback : ICallback
    {
        public Callback()
        {
        }

        // just delegates to the page
        public void BeginProgress(String message)
        {
            BeginProgress(message);
        }

        public void CompleteProgress(int result, String message)
        {
            CompleteProgress(result, message);
        }
    }
}

-.-

于 2013-07-04T20:42:00.627 回答