【发布时间】:2015-11-10 00:36:01
【问题描述】:
我需要将 C# WPF UserControls 包装在 C++/CLI 包装器中以在本机 C++ 程序中使用。本机程序大量使用MFC,并在VS2010中编译。我已经在单独的解决方案中正确生成了 C++/CLI .lib 和 .dll 文件,并从 MFC 应用程序链接到它们,该应用程序成功编译和链接,像往常一样生成可执行文件。但是,当我启动 MFC 应用程序时,我在到达 main() 之前就收到了访问冲突错误 0xc0000005。当我注释掉包装代码时,程序正常启动。
为了尝试隔离问题,我尝试创建一个完全独立的本机 C++ 项目,其唯一目的是使用虚拟数据调用包装类。该项目到达 main() 但在我调用包装类的构造函数时抛出异常(0xe0434352)。
我已经尝试寻找任何可能的解决方案,但与我的情况最匹配的解决方案是检查函数签名以确保我传递了正确数量的参数(我是)。我还从独立项目中查找了 0xe0434352 异常,它似乎是一个通用的 .NET 异常。
我还看到this 发布的问题,但希望解决方案比这更简单。我一直按照this 博客上的说明创建包装类。
我将包括除 MFC 应用程序代码之外的所有代码,因为它甚至没有加载到 main()。我希望如果我能设法解决全新项目中的问题,MFC 应用程序将启动。
C# WPF:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ManagedWPFLink
{
public struct TestResultData
{
public string inspectionType;
public string testResult;
public string measuredValue;
public string passCondition;
public string comments;
}
/// <summary>
/// Interaction logic for TestResultsDialog.xaml
/// </summary>
public partial class TestResultsDialog : UserControl
{
private Window window;
public TestResultsDialog()
{
InitializeComponent();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridTextColumn col2 = new DataGridTextColumn();
DataGridTextColumn col3 = new DataGridTextColumn();
DataGridTextColumn col4 = new DataGridTextColumn();
DataGridTextColumn col5 = new DataGridTextColumn();
this.testResultsGrid.Columns.Add(col1);
this.testResultsGrid.Columns.Add(col2);
this.testResultsGrid.Columns.Add(col3);
this.testResultsGrid.Columns.Add(col4);
this.testResultsGrid.Columns.Add(col5);
col1.Binding = new Binding("inspectionType");
col2.Binding = new Binding("testResult");
col3.Binding = new Binding("measuredValue");
col4.Binding = new Binding("passCondition");
col5.Binding = new Binding("comments");
col1.Header = "Inspection Type";
col2.Header = "Test Result";
col3.Header = "Measured Value";
col4.Header = "Pass Condition";
col5.Header = "Comments";
this.window = new Window
{
Title = "Inspection Results",
Content = this,
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize
};
}
public void addRow(string inspectionType, string testResult, string measuredValue, string passCondition, string comments)
{
TestResultData data = new TestResultData();
data.inspectionType = inspectionType;
data.testResult = testResult;
data.measuredValue = measuredValue;
data.passCondition = passCondition;
data.comments = comments;
this.testResultsGrid.Items.Add(data);
}
public void deleteAllRows()
{
this.testResultsGrid.Items.Clear();
}
public void showDialog()
{
this.window.ShowDialog();
}
}
}
C# XAML:
<UserControl x:Class="ManagedWPFLink.TestResultsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="600">
<Grid>
<DataGrid AutoGenerateColumns="True" Height="376" HorizontalAlignment="Left" Margin="12,12,0,0" Name="testResultsGrid" VerticalAlignment="Top" Width="576" ItemsSource="{Binding}" MinColumnWidth="40">
</DataGrid>
</Grid>
</UserControl>
C++/CLI 头文件:
// ManagedWPFLink.h
#pragma once
namespace WPFLink
{
class WPFPrivate;
class __declspec(dllexport) WPFWrapper
{
private:
WPFPrivate *internalWrapper;
public:
WPFWrapper();
~WPFWrapper();
void addItems(const char **data);
void deleteAllRows();
void showDialog();
};
}
C++/CLI 源码:
// This is the main DLL file.
#include "stdafx.h"
#using <WindowsBase.dll>
#using <PresentationCore.dll>
#using <PresentationFramework.dll>
#using "ManagedWPFLink.dll"
#include "WPFLink.h"
using namespace System::Runtime::InteropServices;
namespace WPFLink
{
public class WPFPrivate
{
public:
msclr::auto_gcroot<System::String^> inspectionType;
msclr::auto_gcroot<System::String^> testResult;
msclr::auto_gcroot<System::String^> measuredValue;
msclr::auto_gcroot<System::String^> passCondition;
msclr::auto_gcroot<System::String^> comments;
msclr::auto_gcroot<ManagedWPFLink::TestResultsDialog^> testResultDialog;
public:
WPFPrivate()
{
}
~WPFPrivate()
{
delete testResultDialog;
}
};
WPFWrapper::WPFWrapper()
{
this->internalWrapper = new WPFLink::WPFPrivate();
}
WPFWrapper::~WPFWrapper()
{
delete this->internalWrapper;
}
void WPFWrapper::addItems(const char **data)
{
this->internalWrapper->inspectionType = gcnew System::String(data[0]);
this->internalWrapper->testResult = gcnew System::String(data[1]);
this->internalWrapper->measuredValue = gcnew System::String(data[2]);
this->internalWrapper->passCondition = gcnew System::String(data[3]);
this->internalWrapper->comments = gcnew System::String(data[4]);
this->internalWrapper->testResultDialog->addRow(this->internalWrapper->inspectionType, this->internalWrapper->testResult,
this->internalWrapper->measuredValue, this->internalWrapper->passCondition, this->internalWrapper->comments);
}
void WPFWrapper::deleteAllRows()
{
this->internalWrapper->testResultDialog->deleteAllRows();
}
void WPFWrapper::showDialog()
{
this->internalWrapper->testResultDialog->showDialog();
}
}
原生 C++ 代码:
#include "..\WPFLink\WPFLink.h"
int main()
{
WPFLink::WPFWrapper wrapper; // Generates 0xe0434352 error
return 0;
}
【问题讨论】:
-
使用 VS 调试器单步调试本机版本没有提供有用的信息?
-
我认为您不应该像在 ~WPFPrivate() 中那样删除
auto_gcroot对象... auto_gcroot 进行自己的资源管理。我还会尝试在 WPFPrivate 中注释掉那个花哨的 TestResultsDialog ,看看这是否导致了问题,或者它是否是更根本的问题。 -
@user4581301 使用 VS 调试器单步执行本机版本会给出评论中提到的错误,无论我是“跳过”还是“进入”该行。没有其他用处。
-
@MarkWaterman 我会尝试删除删除语句,看看是否有帮助。注释掉 TestResultsDialog 可能没有用,因为这是我试图与这个互操作层交互的对象。
-
确认注释掉 WPFPrivate 中的 TestResultsDialog 可以防止系统崩溃。我需要弄清楚它为什么会崩溃或如何正确包装 WPF 以在 MFC 中使用。