中望3D的外部开发模式命令非常少,没有办法使用远程办法打开文件,将图纸转换为PDF(听说以后的版本会有,但是在2022版本上是没有的);
ps:远程方式,意思就是远程电脑必须开启中望3D软件,也可以是本机;
以下就是中望3D远程的函数
/*
** (C) Copyright 2016, ZWCAD Software Co., Proprietary and Trade Secret
*/
#pragma once#ifndef ZW3D_RPC_API_H
#define ZW3D_RPC_API_H#ifndef ZS_RPC_API
# ifdef ZS_RPC_BUILD
# define ZS_RPC_API __declspec(dllexport)
# else
# define ZS_RPC_API __declspec(dllimport)
# endif
#endif#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */typedef struct ZwRpcExportDWG{char file[256];char part[256];double x_axis[3];double y_axis[3];char isFirstAngle;char isExportToDXF;char isShowDim; /* show dimensions from part(1) or not(0) */} ZwRpcExportDWG;ZS_RPC_API void ZwRpcInitialize(const char *host, int port);
ZS_RPC_API int ZwRpcIsAvailable(int wait);
ZS_RPC_API int ZwRpcPartExportToDWG(ZwRpcExportDWG *data);
ZS_RPC_API int ZwRpcPartConvert(const char from[256], const char part[256], const char to[256]);
ZS_RPC_API int ZwRpcPartRegen(const char file[256], const char part[256]);
ZS_RPC_API int ZwRpcCmdSend(const char cmd[256]);
ZS_RPC_API int ZwRpcCmdMacro(const char file[256]);#ifdef __cplusplus
}
#endif /* __cplusplus */#endif
那么只有想其它的办法了,我看到它可以发送命令,想到在中望3D上做一个插件,然后远程发送一个命令就可以了,当然是没有办法传递参数的,只能使用数据库读写想要的数据了,数据库就选择本地sqlite数据库;
中望3D的插件,主要负责读取数据库里需要转换的文件,然后打开,转换为PDF后,再关闭文档,这里再开发时遇到几个问题:
1,打开一个绝对路径的文档,再关闭文档,会发现并没有关闭干净;
2,如果是多个图纸页,转换是一个个的PDF,需要合并;
解决办法是:
1,使用方法不对,需要先添加路径,再打开文档,则可以正常关闭;
2,没有找到好的C++库 合并PDF,调用C#写的控制台应用程序;
以下是主要代码
std::string TCHAR2STRING(TCHAR* str)
{std::string strstr;try{int iLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);char* chRtn = new char[iLen * sizeof(char)];WideCharToMultiByte(CP_ACP, 0, str, -1, chRtn, iLen, NULL, NULL);strstr = chRtn;}catch (std::exception e){}return strstr;
}
//获得自生DLL句柄
HMODULE GetSelfModuleHandle()
{MEMORY_BASIC_INFORMATION mbi;return ((::VirtualQuery(GetSelfModuleHandle, &mbi, sizeof(mbi)) != 0)? (HMODULE)mbi.AllocationBase : NULL);
}std::string GetExecFilePath()
{TCHAR szBuffer[MAX_PATH] = { 0 };DWORD dwError = GetModuleFileName(GetSelfModuleHandle(), szBuffer, ARRAYSIZE(szBuffer));if (dwError > 0){//char msg[256];//TcharToChar(szBuffer, msg);std::string ExecFile = TCHAR2STRING(szBuffer);int pos = ExecFile.find_last_of('\\');if (pos > 0){ExecFile = ExecFile.substr(0,pos);//pos = ExecFile.ReverseFind('\\');//if (pos > 0)// ExecFile = ExecFile.Left(pos);}return ExecFile;}return std::string("");
}std::wstring Utf82Unicode(const std::string& utf8string)
{int widesize = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, NULL, 0);if (widesize == ERROR_NO_UNICODE_TRANSLATION){throw std::exception("Invalid UTF-8 sequence.");}if (widesize == 0){throw std::exception("Error in conversion.");}std::vector<wchar_t> resultstring(widesize);int convresult = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, &resultstring[0], widesize);if (convresult != widesize){throw std::exception("La falla!");}return std::wstring(&resultstring[0]);
}
std::string WString2String(const std::wstring& ws)
{std::string strLocale = setlocale(LC_ALL, "");const wchar_t* wchSrc = ws.c_str();size_t nDestSize = wcstombs(NULL, wchSrc, 0) + 1;char *chDest = new char[nDestSize];memset(chDest, 0, nDestSize);wcstombs(chDest, wchSrc, nDestSize);std::string strResult = chDest;delete[]chDest;setlocale(LC_ALL, strLocale.c_str());return strResult;
}std::string Unicode2Utf8(const std::wstring& widestring) {using namespace std;int utf8size = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, NULL, 0, NULL, NULL);if (utf8size == 0){throw std::exception("Error in conversion.");}std::vector<char> resultstring(utf8size);int convresult = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, &resultstring[0], utf8size, NULL, NULL);if (convresult != utf8size){throw std::exception("La falla!");}return std::string(&resultstring[0]);
}// std::string 转 wstring
std::wstring str2wstr(const std::string& s)
{int len;int slength = (int)s.length() + 1;len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);wchar_t* buf = new wchar_t[len];MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);std::wstring r(buf);delete[] buf;return r;
}
// std:wstring 转 LPWSTR
LPWSTR ws2LPWSTR(const std::wstring& ws) {return const_cast<LPWSTR>(ws.c_str());
}int ExportPdf(vxPath DrawFile, vxPath PdfPath, vxPath error)
{int iRet = 0;vxPath OldFilePath;cvxFileInqActive(OldFilePath, sizeof(OldFilePath));char path_buffer[128];char drive[10];char dir[128];char filename[128];char ext[10];_splitpath_s(DrawFile, drive, dir, filename, ext);vxLongName cname;strcpy(cname, drive);strcat(cname, dir);cvxPathAdd(cname);strcpy(cname, filename);strcat(cname, ext);//打开文件iRet = cvxFileOpen(cname);if (iRet == 1){sprintf(error, "文件打开失败!");return iRet;}//iRet = cvxPartRegenIsActive();iRet = cvxFileActivate(cname);char Name[256];cvxRootInqActive(Name, sizeof(Name));if (Name == NULL){sprintf(error, "文件打开失败!");return 1;}int idRoot;evxRootType Type;iRet = cvxRootId(Name, &idRoot, &Type);if (iRet == 1){sprintf(error, "无法获得根节点标识!");return iRet;}int count;int* idDrawings;cvxMemZero((void*)&idDrawings, sizeof(int));iRet = cvxDwgInqList(idRoot, &count, &idDrawings);if (iRet == 1){sprintf(error, "文件可能不是图档!");return iRet;}if (count == 0){sprintf(error, "文件没有包含图档!");return 1;}char filename2[128];_splitpath_s(PdfPath, drive, dir, filename2, ext);if (filename2==NULL||strcmp(filename2,"")==0){strcpy(filename2, filename);}_makepath_s(path_buffer, drive, dir, filename2, ".pdf");SQLite::Database db("C:\\Users\\Administrator\\Documents\\DrawDb.db"); // std::string ReadPdfExe;bool bExists = db.tableExists("sys_config");if (bExists){const const std::string value = db.execAndGet("select value from sys_config where key = 'MergePDFPath'");ReadPdfExe = WString2String(Utf82Unicode(value));} else{ReadPdfExe = GetExecFilePath() + "\\MergePDF.exe";}//std::string std::string szCommandLine = ReadPdfExe +" \"" + std::string(path_buffer) + "\"";for (int i = 0; i < count; i++){vxName dwg_name;cvxDwgInqName(idDrawings[i], dwg_name, sizeof(vxName));iRet = cvxDwgActivate(dwg_name);svxDrawingAt dwg_attribute;cvxDwgAtGet(idDrawings[i], &dwg_attribute);svxPdfData data;cvxMemZero((void*)&data, sizeof(svxPdfData));data.Type = evxPdfType::VX_EXPORT_PDF_TYPE_VECTOR;data.Color = 1;data.Dpi = 72;//- 这里文档描述有误,实际测试 1 = 多段线 0 = text//data.TextOutStyle = 1;//data.LineWidthScale = 0.5;data.PaperWidth = dwg_attribute.width;data.PaperHeight = dwg_attribute.height;data.Rect.X = { 0,420 };data.Rect.Y = { 0,297 };data.Rect.Z = { 0,0 };data.RangeMode = evxPdfRangeMode::VX_EXPORT_PDF_RANGE_MODE_CUSTOM;//data.ExportMultiSheet = 1;char path[128];sprintf(path, "%s-%d", filename2, i + 1);_makepath_s(path_buffer, drive, dir, path, ".pdf");szCommandLine += " \"" + std::string(path_buffer) + "\"";iRet = cvxFileExport(evxExportType::VX_EXPORT_TYPE_PDF, path_buffer, &data);if (iRet == 1){break;}}STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));si.dwFlags = STARTF_USESHOWWINDOW; //设置隐藏执行窗口 si.wShowWindow = SW_HIDE;if (CreateProcess(NULL,//_T("/c ") + ReadPdfPath,ws2LPWSTR(str2wstr(szCommandLine)),//LPWSTR(szCommandLine.GetString()), // Command line. There should be a space at the beginning NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. FALSE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi) // Pointer to PROCESS_INFORMATION structure. ){WaitForSingleObject(pi.hProcess, INFINITE);CloseHandle(pi.hProcess);CloseHandle(pi.hThread);}cvxMemFree((void**)&idDrawings);if (OldFilePath!=NULL){cvxFileActivate(OldFilePath);//}cvxFileClose2(cname, 2);//cvxFileClose2(NULL, 2);//cvxFileClose();if (iRet == 1){sprintf(error, "转换PDF失败!");}return iRet;}int ExportPdfApi(void)
{try{SQLite::Database db("C:\\Users\\Administrator\\Documents\\DrawDb.db", SQLite::OPEN_READWRITE); // SQLite::OPEN_READONLYbool bExists = db.tableExists("nvt_draw");if (bExists){SQLite::Statement query(db, "SELECT id,DrawFile,PdfFile FROM nvt_draw where status = 0");std::vector<std::string>lstSql;while (query.executeStep()){char draw[254];strcpy(draw, WString2String(Utf82Unicode(query.getColumn("DrawFile").getString())).c_str()); char pdf[254]; strcpy(pdf, WString2String(Utf82Unicode(query.getColumn("PdfFile").getString())).c_str());vxPath error="";bool isExc = ExportPdf(draw, pdf, error) == 0;std::string update = "UPDATE nvt_draw SET update_date=datetime('now','localtime'),status="+ std::string(isExc ?"1":"0")+",info = '" + std::string(error) + "' WHERE status= 0 and id = " + query.getColumn("id").getString();lstSql.push_back(update);}query.reset();for (int i=0;i<lstSql.size();++i){std::string update = lstSql.at(i);int nb = db.exec(Unicode2Utf8(std::wstring(update.begin(), update.end())));}}return 1;}catch (std::exception& e){}return 0;
}
sqlite数据库是使用SQLiteCpp,已经封装好,地址:https://gitee.com/aubo-robotics/SQLiteCpp?_from=gitee_search
//下面是c#写的合并PDF的主要代码
//传递第一个参数是合并之后的PDF,后面的参数是要合并的PDF
static void Main(string[] args){if (args == null || args.Length < 2){Console.WriteLine("没有输入参数 或 参数不正确");return;}string pdfPath = string.Empty;List<string> ls_pdfs = new List<string>();foreach(string item in args){if (string.IsNullOrEmpty(item))continue;System.IO.FileInfo file = new System.IO.FileInfo(item);if(file==null||!file.Extension.Equals(".pdf"))continue;if(string.IsNullOrEmpty(pdfPath)){pdfPath = item;}else{ls_pdfs.Add(item);}Console.WriteLine("传递参数:"+ item);}if (ls_pdfs.Count <= 0){Console.WriteLine("pdf数量为0,无法转换!");return;}//合并输出PdfDocumentBase pdfDoc = PdfDocument.MergeFiles(ls_pdfs.ToArray());pdfDoc.Save(pdfPath, FileFormat.PDF);foreach (string _file in ls_pdfs){Console.WriteLine("删除文件:"+ _file);File.Delete(_file);}}
//下面是外部程序的远程方法主要代码
//插入数据nvt_draw draw = new nvt_draw{DrawFile = @"C:\Users\Administrator\Documents\ZW3D\工程图001.Z3DRW",PdfFile = @"C:\Users\Administrator\Documents\ZW3D\工程图001.pdf",};db.Insert<nvt_draw>(draw);string server = "local";IntPtr serverPtr = Marshal.StringToHGlobalAnsi(server);string cmd = "~ExportPdfApi";IntPtr cmdPtr = Marshal.StringToHGlobalAnsi(cmd);int res = ZW3DCmd_Pub(serverPtr, cmdPtr);
[Table("nvt_draw")]public class nvt_draw{[Key]public int id { set; get; }public string DrawFile { set; get; }public string PdfFile { set; get; }public int status { set; get; }public string info { set; get; }public string update_date { set; get; }}
数据库的设计是:
最终效果是: