封装的原因
Creo的接口有:Creo Toolkit (C语言),Creo Object Toolkit (C++),Creo Object Toolkit (Java),vbapi,weblink。其中Creo Toolkit (C语言)提供的接口最全,但是使用 C 语言开发又会有开发效率的问题。基于以上原因,将C接口进行进一步封装,兼顾功能与效率的问题。
基于Creo内部数据结构的封装方法
分析整理 Creo 提供的C接口中的数据结构,将他们分为以下几个类型:
- Pod Object 可以直接进行内存拷贝的对象或数据:
- ProModelitem(这种数据非常常见,用处非常多)
- ProAsmcompath
- ProMatrix
- 等等;
- Handle Object:指针(句柄),但是由Creo内部管理内存的分配与释放。如:
- ProMdl
- Not Copyable Object:指针,不可以拷贝,需要用户自行管理内存的 Alloc 与 Free 。如:
- ProSelection
- 各种 Data等。
- 其他。
封装类图(见附件):
PtkPkgLib-类图.pdf
(注:类图中的类不全,目前未包含大量的ProMech相关类)
字符串的处理:
程序在处理过程中会大量的使用字符串,在Creo内部支持utf8编码的char及Unicode编码的wchar_t。不支持Multi byte编码,需要自己转换。建议默认使用Unicode编码。
字符串的使用。默认使用 stl 里面的 std::wstring 处理。需要特别注意,std::wstring在跨dll使用时,会出现内存异常 crash 。在必须跨dll使用时,转换成 char 或者 wchar_t。
解耦
字符串的使用会造成Protoolkit与stl代码的耦合。封装过程中主要使用到的stl中类有std::string
, std::wstring
, std::vector
。
string解耦
新定义字符串类型 ptkstring, ptkwstring(便于因需要重定义为其他类型,如QString等)
//utf8
typedef std::string ptkstring;
//unicode
typedef std::wstring ptkwstring;
string转char,wstring 转 wchar_t 都使用宏
_PtkString2Ptr
处理。
_PtkString2Ptr
的实现:
template <typename T> T* ptkConstCastPtr(const T* _item) {
return const_cast<T*>(_item); }
#define _PtkString2Ptr(str) _PtkStringIsEmpty(str) ? nullptr: ptkConstCastPtr(str.c_str())
vector解耦
类似于String,耦合处尽可能使用宏定义来实现
//vector
#define ptkvector std::vector
//set
#define ptkset std::set
内存的管理
Creo Toolkit C 使用过程中会有很多数据对象需要用户自己 Alloc & Free,这无疑很大程度上增加了编程人员的负担。为此,在封装的过程中,增加了以下几个宏:_ScopeClassCrt,_DefineObjectHasScope,_DefineObjectNoScope,_UserControlObjectStructor
宏 _UserControlObjectStructor:
用来快速创建派生自 _UserControlObject类 类的构造函数、析构函数。降低代码量。
宏 _ScopeClassCrt:
_ScopeClassCrt用来快速创建数据对象的“生命域”类,实现代码如下:
#define _ScopeClassCrt(_class) \
class Scope { \
public: \
Scope(_class& _hdl):_ObjectPtr(&_hdl) {}; \
~Scope() {_ObjectPtr->Free();}; \
private: \
_class* _ObjectPtr; \
};
以 ProSelection
的封装 ptkSelection
为例,如下:
class ptkSelection :
public _UserControlObject<ProSelection>
{
public:
_UserControlObjectStructor(Selection);
_ScopeClassCrt(ptkSelection);
public:
void Free();
};
在类 ptkSelection 中,使用宏
_ScopeClassCrt(ptkSelection)
,它将会在类ptkSelection
中定义一个ptkSelection::``Scope
类,用 Scope 类定义的对象在析构时,将会调用ptkSelection
的Free
函数,来释放内存。
Scope使用方法:
1.标准使用方法
ptkSelection selection;
ptkSelection::Scope selection_scope(selection);
这样就可以在 data_scope 析构时,将 selection 中的数据 Free 掉。
2.结合 _DefineObjectHasScope
来使用:
_DefineObjectHasScope(ptkSelection,selection);
_DefineObjectHasScope
宏将会与上面的标准使用方法达到相同的效果。
3.如果代码需要调整,不需“生命域”要释放内存,可以直接将上诉定义方法改为:
_DefineObjectNoScope(ptkSelection,selection);
降低代码变更带来的代码变更量。
宏_DefineObjectHasScope
与 _DefineObjectNoScope
请参照 宏 _ScopeClassCrt 的使用
_DefineObjectHasScope
#define _DefineObjectHasScope(class_name, obj_inst) \
class_name obj_inst; \
class_name::Scope scope_##obj_inst(obj_inst);
_DefineObjectNoScope
#define _DefineObjectNoScope(class_name, obj_inst) class_name obj_inst;