在桌面开发里,用WPF写界面、用C++写核心算法或硬件逻辑是非常常见的组合。要让两者协同工作,关键在于选择稳定的数据通信方式。下面介绍几种主流的C++与WPF交互方法。
C++/CLI封装方式
如果WPF和C++运行在同一个进程内,最方便的做法是用C++/CLI创建一个中间类库。它既能调用原生C++代码,又能被WPF的C#代码直接引用。
示例:C++/CLI桥接类
// NativeCpp.h 原生C++代码
#pragma once
class NativeCalc {
public:
int Add(int a, int b) {
return a + b;
}
};
// Bridge.h C++/CLI包装类
#pragma once
using namespace System;
public ref class CalcBridge {
private:
NativeCalc* native;
public:
CalcBridge() { native = new NativeCalc(); }
~CalcBridge() { delete native; }
int DoAdd(int a, int b) {
return native->Add(a, b);
}
};
在WPF的C#项目中添加对该CLR类库的引用,就可以像使用普通C#对象一样调用DoAdd方法。
进程间通信:命名管道
当C++程序是独立的exe,与WPF分别运行在不同进程时,可以使用命名管道(Named Pipe)来交换数据。
WPF端C#管道客户端
using System;
using System.IO;
using System.IO.Pipes;
class PipeClient {
public static string Send(string msg) {
using (var pipe = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut)) {
pipe.Connect(5000);
using (var writer = new StreamWriter(pipe)) {
writer.Write(msg);
writer.Flush();
}
pipe.ReadMode = PipeTransmissionMode.Byte;
using (var reader = new StreamReader(pipe)) {
return reader.ReadToEnd();
}
}
}
}
C++管道服务端片段
#include <windows.h>
#include <iostream>
int main() {
HANDLE hPipe = CreateNamedPipe(
TEXT("\\.\pipe\testpipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1, 1024, 1024, 0, NULL);
ConnectNamedPipe(hPipe, NULL);
char buf[1024] = {0};
DWORD read;
ReadFile(hPipe, buf, sizeof(buf), &read, NULL);
// 处理buf中的数据并返回
WriteFile(hPipe, "ok", 2, &read, NULL);
CloseHandle(hPipe);
return 0;
}
共享内存方式
对性能要求高且为本地多进程时,可用共享内存(文件映射)传输大块数据。C++端创建内存映射,WPF端用PInvoke打开并读写。
| 方式 | 适用场景 | 复杂度 |
|---|---|---|
| C++/CLI | 同进程集成 | 低 |
| 命名管道 | 跨进程稳定通信 | 中 |
| 共享内存 | 高吞吐本地交换 | 高 |
总结
实际项目中,若历史C++代码较多且允许混合编译,优先用C++/CLI;若必须隔离进程,命名管道更易维护。注意在WPF中调用非托管代码时要处理异常,避免界面卡死。