刚去的新公司分配了我一个项目需求,将PPT文件(包括*.ppt和*.pptx)转换成多张png图片。由于以前只有native C++的经验,在网上逛了多圈后,发现都是使用C#实现这个功能的,被这个需求折磨了几天后,今天终于把这个问题解决了。所以在此记录下解决这个项目需求的总结。

C#的程序代码在非托管的C++环境中使用有三种方式:1.平台调用技术(P/Invoke)。2. C++ Interop。3.COM Interop。

我使用的是C++ Interop方法,也就是使用C++/CLI语法将C#的动态库封装成C++/CLI的动态库,然后在native C++程序中就可以调用C++/CLI的动态库了。以下是我的一些做法:

1.我使用的IDE工具是VS2015,从网上找到了一份PPT转化成图片的C#动态库。链接如下:https://www.cnblogs.com/kksguijiao/articles/9099103.html

将这份C#的代码进行了一些简单的修改符合了我的需求。修改后的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;using Aspose.Cells;using ESBasic;using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
//using System.Threading.Tasks;// 这个是去掉水印的
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Xml;namespace LicenseHelper
{public static class ModifyInMemory{private static string AsposeList = "Aspose.3D.dll, Aspose.BarCode.dll, Aspose.BarCode.Compact.dll, Aspose.BarCode.WPF.dll, Aspose.Cells.GridDesktop.dll, Aspose.Cells.GridWeb.dll, Aspose.CAD.dll, Aspose.Cells.dll, Aspose.Diagram.dll, Aspose.Email.dll, Aspose.Imaging.dll, Aspose.Note.dll, Aspose.OCR.dll, Aspose.Pdf.dll, Aspose.Slides.dll, Aspose.Tasks.dll, Aspose.Words.dll";public static void ActivateMemoryPatching(){Assembly[] arr = AppDomain.CurrentDomain.GetAssemblies();foreach (Assembly assembly in arr){if (AsposeList.IndexOf(assembly.FullName.Split(',')[0] + ".dll") != -1)ActivateForAssembly(assembly);}AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(ActivateOnLoad);}private static void ActivateOnLoad(object sender, AssemblyLoadEventArgs e){if (AsposeList.IndexOf(e.LoadedAssembly.FullName.Split(',')[0] + ".dll") != -1)ActivateForAssembly(e.LoadedAssembly);}private static void ActivateForAssembly(Assembly assembly){MethodInfo miLicensed1 = typeof(ModifyInMemory).GetMethod("InvokeMe1", BindingFlags.NonPublic | BindingFlags.Static);MethodInfo miLicensed2 = typeof(ModifyInMemory).GetMethod("InvokeMe2", BindingFlags.NonPublic | BindingFlags.Static);MethodInfo miEvaluation = null;Dictionary<string, MethodInfo> miDict = new Dictionary<string, MethodInfo>(){{"System.DateTime"      , miLicensed1},{"System.Xml.XmlElement", miLicensed2}};Type[] arrType = null;bool isFound = false;int nCount = 0;try{arrType = assembly.GetTypes();}catch (ReflectionTypeLoadException err){arrType = err.Types;}foreach (Type type in arrType){if (isFound) break;if (type == null) continue;MethodInfo[] arrMInfo = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static);foreach (MethodInfo info in arrMInfo){if (isFound) break;try{string strMethod = info.ToString();if ((strMethod.IndexOf("(System.Xml.XmlElement, System.String)") > 0) && (miDict.ContainsKey(info.ReturnType.ToString()))){miEvaluation = info;MemoryPatching(miEvaluation, miDict[miEvaluation.ReturnType.ToString()]);nCount++;if (((assembly.FullName.IndexOf("Aspose.Pdf") == -1) && (nCount == 2)) ||((assembly.FullName.IndexOf("Aspose.Pdf") != -1) && (nCount == 6))){isFound = true;break;}}}catch{throw new InvalidOperationException("MemoryPatching for \"" + assembly.FullName + "\" failed !");}}}String[] aParts = assembly.FullName.Split(',');string fName = aParts[0];if (fName.IndexOf("Aspose.BarCode.") != -1)fName = "Aspose.BarCode";else if (fName.IndexOf("Aspose.3D") != -1)fName = "Aspose.ThreeD";try{Type type2 = assembly.GetType(fName + ".License");MethodInfo mi = type2.GetMethod("SetLicense", new Type[] { typeof(Stream) });string LData = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPExpY2Vuc2U+CiAgPERhdGE+CiAgICA8TGljZW5zZWRUbz5MaWNlbnNlZTwvTGljZW5zZWRUbz4KICAgIDxFbWFpbFRvPmxpY2Vuc2VlQGVtYWlsLmNvbTwvRW1haWxUbz4KICAgIDxMaWNlbnNlVHlwZT5EZXZlbG9wZXIgT0VNPC9MaWNlbnNlVHlwZT4KICAgIDxMaWNlbnNlTm90ZT5MaW1pdGVkIHRvIDEwMDAgZGV2ZWxvcGVyLCB1bmxpbWl0ZWQgcGh5c2ljYWwgbG9jYXRpb25zPC9MaWNlbnNlTm90ZT4KICAgIDxPcmRlcklEPjc4NDM3ODU3Nzg1PC9PcmRlcklEPgogICAgPFVzZXJJRD4xMTk3ODkyNDM3OTwvVXNlcklEPgogICAgPE9FTT5UaGlzIGlzIGEgcmVkaXN0cmlidXRhYmxlIGxpY2Vuc2U8L09FTT4KICAgIDxQcm9kdWN0cz4KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIFByb2R1Y3QgRmFtaWx5PC9Qcm9kdWN0PgogICAgPC9Qcm9kdWN0cz4KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4KICAgIDxTZXJpYWxOdW1iZXI+e0YyQjk3MDQ1LTFCMjktNEIzRi1CRDUzLTYwMUVGRkExNUFBOX08L1NlcmlhbE51bWJlcj4KICAgIDxTdWJzY3JpcHRpb25FeHBpcnk+MjA5OTEyMzE8L1N1YnNjcmlwdGlvbkV4cGlyeT4KICAgIDxMaWNlbnNlVmVyc2lvbj4zLjA8L0xpY2Vuc2VWZXJzaW9uPgogIDwvRGF0YT4KICA8U2lnbmF0dXJlPlFYTndiM05sTGxSdmRHRnNJRkJ5YjJSMVkzUWdSbUZ0YVd4NTwvU2lnbmF0dXJlPgo8L0xpY2Vuc2U+";Stream stream = new MemoryStream(Convert.FromBase64String(LData));stream.Seek(0, SeekOrigin.Begin);mi.Invoke(Activator.CreateInstance(type2, null), new Stream[] { stream });}catch{//throw new InvalidOperationException("SetLicense for \"" + assembly.FullName + "\" failed !");}}private static DateTime InvokeMe1(XmlElement element, string name){return DateTime.MaxValue;}private static XmlElement InvokeMe2(XmlElement element, string name){if (element.LocalName == "License"){string License64 = "PERhdGE+PExpY2Vuc2VkVG8+R3JvdXBEb2NzPC9MaWNlbnNlZFRvPjxMaWNlbnNlVHlwZT5TaXRlIE9FTTwvTGljZW5zZVR5cGU+PExpY2Vuc2VOb3RlPkxpbWl0ZWQgdG8gMTAgZGV2ZWxvcGVyczwvTGljZW5zZU5vdGU+PE9yZGVySUQ+MTMwNzI0MDQwODQ5PC9PcmRlcklEPjxPRU0+VGhpcyBpcyBhIHJlZGlzdHJpYnV0YWJsZSBsaWNlbnNlPC9PRU0+PFByb2R1Y3RzPjxQcm9kdWN0PkFzcG9zZS5Ub3RhbDwvUHJvZHVjdD48L1Byb2R1Y3RzPjxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT48U2VyaWFsTnVtYmVyPjliNTc5NTAxLTUyNjEtNDIyMC04NjcwLWZjMmQ4Y2NkZDkwYzwvU2VyaWFsTnVtYmVyPjxTdWJzY3JpcHRpb25FeHBpcnk+MjAxNDA3MjQ8L1N1YnNjcmlwdGlvbkV4cGlyeT48TGljZW5zZVZlcnNpb24+Mi4yPC9MaWNlbnNlVmVyc2lvbj48L0RhdGE+PFNpZ25hdHVyZT5udFpocmRoL3I0QS81ZFpsU2dWYnhac0hYSFBxSjZ5UVVYa0RvaW4vS2lVZWhUUWZET0lQdHdzUlR2NmRTUVplOVdXekNnV3RGdkdROWpmR2QySmF4YUQvbkx1ZEk2R0VVajhqeVhUMG4vbWRrMEF1WVZNYlBXRjJYd3dSTnFlTmRrblYyQjhrZVFwbDJ2RzZVbnhxS2J6VVFxS2Rhc1pzZ2w1Q0xqSFVEWms9PC9TaWduYXR1cmU+";element.InnerXml = new UTF8Encoding().GetString(Convert.FromBase64String(License64));}if (element.LocalName == "BlackList"){string BlackList64 = "PERhdGE+PC9EYXRhPjxTaWduYXR1cmU+cUJwMEx1cEVoM1ZnOWJjeS8vbUVXUk9KRWZmczRlY25iTHQxYlNhanU2NjY5RHlad09FakJ1eEdBdVBxS1hyd0x5bmZ5VWplYUNGQ0QxSkh2RVUxVUl5eXJOTnBSMXc2NXJIOUFyUCtFbE1lVCtIQkZ4NFMzckFVMnd6dkxPZnhGeU9DQ0dGQ2UraTdiSHlGQk44WHp6R1UwdGRPMGR1RTFoRTQ5M1RNY3pRPTwvU2lnbmF0dXJlPg==";element.InnerXml = new UTF8Encoding().GetString(Convert.FromBase64String(BlackList64));}XmlNodeList elementsByTagName = element.GetElementsByTagName(name);if (elementsByTagName.Count <= 0){return null;}return (XmlElement)elementsByTagName[0];}private static unsafe void MemoryPatching(MethodBase miEvaluation, MethodBase miLicensed){IntPtr IntPtrEval = GetMemoryAddress(miEvaluation);IntPtr IntPtrLicensed = GetMemoryAddress(miLicensed);if (IntPtr.Size == 8)*((long*)IntPtrEval.ToPointer()) = *((long*)IntPtrLicensed.ToPointer());else*((int*)IntPtrEval.ToPointer()) = *((int*)IntPtrLicensed.ToPointer());}private static unsafe IntPtr GetMemoryAddress(MethodBase mb){RuntimeHelpers.PrepareMethod(mb.MethodHandle);if ((Environment.Version.Major >= 4) || ((Environment.Version.Major == 2) && (Environment.Version.MinorRevision >= 3053))){return new IntPtr(((int*)mb.MethodHandle.Value.ToPointer() + 2));}UInt64* location = (UInt64*)(mb.MethodHandle.Value.ToPointer());int index = (int)(((*location) >> 32) & 0xFF);if (IntPtr.Size == 8){ulong* classStart = (ulong*)mb.DeclaringType.TypeHandle.Value.ToPointer();ulong* address = classStart + index + 10;return new IntPtr(address);}else{uint* classStart = (uint*)mb.DeclaringType.TypeHandle.Value.ToPointer();uint* address = classStart + index + 10;return new IntPtr(address);}}}
}namespace pptToImage
{public class Class1{/// <summary>/// 将PPT、Excel、Txt文档转换为图片的方法      /// </summary>// <param name="originFilePath">ppt文件路径</param>// <param name="imageOutputDirPath">图片输出路径,如果为空,默认值为pdf所在路径</param>       // <param name="startPageNum">从PDF文档的第几页开始转换,如果为0,默认值为1</param>// <param name="endPageNum">从PDF文档的第几页开始停止转换,如果为0,默认值为pdf总页数</param>       // <param name="resolution">设置图片的像素,数字越大越清晰,如果为0,默认值为128,建议最大值不要超过1024</param>public void ConvertToImage_PPT(string originFilePath){string imageOutputDirPath = string.Empty;int startPageNum = 0, endPageNum = 0, resolution = 0;string Format = Path.GetExtension(originFilePath).ToLower();try{//先将文件转换为pdf临时文件string tmpPdfPath = originFilePath.Replace(Format, ".pdf");if (Format == ".xls" || Format == ".xlsx" || Format == ".txt"){Workbook wb = new Workbook(originFilePath);wb.Save(tmpPdfPath, SaveFormat.Pdf);}else{Aspose.Slides.Presentation doc = new Aspose.Slides.Presentation(originFilePath);if (doc == null){throw new Exception("ppt文件无效或者ppt文件被加密!");}if (imageOutputDirPath.Trim().Length == 0){imageOutputDirPath = Path.GetDirectoryName(originFilePath);}if (!Directory.Exists(imageOutputDirPath)){Directory.CreateDirectory(imageOutputDirPath);}if (startPageNum <= 0){startPageNum = 1;}if (endPageNum > doc.Slides.Count || endPageNum <= 0){endPageNum = doc.Slides.Count;}if (startPageNum > endPageNum){int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;}if (resolution <= 0){resolution = 128;}if (doc != null){doc.Save(tmpPdfPath, Aspose.Slides.Export.SaveFormat.Pdf);}}//再将pdf转换为图片ConvertToImage_PDF(tmpPdfPath, imageOutputDirPath, startPageNum, endPageNum, resolution);//删除pdf临时文件File.Delete(tmpPdfPath);return ;}catch (Exception ex){//ErrorHandler.WriteError(ex);//IErrorHandler.WriteError(ex);//IErrorHandler.WriteError(ex);Console.WriteLine(ex);return ;throw;}}/// <summary>/// 将pdf文档转换为图片的方法      /// </summary>// <param name="originFilePath">pdf文件路径</param>// <param name="imageOutputDirPath">图片输出路径,如果为空,默认值为pdf所在路径</param>       // <param name="startPageNum">从PDF文档的第几页开始转换,如果为0,默认值为1</param>// <param name="endPageNum">从PDF文档的第几页开始停止转换,如果为0,默认值为pdf总页数</param>       // <param name="resolution">设置图片的像素,数字越大越清晰,如果为0,默认值为128,建议最大值不要超过1024</param>public void ConvertToImage_PDF(string originFilePath, string imageOutputDirPath, int startPageNum, int endPageNum, int resolution){try{Aspose.Pdf.Document doc = new Aspose.Pdf.Document(originFilePath);if (doc == null){throw new Exception("pdf文件无效或者pdf文件被加密!");}if (imageOutputDirPath.Trim().Length == 0){imageOutputDirPath = Path.GetDirectoryName(originFilePath);}if (!Directory.Exists(imageOutputDirPath)){Directory.CreateDirectory(imageOutputDirPath);}if (startPageNum <= 0){startPageNum = 1;}if (endPageNum > doc.Pages.Count || endPageNum <= 0){endPageNum = doc.Pages.Count;}if (startPageNum > endPageNum){int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;}if (resolution <= 0){resolution = 128;}string imageNamePrefix = Path.GetFileNameWithoutExtension(originFilePath).ToLower();string imgName = string.Empty;string newPath = Path.Combine(imageOutputDirPath, imageNamePrefix) + "/";// 创建目录路径if (!Directory.Exists(newPath)){Directory.CreateDirectory(newPath);}for (int i = startPageNum; i <= endPageNum; i++){MemoryStream stream = new MemoryStream();//string imgPath = Path.Combine(imageOutputDirPath, imageNamePrefix) + "_" + i.ToString("000") + ".jpg";string imgPath = newPath + (i-1).ToString("0") + ".png";// imgName += imgUrl + "/" + imageNamePrefix + "_" + i.ToString("000") + ".jpg|";imgName += newPath + (i-1).ToString("0") + ".png|";Aspose.Pdf.Devices.Resolution reso = new Aspose.Pdf.Devices.Resolution(resolution);Aspose.Pdf.Devices.JpegDevice jpegDevice = new Aspose.Pdf.Devices.JpegDevice(reso, 100);jpegDevice.Process(doc.Pages[i], stream);Image img = Image.FromStream(stream);Bitmap bm = ESBasic.Helpers.ImageHelper.Zoom(img, 0.6f);bm.Save(imgPath, ImageFormat.Png);img.Dispose();stream.Dispose();bm.Dispose();System.Threading.Thread.Sleep(200);}if (!string.IsNullOrEmpty(imgName)){imgName = imgName.Substring(0, imgName.Length - 1);}return ;}catch (Exception ex){// ErrorHandler.WriteError(ex);Console.WriteLine(ex);throw;}}}
}

在上面链接中下载Aspose的dll动态库,把这些动态库和我修改的代码一起编译,生成pptToImage.dll的C#动态库。

2. 新建C++/CLI的类库项目。截图如下:

我的C++/CLI的类库代码如下:

// ToCppDll_CsharpDll.h#pragma once//namespace ToCppDll_CsharpDll {
//
//  public ref class Class1
//  {
//      // TODO:  在此处添加此类的方法。
//
//  };
//}extern "C" __declspec(dllexport)
void ConvertToImage_PPT(char* originFilePath);// 这是主 DLL 文件。#include "stdafx.h"#include "ToCppDll_CsharpDll.h"
#include <string>using namespace System;using namespace Runtime::InteropServices;using namespace pptToImage;
using namespace LicenseHelper;__declspec(dllexport)
void ConvertToImage_PPT(char* originFilePath)
{LicenseHelper::ModifyInMemory::ActivateMemoryPatching();Class1 ^cls = gcnew Class1();String ^inputPath = gcnew String(originFilePath);cls->ConvertToImage_PPT(inputPath);}

编译以上代码,会生成ToCppDll_CsharpDll.dll,ToCppDll_CsharpDll.lib的动态库,在非托管 C++的环境中就可以使用这两个库了,当然上面生成的C#动态库和Aspose的动态库也都是需要。这个C++/CLI的ToCppDll_CsharpDll库相当于一个桥梁的作用,连接非托管的C++环境和.net 应用程序环境。这一步也是对C#的动态库进行封装,封装成了一个C++/CLI的动态库,非托管的C++程序中能够像调用普通的C/C++库一样调用这个库。

3. 这个是测试主程序了,不需要设置/clr。代码如下:


#include <stdio.h>
#include <stdlib.h>#include "../CppCliInclude/ToCppDll_CsharpDll.h"//#pragma  comment(lib,"ToCppDll_CsharpDll.lib")int main(int argc, char *argv[])
{char *pTemp = "C:/Users/tz100/Desktop/title.ppt";ConvertToImage_PPT(pTemp);getchar();return 0;
}

由于是刚刚接触这些C#,托管C++/CLI语言和VS IDE环境,导致我走了太多的弯路,浪费了许多的时间,心累了多次,终于有了上面的一点点收获,这或许是对自己最大的勉励吧。

注意事项:

1> 编译程序的时候注意引用C#动态库,C++/CLI库。

2> 如果还有问题先自己上网查查,实在解决不了再留言吧。

非托管C++程序中调用C#的dll相关推荐

  1. 利用c#实现远程注入非托管WIN32程序,并利用嵌入汇编调用非托管WIN32程序中的内部过程...

    c#通过调用windows API函数,可以很轻松的完成非托管WIN32程序的注入.内存读写等操作,以下为c#实现远程注入非托管WIN32程序,并利用嵌入汇编调用非托管WIN32程序中的内部过程的源码 ...

  2. 本地方法(JNI)——从java 程序中调用C函数

    [0]README 1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法--从java 程序中调用C函数 的基础知识 : 2) for source code, ...

  3. [翻译]Kean' Blog 在一个.NET应用程序中调用AutoCAD

    程序员通常要么整合功能到AutoCAD(利用其Plug-in结构,以增加命令,用户界面,对象等),或者调用它自动完成任务.显然,这两者之间的界限已经比较模糊,但是今天我们重点介绍第二类. 用于帮助理解 ...

  4. 在VB应用程序中调用Excel2000

    Visual Basic简称(VB)是设计Windows应用程序强有力的开发工具,"全球绝大多数Windows应用程序都是用VB开发的": Excel是目前使用最广泛的办公应用软件 ...

  5. Linux jsp php集成环境,ImageMagick在程序中调用(linux环境,jsp,php)

    最近发现图片格式为cmyk时,图片上传浏览器不能正常显示,图片缩放会变成黑屏, 后来通过google发现imagemagick的功能很强大,安装可以采用两种方法,1)直接与php编译安装,在程序中调用 ...

  6. SQL Server 2005 - 如何在预存程序中调用另外一个预存程序

    要在一个预存程序中调用另外一个预存程序,可以使用下列两种方式之一进行调用:  <?xml:namespace prefix = o /> EXECUTE <欲执行之预存程序的名称&g ...

  7. 在Delphi程序中调用控制面板设置功能

    ====================================================== 注:本文源代码点此下载 ================================= ...

  8. 安卓程序中调用 linux 命令

    博客: 安卓之家 微博: 追风917 CSDN: 蒋朋的家 简书: 追风917 在研究串口 jni 开发的时候,遇到了这样一段代码: Process su;su = Runtime.getRuntim ...

  9. iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话,iTunes,iBooks )...

    在网上找到了下在记录下来以后方便用 在程序中调用系统自带的应用,比如我进入程序的时候,希望直接调用safar来打开一个网页,下面是一个简单的使用: 查看更多iPhone应用程序的调用和第三方应用程序的 ...

