中望3D二次开发 控制台命令转PDF

中望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; }
    }

数据库的设计是:

最终效果是:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq285503851

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值