1

背景を読みたくない場合は、「問題」ラベルに移動してください。

C++ から C# に関数を呼び出す方法を見つけるために、最初にこの質問を投稿しました: How do one make function calls or trigger events from a Native component into a C#/XAML component?

これは、回答としてマークされた解決策につながります。これは、友人がスタックオーバーフローを回避して機能することを確認しました。

次に、ソリューションの指示に従って、次の 2 つのコールバック クラスを実装しました。

// 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++ コンパイラが (ICallback の定義に従って) 考えたものと 100% 似ていなかったことです。

問題?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 に答える