最新文章

  1. php发卡_发卡网代码审计
  2. OpenAI的GPT-3花费了1200万美元,现在放出商用API,人人皆可用
  3. 查询用户所有信息后只需要两个字段的信息_Excel VBA+ADO+SQL入门教程023:OpenSchema获取表信息...
  4. java 判断客户端_javaweb服务端判断客户端使用的是手机还是电脑访问
  5. (40)不确定性约束
  6. 设置CMD窗口为UTF-8编码
  7. android 通过短信找回密码,如何通过强力安卓恢复精灵找回丢失的手机短信?
  8. 简约大气毕业论文答辩PPT模板
  9. java汉字转拼音或效验汉字是否存在(过滤)
  10. Arduino操控1602 LCD液晶屏
  11. STM32F103C8T6串口通信
  12. VMware安装Kali2021虚拟机
  13. 计算机图形学迷宫论文,三维迷宫的设计与制造
  14. 深入理解Android系统多用户
  15. java 森林_森林 - Minecraft Wiki,最详细的官方我的世界百科
  16. 【第一天日记-html】
  17. 圣诞节,深圳街头有点冷清了~
  18. 数字赋能 共创未来憨猴科技“共域时代”年度大会成功举办
  19. 实战:windows上如何安装kubectl并连接我们的k8s集群(测试成功-博客输出)-2022.1.3
  20. app store/ios开发证书、发布证书、推送证书的快捷制作

热门文章

  1. 正常血压c语言编程,关于测试血压的C语言编程,要求有纠错功能,最少能输入五组数据...
  2. Win10系统FF新推荐怎么卸载?FF新推荐新闻弹窗彻底关闭删除教程
  3. pta 吉老师的回归(C语言实现)
  4. 我与TDengine的故事
  5. 公众演讲如何脱稿演讲
  6. 321_MediaType Media Type 是什么
  7. C++ 进程退出后,子线程还会存在吗?
  8. numpy.polyfit(x,y,deg=?) 中的deg的意思
  9. 用python画玫瑰花 表白浪漫
  10. BigInteger 用法详解