一、需求分析
在用MASM32编程更新完善SysInfo的网络连接信息,用到了MIB_TCP6TABLE_OWNER_MODULE结构体:
typedef struct _MIB_TCP6TABLE_OWNER_MODULE { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_MODULE table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_MODULE, *PMIB_TCP6TABLE_OWNER_MODULE;
MASM32内置的inc文件没有包含 这个结构体的定义,需要自己DIY。
结构体成员数量少还行,如果成员数量多的话,手工转换繁琐易出错,于是在之前写的
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
的基础上增加了C++ 结构体代码转MASM32代码的功能。
二、判断是否为c++结构体定义代码
这个跟判断是c++类定义代码是相似的。判断c++类定义代码我们是检测class关键字,那么判断c++结构体定义代码我们是检测struct关键字,再检测是否存在{和}这两个字符:
function isCppStruct(c) { //taMASM32.value += 'isCppStruct : c.search(/\bstruct\b/i =' + c.search(/\bstruct\b/i) + '\n'; if (c.search(/\bstruct\b/i)) { if ( -1 != c.indexOf('{') ) { if ( -1 != c.lastIndexOf('}')) { return true; }//if }//if }//if return false; }//isCppStruct(c)
三、获取结构体名称
在微软Windows 里中,C++类的类名一般位于定义代码的开头,class关键字的后面,如:
[Dynamic, Provider("CIMWin32"), UUID("{8502C4CC-5FBB-11D2-AAC1-006008C78BC7}"), AMENDMENT] class Win32_UserAccount : Win32_Account { uint32 AccountType; string Caption; string Description; boolean Disabled; string Domain; string FullName; datetime InstallDate; boolean LocalAccount; boolean Lockout; string Name; boolean PasswordChangeable; boolean PasswordExpires; boolean PasswordRequired; string SID; uint8 SIDType; string Status; };
类名就是 Win32_UserAccount。
与C++类定义不同的是,C++结构体定义中,结构体名称既可能位于定义体首部的struct关键字后面,也可能位于结体体的末尾,如:
typedef struct _MIB_TCP6TABLE_OWNER_MODULE { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_MODULE table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_MODULE, *PMIB_TCP6TABLE_OWNER_MODULE;
结构体名称是位于}符号的MIB_TCP6TABLE_OWNER_MODULE。
所以要获取C++结构体定义中的结构体名称,我们要分清主次,优先检查结构体定义末尾}后是否有结构体名称,有则从此获取结构体名称,没有的话,再从结构体定义首部struct关键字后获取结构体名称。
//功能:获取为c++ struct的名称 //输入:c=code //输出:struct的名称(可能为'') //记录:20230822创建 // 20230824增加变量t,避免}后无结构名时获取struct关键字后面的结构名不对的问题 function getStructName(c) { //var r = c.substring(/\bstruct\b/i + 6).ltrim(); //return r.substring(0, r.indexOf(' ')); var r = c.search(/\bstruct\b/i); if (-1==r) { return ''; } //获取}后的结构体名称 var t = c.lastIndexOf('}'); if ( (-1!=t) && (t<c.length) ) { t = c.substring(t+1).trim(); //alert(t); var i = t.indexOf(','); if (-1==i) { i = t.indexOf(';'); } if (i > 0 && (i+1) < c.length ) { return t.substring(0,i); } } //获取struct关键字后面的结构名 r = c.substring(r + 6).ltrim(); return r.substring(0, r.indexOf(' ')); }//getStructName(c)
四、获取c++结构体成员信息
获取c++结构体定义代码中的结构体成员信息与之前获取c++类定义代码中的类成员信息的思路是一样的,这里我们要考虑到成员可能是数组的情况,比如:
typedef struct _MIB_TCP6TABLE_OWNER_MODULE { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_MODULE table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_MODULE, *PMIB_TCP6TABLE_OWNER_MODULE;
中的table成员就是一个数组,因此我们对原先的代码进行改进,检查成员名称中是否包含'['字符,如果包含,那么就要把'['及其后面的字符串去掉:
//功能:抽取c++ class中的成员名称和类型到数组 //输入:c=code //输出:二维数组,每行第1个元素为C++类的成员类型,第2个元素为C++类的成员名称 //记录:20230812创建 // 20230825增加对数组类成员的检测 function extractMember(c) { var r = c.substring(c.search(/\bclass\b/i) + 5); r = r.substring(r.indexOf('{')+1, r.lastIndexOf('}')); r = r.replace(/;/g,''); var a = r.split('\n'); a.shift();//删除首个空行 r = []; //i < a.length-1,跳过末个空行 for (var i = 0; i < a.length-1; i++) { r[i] =[]; r[i] = a[i].trim().split(' '); //是数组?20230825增加 var j = r[i][1].indexOf('['); if (-1 != j) { r[i][1] = r[i][1].substring(0,j); } } return r; }//extractMember(c)
五、转换效果