中望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_READONLY
bool 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; }
}
数据库的设计是:
最终效果是: