通過COM呼叫, 讀取AutoCAD機械版Bom表

yzhuang發表於2018-05-31

AutoCad提供COM呼叫互操作,但是通過VC呼叫的相關資料少的可憐,在網上基本查不到,去Autodesk官網上找居然也沒有相應的說明,都得靠自個兒摸索呀。

第一步,建立一個VC的工程, 不多說了。

第二步,匯入相關的AutoCAD相關的COM型別庫,在工程檔案加上電機右鍵,選擇新增 -> 類 -> C++ -> VisulC++ -> MFC -> TypeLibvs 的MFC類, 如下圖:



需要從三個型別庫中匯入, 下圖中畫框的部分


裡面有很多個介面標頭檔案,選中我們需要的幾個標頭檔案匯入即可,或者全部選中匯入。本次工作用到的只有如下的9個:

#include "CAcadApplication.h"
#include "CAcadDocument.h"
#include "CAcadModelSpace.h"
#include "CAcadDocuments.h"
#include "CAcadEntity.h"
#include "CMcadPartList.h"
#include "CMcadBOMItems.h"
#include "CMcadBOMItem.h"

#include "CMcadBOM.h"

第三部:建立AutoCAD的COM例項

CAcadApplication* m_pAcadApplication = NULL;

BOOL OpenAutoCAD()
{
	BOOL bResult = FALSE;
	CString strId = _T("AutoCAD.Application");	// 預設版本

	CLSID clsid;
	HRESULT hRlt = ::CLSIDFromProgID(strId, &clsid);
	if (FAILED(hRlt))
	{
		AfxMessageBox(_T("當前機器上沒有安裝 AutoCAD 軟體, 或沒有指定的版本號。"));
	}

	ASSERT(NULL == m_pAcadApplication);
	m_pAcadApplication = new CAcadApplication();

	// 檢查是否已經有ACAD程式開啟了
	IUnknown* pUnknown = NULL;
	hRlt = ::GetActiveObject(clsid, NULL, &pUnknown);
	if (SUCCEEDED(hRlt) ) 
	{
		hRlt = pUnknown->QueryInterface(IID_IDispatch, (LPVOID*)m_pAcadApplication);
		bResult = SUCCEEDED(hRlt);
		if (!bResult)
		{
			pUnknown->Release();
			pUnknown = NULL;
		}
	}

	if (!bResult) 
	{
		bResult = m_pAcadApplication->CreateDispatch(strId);
	}

	if (!bResult) 
	{
		AfxMessageBox(_T("起動 AutoCAD 軟體失敗。"));
	}

	return bResult;
}

第四步:讀入BOM資料

void ReadBomData()
{
	
	CString strFile;
	HMODULE hModule = ::GetModuleHandle(NULL);
	::GetModuleFileName(hModule, strFile.GetBuffer(MAX_PATH), MAX_PATH);
	strFile.ReleaseBuffer();

	int iPos = strFile.ReverseFind('\\');
	if (iPos > 1)
		strFile.Truncate(iPos);

	strFile += _T("\\讀入Bom示例.dwg");

	if (OpenAutoCAD())
	{
		// 新增一個新的頁面
		CAcadDocuments clDocs  = m_pAcadApplication->get_Documents();
		clDocs.Open(strFile, _variant_t(FALSE), COleVariant(_T("")));

		CAcadDocument m_pAcadDocument  = m_pAcadApplication->get_ActiveDocument();
		CAcadModelSpace m_pAcadModelSpace = m_pAcadDocument.get_ModelSpace();

		for (int i=0; i<m_pAcadModelSpace.get_Count(); i++)
		{
			CAcadEntity clEntity = m_pAcadModelSpace.Item(_variant_t(i));

			CString str;
			if (clEntity.get_EntityName() == _T("AcmPartList"))
			{
				CMcadPartList clPartList = clEntity.DetachDispatch();
				CMcadBOMItems clItems =  clPartList.get_ItemList();

				for (long j=0; j<clItems.get_Count(); j++)
				{
					CMcadBOMItem clItem = clItems.Item(j);
					COleSafeArray arData = clItem.get_Data();

					long lBound1 = -1;
					long uBound1 = -1;
					long lBound2 = -1;
					long uBound2 = -1;
					arData.GetLBound(1, &lBound1);
					arData.GetUBound(1, &uBound1);
					arData.GetLBound(2, &lBound2);
					arData.GetUBound(2, &uBound2);

					BSTR *pbstr;
					arData.AccessData((LPVOID*)&pbstr);

					

					int idx = 0;
					for (int r=0; r<uBound2-lBound2+1; r++)
					{
						str.Format(_T("%s\t"), clItem.get_ItemNumber());
						for (int c=0; c<uBound1-lBound1+1; c++)
						{
							str.AppendFormat(_T("%s\t"), pbstr[idx++]);
						}
						str += '\n';
						OutputDebugString(str);
					}

					ASSERT(uBound1-lBound1+1 == 9);
					ASSERT(uBound2-lBound2+1 == 2);

					pbstr += 9;

					str.Format(_T("%s"), clItem.get_ItemNumber());
					m_lstBom.SetItemText(j, 0, str);
					m_lstBom.SetItemText(j, 1, pbstr[4]);
					m_lstBom.SetItemText(j, 2, pbstr[7]);
					m_lstBom.SetItemText(j, 3, pbstr[8]);
					m_lstBom.SetItemText(j, 4, pbstr[6]);
					m_lstBom.SetItemText(j, 5, pbstr[1]);
					m_lstBom.SetItemText(j, 6, pbstr[0]);
					m_lstBom.SetItemText(j, 7, pbstr[5]);

					arData.UnaccessData();
				}
			}
		}
	}

	delete m_pAcadApplication;
}
m_lstBom是個listCtrl控制元件

詳細請參考示例程式碼: https://download.csdn.net/download/yzhuang/10449286


相關文章