这段mfc代码为什么word显示不了公式
#include "pch.h"#include "FounderToOmmlConverter.h"
#include <oleauto.h>
#include <msxml6.h>
#include <afx.h>
#include <vector>
#define CLSID_WordApplication _T("{000209FF-0000-0000-C000-000000000046}")
bool FounderToOmmlConverter::InsertToWord(const CString& ommlXml)
{
if (ommlXml.IsEmpty())
{
TRACE("Empty OMML content\n");
return false;
}
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
TRACE("CoInitialize failed: 0x%08X\n", hr);
return false;
}
CComPtr<IDispatch> pWordApp;
try {
// 创建Word实例
CLSID clsid;
if (FAILED(CLSIDFromString(CLSID_WordApplication, &clsid))) {
TRACE("Failed to get CLSID for Word.Application\n");
CoUninitialize();
return false;
}
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch, (void**)&pWordApp);
if (FAILED(hr)) {
TRACE("CoCreateInstance failed: 0x%08X (Is Word installed?)\n", hr);
CoUninitialize();
return false;
}
// 显示Word窗口
CComVariant varVisible(true);
PutProperty(pWordApp, L"Visible", &varVisible);
// 获取Documents集合
CComVariant varDocs;
if (FAILED(GetProperty(pWordApp, L"Documents", &varDocs))) {
TRACE("Failed to get Documents property\n");
CoUninitialize();
return false;
}
CComPtr<IDispatch> pDocuments = varDocs.pdispVal;
// 添加新文档
CComVariant varDoc;
if (FAILED(InvokeMethod(pDocuments, L"Add", &varDoc, NULL))) {
TRACE("Failed to add new document\n");
if (FAILED(GetProperty(pWordApp, L"ActiveDocument", &varDoc))) {
TRACE("Failed to get active document\n");
CoUninitialize();
return false;
}
}
CComPtr<IDispatch> pDoc = varDoc.pdispVal;
// 获取Selection对象
CComVariant varSelection;
if (FAILED(GetProperty(pWordApp, L"Selection", &varSelection))) {
TRACE("Failed to get Selection\n");
CoUninitialize();
return false;
}
CComPtr<IDispatch> pSelection = varSelection.pdispVal;
// 插入提示文本
CComVariant testText(L"数学公式:");
InvokeMethod(pSelection, L"TypeText", NULL, &testText, NULL);
// 尝试插入数学公式的方法 - 使用OMath对象而不是InsertXML
bool insertSuccess = InsertOmmlUsingOMath(pSelection, ommlXml);
if (!insertSuccess) {
// 备用方法:使用InsertXML
insertSuccess = InsertOmmlUsingXML(pSelection, ommlXml);
}
//if (!insertSuccess) {
// // 最后的备用方法:插入为普通文本以便调试
// TRACE("All insertion methods failed, inserting as text for debugging\n");
// CComVariant fallbackText(L"\n\n");
// InvokeMethod(pSelection, L"TypeText", NULL, &fallbackText, NULL);
// CString correctOmmlXml = CreateCorrectOmmlXml(ommlXml);
// CComVariant ommlTextVar(correctOmmlXml);
// InvokeMethod(pSelection, L"TypeText", NULL, &ommlTextVar, NULL);
//}
CoUninitialize();
return insertSuccess;
}
catch (...) {
TRACE("Exception occurred during Word automation\n");
CoUninitialize();
return false;
}
}
// 新方法:使用Word的OMath对象插入数学公式
bool FounderToOmmlConverter::InsertOmmlUsingOMath(IDispatch* pSelection, const CString& ommlXml)
{
try {
// 获取OMath对象集合
CComVariant varOMaths;
if (FAILED(GetProperty(pSelection, L"OMaths", &varOMaths))) {
TRACE("Failed to get OMaths property\n");
return false;
}
CComPtr<IDispatch> pOMaths = varOMaths.pdispVal;
// 添加新的数学公式对象
CComVariant varOMath;
CComVariant varRange;
GetProperty(pSelection, L"Range", &varRange);
if (FAILED(InvokeMethod(pOMaths, L"Add", &varOMath, &varRange, NULL))) {
TRACE("Failed to add OMath object\n");
return false;
}
CComPtr<IDispatch> pOMath = varOMath.pdispVal;
// 创建正确的OMML内容(去掉外层的oMath标签,因为OMath对象会自动添加)
CString innerOmml = ExtractInnerOmml(ommlXml);
// 获取Range对象并设置XML
CComVariant varMathRange;
if (FAILED(GetProperty(pOMath, L"Range", &varMathRange))) {
TRACE("Failed to get OMath Range\n");
return false;
}
CComPtr<IDispatch> pMathRange = varMathRange.pdispVal;
// 设置数学公式的XML内容
CComVariant xmlVar(innerOmml);
if (SUCCEEDED(InvokeMethod(pMathRange, L"InsertXML", NULL, &xmlVar, NULL))) {
TRACE("Successfully inserted OMML using OMath object\n");
return true;
}
TRACE("Failed to insert XML into OMath Range\n");
return false;
}
catch (...) {
TRACE("Exception in InsertOmmlUsingOMath\n");
return false;
}
}
// 备用方法:使用InsertXML
bool FounderToOmmlConverter::InsertOmmlUsingXML(IDispatch* pSelection, const CString& ommlXml)
{
try {
// 创建正确的OMML XML格式
CString correctOmmlXml = CreateCorrectOmmlXml(ommlXml);
TRACE("Generated OMML XML: %s\n", correctOmmlXml.GetString());
//// 方法1:直接插入OMML
CComVariant xmlVar(correctOmmlXml);
HRESULT hr = InvokeMethod(pSelection, L"InsertXML", NULL, &xmlVar, NULL);
if (SUCCEEDED(hr)) {
TRACE("Successfully inserted OMML directly\n");
return true;
}
// 方法2:使用完整的WordProcessingML包装
//CString wrappedXML = CreateWordProcessingMLDocument(correctOmmlXml);
//CComVariant wrappedVar(wrappedXML);
//HRESULT hr = InvokeMethod(pSelection, L"InsertXML", NULL, &wrappedVar, NULL);
//if (SUCCEEDED(hr)) {
// TRACE("Successfully inserted wrapped OMML\n");
// return true;
//}
// 方法3:通过Range插入
//CComVariant varRange;
//CComVariant xmlVar(correctOmmlXml);
//if (SUCCEEDED(GetProperty(pSelection, L"Range", &varRange))) {
// CComPtr<IDispatch> pRange = varRange.pdispVal;
// HRESULT hr = InvokeMethod(pRange, L"InsertXML", NULL, &xmlVar, NULL);
// if (SUCCEEDED(hr)) {
// TRACE("Successfully inserted via Range\n");
// return true;
// }
//}
else {
TRACE("Failed to insert OMML\n");
return false;
}
}
catch (...) {
TRACE("Exception in InsertOmmlUsingXML\n");
return false;
}
}
// 提取OMML内部内容(去掉外层的oMath标签)
CString FounderToOmmlConverter::ExtractInnerOmml(const CString& ommlXml)
{
//CString inner = ommlXml;
//// 简单的字符串处理,实际应该使用XML解析
//int startPos = inner.Find(L"<m:oMath");
//if (startPos != -1) {
// int endTag = inner.Find(L">", startPos);
// if (endTag != -1) {
// inner = inner.Mid(endTag + 1);
// int endPos = inner.ReverseFind(L"</m:oMath>");
// if (endPos != -1) {
// inner = inner.Left(endPos);
// }
// }
//}
//return inner;
CString inner = ommlXml;
// 移除开始标签
int startPos = inner.Find(L"<m:oMath");
if (startPos != -1) {
int endTag = inner.Find(L">", startPos);
if (endTag != -1) {
inner = inner.Mid(endTag + 1);
}
}
// 移除结束标签
inner.Replace(L"</m:oMath>", L"");
return inner.Trim(); // 去除首尾空白
}
// 创建正确的OMML XML格式
CString FounderToOmmlConverter::CreateCorrectOmmlXml(const CString& inputOmml)
{
// 如果输入已经是正确格式,直接返回
//if (inputOmml.Find(L"xmlns:m=") != -1 && inputOmml.Find(L"m:oMath") != -1) {
// return inputOmml;
//}
//// 创建一个简单但正确的数学公式 x = a² + b
//CString correctedOmml =
// L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
// L"<m:r>"
// L"<m:t>x</m:t>"
// L"</m:r>"
// L"<m:r>"
// L"<m:t>=</m:t>"
// L"</m:r>"
// L"<m:sSup>"
// L"<m:e>"
// L"<m:r>"
// L"<m:t>a</m:t>"
// L"</m:r>"
// L"</m:e>"
// L"<m:sup>"
// L"<m:r>"
// L"<m:t>2</m:t>"
// L"</m:r>"
// L"</m:sup>"
// L"</m:sSup>"
// L"<m:r>"
// L"<m:t>+</m:t>"
// L"</m:r>"
// L"<m:r>"
// L"<m:t>b</m:t>"
// L"</m:r>"
// L"</m:oMath>";
//return correctedOmml;
// 创建一个正确的分式:1/2
CString correctedOmml =
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"// 分式元素
L"<m:num>"// 分子
L"<m:r>"
L"<m:t>1</m:t>"
L"</m:r>"
L"</m:num>"
L"<m:den>"// 分母
L"<m:r>"
L"<m:t>2</m:t>"
L"</m:r>"
L"</m:den>"
L"</m:f>"
L"</m:oMath>";
return correctedOmml;
}
// 创建WordProcessingML文档
CString FounderToOmmlConverter::CreateWordProcessingMLDocument(const CString& ommlContent)
{
CString document;
document.Format(
L"<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "
L"xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<w:body>"
L"<w:p>"
L"<w:r>"
L"<w:rPr></w:rPr>"
L"%s"
L"</w:r>"
L"</w:p>"
L"</w:body>"
L"</w:document>",
ommlContent.GetString()
);
return document;
}
// COM辅助函数实现(保持不变)
HRESULT FounderToOmmlConverter::GetProperty(IDispatch* pDisp, LPCOLESTR propertyName, VARIANT* pResult)
{
if (!pDisp || !propertyName || !pResult) return E_INVALIDARG;
DISPID dispid;
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&propertyName, 1,
LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr)) return hr;
DISPPARAMS dispparams = { NULL, NULL, 0, 0 };
return pDisp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET, &dispparams, pResult, NULL, NULL);
}
HRESULT FounderToOmmlConverter::InvokeMethod(IDispatch* pDisp, LPCOLESTR methodName, VARIANT* pResult, ...)
{
if (!pDisp || !methodName) return E_INVALIDARG;
DISPID dispid;
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&methodName, 1,
LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr)) return hr;
va_list args;
va_start(args, pResult);
VARIANT varArgs;
int argCount = 0;
VARIANT* pArg = va_arg(args, VARIANT*);
while (pArg && argCount < 10) {
varArgs = *pArg;
pArg = va_arg(args, VARIANT*);
}
va_end(args);
// 反转参数顺序
if (argCount > 0) {
for (int i = 0; i < argCount / 2; i++) {
VARIANT temp = varArgs;
varArgs = varArgs;
varArgs = temp;
}
}
DISPPARAMS dispparams = { varArgs, NULL, argCount, 0 };
return pDisp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, pResult, NULL, NULL);
}
HRESULT FounderToOmmlConverter::PutProperty(IDispatch* pDisp, LPCOLESTR propertyName, VARIANT* pValue)
{
if (!pDisp || !propertyName || !pValue) return E_INVALIDARG;
DISPID dispid;
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&propertyName, 1,
LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr)) return hr;
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPPARAMS dispparams = { pValue, &dispidNamed, 1, 1 };
return pDisp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
}
// 转换函数(保持原有逻辑)
CString FounderToOmmlConverter::ConvertToOmml(const CString& founderFormula)
{
//CString ommlXml;
//ommlXml.Format(
// L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
// L"<m:r>"
// L"<m:t>%s</m:t>"
// L"</m:r>"
// L"</m:oMath>",
// founderFormula.GetString());
//return ommlXml;
CString ommlXml;
// 检查是否是分式格式(例如 "1/2" 或 "a/b")
int slashPos = founderFormula.Find(L"/");
if (slashPos != -1 && slashPos > 0 && slashPos < founderFormula.GetLength() - 1) {
// 提取分子和分母
CString numerator = founderFormula.Left(slashPos).Trim();
CString denominator = founderFormula.Mid(slashPos + 1).Trim();
// 创建分式OMML
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:num>"
L"<m:den>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:den>"
L"</m:f>"
L"</m:oMath>",
numerator.GetString(),
denominator.GetString());
}
else
{
// 普通文本公式
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:oMath>",
founderFormula.GetString());
}
return ommlXml;
}
// 其他辅助函数(保持不变)
CString FounderToOmmlConverter::ProcessFounderFormula(const CString& formula)
{
return formula;
}
CString FounderToOmmlConverter::GetEndBracket(const CString& startBracket)
{
if (startBracket == L"(") return L")";
if (startBracket == L"[") return L"]";
if (startBracket == L"{") return L"}";
return L"";
}
CString FounderToOmmlConverter::WrapOMMLWithWordNamespace(const CString& rawOMML)
{
if (rawOMML.Find(L"xmlns:m=") == -1) {
CString wrapped;
wrapped.Format(L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">%s</m:oMath>", rawOMML);
return wrapped;
}
return rawOMML;
}
// 在cpp文件中实现
CString FounderToOmmlConverter::CreateFractionOmml(const CString& numerator, const CString& denominator)
{
CString ommlXml;
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:num>"
L"<m:den>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:den>"
L"</m:f>"
L"</m:oMath>",
numerator.GetString(),
denominator.GetString());
return ommlXml;
}
// 创建更复杂的数学表达式
CString FounderToOmmlConverter::CreateComplexOmml(const CString& formula)
{
// 示例:创建 x = a²/b + c 这样的复杂公式
CString ommlXml =
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:r>"
L"<m:t>x</m:t>"
L"</m:r>"
L"<m:r>"
L"<m:t>=</m:t>"
L"</m:r>"
L"<m:f>"// 分式 a²/b
L"<m:num>"
L"<m:sSup>"// 上标 a²
L"<m:e>"
L"<m:r>"
L"<m:t>a</m:t>"
L"</m:r>"
L"</m:e>"
L"<m:sup>"
L"<m:r>"
L"<m:t>2</m:t>"
L"</m:r>"
L"</m:sup>"
L"</m:sSup>"
L"</m:num>"
L"<m:den>"
L"<m:r>"
L"<m:t>b</m:t>"
L"</m:r>"
L"</m:den>"
L"</m:f>"
L"<m:r>"
L"<m:t>+</m:t>"
L"</m:r>"
L"<m:r>"
L"<m:t>c</m:t>"
L"</m:r>"
L"</m:oMath>";
return ommlXml;
}
// MFCApplication1Dlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"
#include "FounderToOmmlConverter.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMFCApplication1Dlg 对话框
CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_COVENT, &CMFCApplication1Dlg::OnBnClickedCovent)
ON_BN_CLICKED(IDC_INSERT, &CMFCApplication1Dlg::OnBnClickedInsert)
END_MESSAGE_MAP()
// CMFCApplication1Dlg 消息处理程序
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
//执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
// 设置示例文本
m_strFounder = _T("〖SX(〗A〖〗B〖SX)〗");
UpdateData(FALSE);
return TRUE;// 除非将焦点设置到控件,否则返回 TRUE
}
void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
//来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//这将由框架自动完成。
void CMFCApplication1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMFCApplication1Dlg::OnBnClickedCovent()
{
// TODO: 在此添加控件通知处理程序代码
if (m_strFounder.IsEmpty()) {
AfxMessageBox(_T("请输入方正公式!"));
return;
}
m_strOmml = FounderToOmmlConverter::ConvertToOmml(m_strFounder);
UpdateData(FALSE);
AfxMessageBox(_T("转换完成!"));
}
void CMFCApplication1Dlg::OnBnClickedInsert()
{
// TODO: 在此添加控件通知处理程序代码
if (m_strOmml.IsEmpty()) {
AfxMessageBox(_T("请先转换公式!"));
return;
}
CString simpleOmml = FounderToOmmlConverter::CreateFractionOmml(L"1", L"2");
if (FounderToOmmlConverter::InsertToWord(simpleOmml)) {
AfxMessageBox(_T("插入Word成功!"));
}
/*if (FounderToOmmlConverter::InsertToWord(m_strOmml)) {
AfxMessageBox(_T("插入Word成功!"));
}*/
else
{
AfxMessageBox(_T("插入Word失败!请确保Word已打开。"));
}
}
这段mfc代码为什么word显示不了公式
// MFCApplication1Dlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"
#include "FounderToOmmlConverter.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMFCApplication1Dlg 对话框
CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_COVENT, &CMFCApplication1Dlg::OnBnClickedCovent)
ON_BN_CLICKED(IDC_INSERT, &CMFCApplication1Dlg::OnBnClickedInsert)
END_MESSAGE_MAP()
// CMFCApplication1Dlg 消息处理程序
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
//执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
// 设置示例文本
m_strFounder = _T("〖SX(〗A〖〗B〖SX)〗");
UpdateData(FALSE);
return TRUE;// 除非将焦点设置到控件,否则返回 TRUE
}
void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
//来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//这将由框架自动完成。
void CMFCApplication1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMFCApplication1Dlg::OnBnClickedCovent()
{
// TODO: 在此添加控件通知处理程序代码
if (m_strFounder.IsEmpty()) {
AfxMessageBox(_T("请输入方正公式!"));
return;
}
m_strOmml = FounderToOmmlConverter::ConvertToOmml(m_strFounder);
UpdateData(FALSE);
AfxMessageBox(_T("转换完成!"));
}
void CMFCApplication1Dlg::OnBnClickedInsert()
{
// TODO: 在此添加控件通知处理程序代码
if (m_strOmml.IsEmpty()) {
AfxMessageBox(_T("请先转换公式!"));
return;
}
CString simpleOmml = FounderToOmmlConverter::CreateFractionOmml(L"1", L"2");
if (FounderToOmmlConverter::InsertToWord(simpleOmml)) {
AfxMessageBox(_T("插入Word成功!"));
}
/*if (FounderToOmmlConverter::InsertToWord(m_strOmml)) {
AfxMessageBox(_T("插入Word成功!"));
}*/
else
{
AfxMessageBox(_T("插入Word失败!请确保Word已打开。"));
}
}
根据提供的代码,Word无法显示公式的主要原因有以下几点:
### 1. 方正公式转换问题
在 `ConvertToOmml` 方法中,方正公式 `〖SX(〗A〖〗B〖SX)〗` 未被正确解析:
// 当前转换逻辑错误地依赖 "/" 符号
int slashPos = founderFormula.Find(L"/"); // 方正公式中没有斜杠
if (slashPos != -1) { ... } // 条件永远不成立
else {
// 错误地生成了普通文本OMML
ommlXml.Format(L"<m:oMath><m:r>%s</m:r></m:oMath>", ...);
}
### 2. OMML生成格式错误
生成的OMML缺少关键命名空间声明:
// 缺少必要的命名空间 xmlns:m
CString ommlXml = L"<m:oMath>...</m:oMath>"; // 无效格式
// 正确格式应包含命名空间
CString correctOmml =
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>...</m:f></m:oMath>";
### 3. 插入逻辑冲突
在插入按钮事件中,实际插入的是测试公式而非转换结果:
void CMFCApplication1Dlg::OnBnClickedInsert() {
// 错误:插入的是硬编码的测试公式
CString simpleOmml = FounderToOmmlConverter::CreateFractionOmml(L"1", L"2");
FounderToOmmlConverter::InsertToWord(simpleOmml); // 应使用 m_strOmml
}
### 4. COM方法调用问题
`InsertOmmlUsingXML` 方法存在逻辑缺陷:
bool InsertOmmlUsingXML(IDispatch* pSelection, const CString& ommlXml) {
// 错误:直接使用未验证的原始XML
CComVariant xmlVar(ommlXml); // 可能包含无效XML
HRESULT hr = InvokeMethod(pSelection, L"InsertXML", NULL, &xmlVar, NULL);
// 未处理失败时的备用方案
}
---
### 解决方案
#### 1. 修复方正公式解析
CString FounderToOmmlConverter::ConvertToOmml(const CString& founderFormula) {
// 解析方正分式标记 〖SX(〗A〖〗B〖SX)〗
if (founderFormula.Find(L"〖SX(〗") != -1) {
int start = 6;// "〖SX(〗"长度
int mid = founderFormula.Find(L"〖〗", start);
int end = founderFormula.Find(L"〖SX)〗", mid);
CString num = founderFormula.Mid(start, mid - start);
CString den = founderFormula.Mid(mid + 2, end - mid - 2);
return CreateFractionOmml(num, den); // 生成正确OMML
}
// 其他公式处理...
}
#### 2. 生成有效OMML
CString FounderToOmmlConverter::CreateFractionOmml(const CString& num, const CString& den) {
return
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f><m:num><m:r>" + num + L"</m:r></m:num>"
L"<m:den><m:r>" + den + L"</m:r></m:den></m:f>"
L"</m:oMath>";
}
#### 3. 修正插入逻辑
void CMFCApplication1Dlg::OnBnClickedInsert() {
if (m_strOmml.IsEmpty()) return;
// 正确使用转换后的公式
if (FounderToOmmlConverter::InsertToWord(m_strOmml)) {
AfxMessageBox(_T("插入成功!"));
}
}
#### 4. 增强XML插入健壮性
bool InsertOmmlUsingXML(IDispatch* pSelection, const CString& ommlXml) {
// 添加XML声明和命名空间
CString validXml =
L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
+ ommlXml + L"</m:oMath>";
CComVariant xmlVar(validXml);
return SUCCEEDED(InvokeMethod(pSelection, L"InsertXML", NULL, &xmlVar, NULL));
}
### 验证步骤
1. 确保输入方正公式格式正确,如 `〖SX(〗分子〖〗分母〖SX)〗`
2. 在转换后检查生成的OMML是否包含完整命名空间
3. 使用Word的XML验证工具检查生成的XML有效性
4. 在`InsertToWord`中添加TRACE输出HRESULT错误代码
> 关键提示:Office 2007+ 才支持OMML,请确认Word版本符合要求。调试时可在`InsertXML`调用后添加`TRACE("InsertXML result: 0x%X\n", hr);`查看具体错误代码。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 CString FounderToOmmlConverter::CreateFractionOmml(const CString& num, const CString& den) {
return
L"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">"
L"<m:f><m:num><m:r>" + num + L"</m:r></m:num>"
L"<m:den><m:r>" + den + L"</m:r></m:den></m:f>"
L"</m:oMath>";
} 这一行的代码显示报错 找不到文本运算符 janeyjhon 发表于 2025-08-17 11:35
CString FounderToOmmlConverter::CreateFractionOmml ...
你的代码报错是因为在拼接XML字符串时使用了错误的语法。C++中不能直接用 `+` 操作符连接字符串字面量和CString对象,需要显式转换。以下是修正后的代码:
CString FounderToOmmlConverter::CreateFractionOmml(const CString& num, const CString& den) {
return
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num>" + num + L"</m:num>"
L"<m:den>" + den + L"</m:den>"
L"</m:f>"
L"</m:oMath>";
}
关键修正点:
1. 字符串字面量需要显式转换为CString:
// 错误写法
L"text" + cstringVar + L"text"
// 正确写法
CString(L"text") + cstringVar + CString(L"text")
2. 更推荐的格式化写法(避免拼接错误):
CString FounderToOmmlConverter::CreateFractionOmml(const CString& num, const CString& den) {
CString xml;
xml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num>%s</m:num>"
L"<m:den>%s</m:den>"
L"</m:f>"
L"</m:oMath>",
num.GetString(), den.GetString());
return xml;
}
3. 必须包含XML命名空间声明:
// 缺少这个会导致Word无法识别公式
xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"
4. 完整的OMML结构应该是:
<m:oMath xmlns:m="命名空间">
<m:f> <!-- 分式 -->
<m:num>分子</m:num>
<m:den>分母</m:den>
</m:f>
</m:oMath>
验证建议:
1. 调试时输出生成的XML:
TRACE(L"Generated OMML: %s\n", xml);
2. 将输出的XML复制到文本编辑器,检查标签是否闭合
3. 在Word中手动粘贴XML测试(通过"插入-对象-公式")
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 CString ommlXml;
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:num>"
L"<m:den>"
L"<m:r>"
L"<m:t>%s</m:t>"
L"</m:r>"
L"</m:den>"
L"</m:f>"
L"</m:oMath>",
numerator.GetString(),
denominator.GetString());这样写对吗 janeyjhon 发表于 2025-08-17 13:28
CString ommlXml;
ommlXml.Format(
L""
...
你的代码结构基本正确,但需要注意以下关键点:
CString FounderToOmmlConverter::CreateFractionOmml(const CString& numerator, const CString& denominator) {
CString ommlXml;
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"// 分式开始
L"<m:num>"// 分子开始
L"<m:r><m:t>%s</m:t></m:r>"// 分子内容
L"</m:num>"// 分子结束
L"<m:den>"// 分母开始
L"<m:r><m:t>%s</m:t></m:r>"// 分母内容
L"</m:den>"// 分母结束
L"</m:f>"// 分式结束
L"</m:oMath>",// 公式结束
numerator.GetString(),
denominator.GetString());
return ommlXml;
}
### 需要修正的关键点:
1. **XML命名空间声明**:
// 必须包含此命名空间声明
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
2. **标签闭合问题**:
// 错误:缺少闭合标签
L"<m:num><m:r><m:t>%s</m:t></m:r>"
// 正确:添加分子结束标签
L"<m:num><m:r><m:t>%s</m:t></m:r></m:num>"
3. **特殊字符处理**(重要):
如果分子/分母包含 `<`, `>`, `&` 等字符,需要转义:
CString escapedNum = numerator;
escapedNum.Replace(L"&", L"&");
escapedNum.Replace(L"<", L"<");
escapedNum.Replace(L">", L">");
### 完整修正版:
CString FounderToOmmlConverter::CreateFractionOmml(const CString& numerator, const CString& denominator) {
// 转义特殊字符
CString safeNum = EscapeXml(numerator);
CString safeDen = EscapeXml(denominator);
CString ommlXml;
ommlXml.Format(
L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"
L"<m:f>"
L"<m:num><m:r><m:t>%s</m:t></m:r></m:num>"
L"<m:den><m:r><m:t>%s</m:t></m:r></m:den>"
L"</m:f>"
L"</m:oMath>",
safeNum.GetString(),
safeDen.GetString());
return ommlXml;
}
// XML转义辅助函数
CString FounderToOmmlConverter::EscapeXml(const CString& input) {
CString result = input;
result.Replace(L"&", L"&");
result.Replace(L"<", L"<");
result.Replace(L">", L">");
result.Replace(L"\"", L""");
return result;
}
### 验证方法:
在调用处添加调试输出:
// 在调用CreateFractionOmml后添加:
CString generated = CreateFractionOmml(L"1/2", L"x+y");
TRACE(L"Generated OMML:\n%s\n", generated);
输出应该类似:
<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:f>
<m:num><m:r><m:t>1/2</m:t></m:r></m:num>
<m:den><m:r><m:t>x+y</m:t></m:r></m:den>
</m:f>
</m:oMath>
> **重要提示**:Word对OMML的解析非常严格,必须确保:
> 1. 所有标签正确闭合
> 2. 命名空间正确定义
> 3. 特殊字符正确转义
> 4. 整个XML是单根结构(如使用`<m:oMath>`作为根元素)
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 L"<m:oMath xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\">"这个里面写成这样没报错写成这样<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">报错 出现红色波浪线 janeyjhon 发表于 2025-08-17 13:34
L""这个里面写成这样没报错写成这样报错
您遇到的问题是C++字符串拼接的语法问题。让我解释清楚正确的写法:
### 正确写法(不会报错):
CString ommlXml;
ommlXml.Format(
L"" // 注意这里没有逗号
L""
L""
L"%s" // 分子
L""
L""
L""
L""
L"%s" // 分母
L""
L""
L""
L"",
numerator.GetString(),
denominator.GetString());
### 错误写法(会报错):
CString ommlXml;
ommlXml.Format(
L"", // 这里有逗号
L"", // 这里有逗号
L"", // 这里有逗号
L"%s", // 这里有逗号
...); // 错误:Format函数不接受多个字符串参数
### 关键区别:
1. **没有逗号分隔**:所有XML字符串必须写在一个连续的大字符串中,不能在每个L""后面加逗号
2. **整体是一个字符串**:编译器会将相邻的字符串字面量自动拼接成一个字符串
3. **Format参数对应**:`%s`的数量必须与后面的参数数量一致
### 更安全的写法(推荐):
CString ommlXml;
ommlXml.Format(
L""
L""
L"%s"
L""
L""
L""
L"%s"
L""
L"",
numerator.GetString(),
denominator.GetString());
### 调试技巧:
如果仍然报错,可以简化测试:
// 简化测试1:纯文本
CString test;
test.Format(L"第一部分" L"第二部分 %s" L"第三部分", L"测试");
TRACE(L"测试结果: %s\n", test.GetString());
// 简化测试2:XML结构
CString xmlTest =
L""
L""
L"分子"
L""
L""
L""
L"分母"
L""
L"";
TRACE(L"XML测试:\n%s\n", xmlTest.GetString());
### 常见错误原因:
1. 在L""之间添加了逗号(最常见错误)
2. 漏掉了某个字符串的L前缀
3. 标签没有正确闭合(如缺少`</m:num>`)
4. 特殊字符未转义(特别是`<`、`>`、`&`)
5. 命名空间声明不正确
> 提示:在VS中,将鼠标悬停在Format方法上,会显示函数签名:`void Format(LPCTSTR lpszFormat, ...);` 这证明它只接受一个格式字符串和可变参数。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]