使用VC内嵌Python实现的一个代码检测工具
最近组内准备整顿代码,领导让我写个简单的python脚本分析代码中注释的行数和无效注释。因为这个需求不是很急,所以我想把简单的事情做复杂点。于是就写了一个用VC内嵌Python,并通过模拟按键和发消息去控制其他软件的工具。(转载请指明出处)
作为一个程序员,总是希望自己写的东西别人能用上且喜欢去用。因为python更新很快,往往两个版本中存在一些语法或者实现的改动。其实最讨厌的就是语法变动了,像2.X的print到3.X时就是print()了。我本意是希望做个大家都能用上的,于是我决定用VC内嵌一个python引擎去完成相关工作。
首先说一下环境准备,这个网上一大堆,主要是下载并配置好pythonXX_d.lib、pythonXX.lib、python.dll等几个文件。然后一切就可以开始了。
python分析的过程也很简单, AnalyzeFloder.py是对一个文件夹进行遍历,并做相关统计;AnalyzeFileComment.py是分析每个文件并且筛选出注释;CommentUseOrNo.py是分析每个注释,看看是否是无用注释;AnalyzeReport.py做相关统计和序列化、反序列化工作。 AFCUI.py 是对上述功能的封装。这里说一下对无用注释的定义,我们定义如果注释内容为符合VC编码风格的代码即认为是无效代码。在现实开发中,特别是人员流动性特别大的公司,新人做需求时往往不敢去碰那些没有任何注释的代码,于是他们就直接把这些似乎不用了的代码注释掉。这样长久下来,“无用注释”的量就会很大了。
# a(x)# a (x)# a (x)# x = x# x x# x x,y yself.InitNoUseRe(r'[a-zA-Z](\w)*([ \t])*\([\w\s]*|([\w\s]*(,[\w\s]*))\)')# }# }a;self.InitNoUseRe(r'\}[ \t\r\n]*([a-zA-z]+;)?[ \t\r\n]*)self.InitNoUseRe(r'^([ \r\t\n]*)({[ \r\t\n]*))self.InitNoUseRe(r'[a-zA-Z]+[ \t]*[=><]{1,2}([ \t]*[a-z0-9A-Z]+[ \t]*))self.InitNoUseRe(r'#define[ \t][a-zA-Z]*([ \r\t\n]*))self.InitNoUseRe(r'return[ \t][a-zA-Z]*(;[ \r\t\n]*))self.InitNoUseRe(r'[a-zA-Z](\w)*\+\+(;[ \r\t\n]*))self.InitNoUseRe(r'[a-zA-Z](\w)*--(;[ \r\t\n]*))self.InitNoUseRe(r'^([ \r\t\n]*continue)(;[ \r\t\n]*))self.InitNoUseRe(r'^([ \r\t\n]*break)(;[ \r\t\n]*))self.InitNoUseRe(r'case (\w)+(:[ \r\t\n]*))self.InitNoUseRe(r'^([ \r\t\n]*[a-zA-Z](\w)*[ \r\t\n]+[_a-zA-Z](\w)*)((;|\{|(\[\w*\]);)[ \r\t\n]*))self.InitNoUseRe(r'^([ \r\t\n]*))self.InitNoUseRe(r'^([ \r\t\n]*(struct|class))([ \r\t\n]* [a-zA-Z](\w)*)((\{|;)?[ \r\t\n]*))
以上是我定义的无效代码的正则表达式,因为正则也是拿来用用,没有好好研究过,所以写的不好,凑合着用了,从目前的效果看,还是可以的。
其次,对于分析出来的数据,我将其序列化到一个文件中,这样以后要是加载之前分析过的工程,就可以直接反序列化那个文件就行了,不用重复分析。
def GetFileInfoMapFromDump(self,filepath):with open(filepath, 'rb') as f:data = pickle.load(f)return datadef DumpFileInfoMap(self,filemap,filepath):with open(filepath, 'wb') as f:pickle.dump(filemap, f, pickle.HIGHEST_PROTOCOL)
再次,说下python和VC的通信。python可以直接和VC通信,但是我返回的数据是一个复杂的结构,我一直也没想到一个简便的办法去解决,于是,我就自定义一种格式,让python在处理完数据后,将数据保存为我定义的格式,然后把文件名返回给VC,VC去读并分析这个文件,从而得到数据。
def GenerateVcDataFile(self,fileinfomap,vcdatefilepath):vcdatafileobj = open( vcdatefilepath, 'w+') for key in fileinfomap:strvcdata = Nonestrvcdata = keyindex = 0for value in fileinfomap[key]:if index == 3:for linenum in value:strvcdata = strvcdata + '|' + str(linenum)else:strvcdata = strvcdata + '|' + str(value) index = index + 1strvcdata = strvcdata + '|\n'vcdatafileobj.write(strvcdata) if None != vcdatafileobj:vcdatafileobj.close()return vcdatefilepath
对应的VC解析代码我放在CAnalyzeVcData中,代码就不贴的(没严格省代码)。
python的大致流程就是如此,VC要是想执行Python的脚本,就如下了
CString CManageTask::AnanlyzeCodeFloder( const CString& cstrCodeFloderPath,const CString& cstrProjectFloderPath )
{CString cstrVcDataPath = L"";Py_Initialize(); // 进行初始化pythonPyObject* pModule = NULL;// 函数对象PyObject* pFunc = NULL; do {// 找到模块对象指针pModule = PyImport_ImportModule("AFCUI"); if ( NULL == pModule ){ASSERT(pModule);break;}// 从模块对象中获取指定函数对象指针pFunc = PyObject_GetAttrString( pModule, "AFloderFunc" ); if ( NULL == pFunc ){ASSERT(pFunc);break;}std::string strProjectPath = ConvertCstrint2String(cstrProjectFloderPath);std::string strCodeFloderPath = ConvertCstrint2String(cstrCodeFloderPath);// 构造参数PyObject* pargslist = Py_BuildValue("(s,s)", strCodeFloderPath.c_str(), strProjectPath.c_str());char* pchvcdatapath = NULL;// 调用函数 PyObject* pstr = PyEval_CallObject(pFunc, pargslist); if ( NULL == pstr ){ASSERT(pstr);break;}PyArg_Parse(pstr, "s", &pchvcdatapath);if ( NULL != pchvcdatapath ){cstrVcDataPath = CA2W(pchvcdatapath);}} while (0);Py_Finalize(); return cstrVcDataPath;
}
如果对于分析出的数据,为了方便用户查看,我得打开源代码并定位到那个位置。我想过很多方法,想过自己做RichEdit,但是我对界面实在不感冒,于是懒的情绪就上来了。但是我对“玩”还是很有感觉的,我决定盗用微软的Notepad.exe,还修改了Notepad.exe的资源,成为我定制版的东东。然后通过模拟按键和发消息等方法去让它去打开源代码并定位位置。
但是使用中,我发现有点不爽。因为我发现,notepad.exe不可以显示行。UE呢还要注册,于是选用Notepadplusplus了。Notepadplusplus还支持多标签页,让我感觉很兴奋,超出我的预期。
贴一段控制notepadplusplus的代码。
DWORD CManageTask::CreateNotePad()
{STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory( &pi, sizeof(pi) );ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);CString cstrNNotepadPath = m_strFloder + L"\\Notepadplusplus\\notepad++.exe";CreateProcess( cstrNNotepadPath,L"", NULL, NULL, FALSE, NULL, NULL,NULL , &si, &pi);return pi.dwProcessId;
}RECT CManageTask::GetNotePadRect()
{RECT rc;m_pAnalyzeCodeDlg->GetWindowRect(&rc);m_pAnalyzeCodeDlg->ClientToScreen(&rc);RECT nrc;nrc.left = rc.left;nrc.right = nrc.left + rc.right - rc.left;nrc.top = rc.top + rc.bottom - rc.top;nrc.bottom = nrc.top + rc.bottom - rc.top;m_pAnalyzeCodeDlg->ScreenToClient( &nrc );return nrc;
}HWND CManageTask::GetNotePadFilePathEdit( HWND hwndP )
{if ( NULL == hwndP ){return NULL;}HWND hComboBoxEx32 = ::FindWindowEx( hwndP, NULL, L"ComboBoxEx32", NULL );HWND hComboBox = ::FindWindowEx( hComboBoxEx32 , NULL, L"ComboBox", NULL );HWND hEdit = ::FindWindowEx( hComboBox , NULL, L"Edit", NULL );return hEdit;
}HWND CManageTask::GetNotePadOkButton( HWND hwndP )
{if ( NULL == hwndP ){return NULL;}HWND hOKButton = ::FindWindowEx( hwndP, NULL, L"Button", NOTEPADOPENFILENAME2 );return hOKButton;
}HWND CManageTask::GetNotePadOpenFileDialog()
{HWND hAfter = NULL;HWND h = ::FindWindowEx( NULL, hAfter, NULL, NOTEPADOPENFILENAME );DWORD dwPID = 0;while ( NULL != h ){h = ::FindWindowEx( NULL, hAfter, NULL, NOTEPADOPENFILENAME );GetWindowThreadProcessId( h, &dwPID );if ( dwPID == m_dwThreadNotePadID ){return h;}else{hAfter = h;}}return NULL;
}HWND CManageTask::GetNotePadEdit( HWND hwndP )
{if ( NULL == hwndP ){return NULL;}HWND hEidt = ::FindWindowEx( hwndP, NULL, L"Scintilla", NULL);return hEidt;
}VOID CManageTask::OpenNewFile( const CString& cstrFilePath )
{HWND hwndP = NULL;while ( NULL == hwndP ){::SetForegroundWindow( m_hwndNotePad );::SetActiveWindow( m_hwndNotePad );::SetFocus( m_hwndNotePad );{keybd_event( VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0 );keybd_event( 0x4F, 0, 0, 0 );keybd_event( 0x4F, 0, KEYEVENTF_KEYUP, 0 );keybd_event( VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0 );}Sleep(500);hwndP = GetNotePadOpenFileDialog();}HWND hEdit = GetNotePadFilePathEdit(hwndP);HWND hOKButton = GetNotePadOkButton(hwndP);CString strTmp = cstrFilePath;if ( NULL != hEdit ){::SendMessage( hEdit, WM_SETTEXT, 0, (LPARAM)strTmp.GetBuffer() );strTmp.ReleaseBuffer();if ( NULL != hOKButton ){::SendMessage( hOKButton, WM_LBUTTONDOWN, 0, 0);::SendMessage( hOKButton, WM_LBUTTONUP, 0, 0);}}
}
于是大功告成了。
目前还有很多没有完善的地方,比如字符串的转码(程序放在中文目录下有转码问题,出在python回传结果的时候)和规则(规则不全面)。还有很多可以“玩”的功能,比如对单个文件的重新分析。目前我思路都想好了,也预留了接口。我想通过FindFirstChangeNotification监控指定目录文件,如果有改动,就调用AFCUI.py中
def AnalyzeCodeFilePathFunc(self,codefilepath):analyzefile = CAnalyzeFloder()analyzefile.AnalyzeFile(codefilepath)fileinfomap = analyzefile.GetCodeFloderInfo()AnalyzeReport(fileinfomap)
(需要封装)。然后VC得到当个文件的可以解析的数据,并更新内存和界面。因为之前玩过FindFirstChangeNotification(我毕设就是玩它的),所以我就没多大兴趣去做这个功能了。
还有这次MFC代码,我尝试了下界面和逻辑分离的原则,很好玩,代码也清晰很多,所有的逻辑都在CManageTask类中。
代码链接:AnalyzeCode(onedriver)
链接:https://pan.baidu.com/s/1SVRDXIi6lB3mrUscQREqIQ
提取码:be0p
(转载请指明出处)
相关文章:
Python如何实现24个微信大群万人同步转发直播?
作者 | 猪哥66来源 | CSDN博客今天我们来学习微信机器人多群转发做同步图文直播!一、背景介绍猪哥一年前在建Python学习群的时候就说过,要邀请企业大佬来学习群做直播。其实文章早就写好了,但是一直没有找到好的转发软件,所以耽搁…

ITSM实施三招[案例]
当前国外成熟的ITSM解决方案的实施成本相对比较高,使一些对成本较敏感的的IT部门,成为ITSM实施的一个真空区。对于国内起步阶段的ITSM(IT服务管理)实施来说,南航的ITSM实施之路是一个借鉴。 南航it环境 在各大航空公司…
lr手工添加关联函数的步骤:
点击“确定”后: 如何修改已经创建好的关联规则:

新闻内容实现分页
/**//// <summary> /// 新闻内容分页 /// </summary> /// <param name"content">新闻内容</param> /// <param name"extension">扩展名(aspx,html..)</param> /// <returns></returns>pub…
使用自己的数据集训练MobileNet、ResNet实现图像分类(TensorFlow)| CSDN博文精选
作者 | pan_jinquan来源 | CSDN博文精选之前写了一篇博客《使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)》https://panjinquan.blog.csdn.net/article/details/81560537,本博客就是此博客的框架基础上,完…

VC下提前注入进程的一些方法1——远线程不带参数
前些天一直在研究Ring3层的提前注入问题。所谓提前注入,就是在程序代码逻辑还没执行前就注入,这样做一般用于Hook API。(转载请指明出处)自己写了个demo,在此记下。 我的demo使用了两种注入方式:1 远线程&a…

【转】用示例说明索引数据块中出现热块的场景,并给出解决方案
文章转自:http://www.luocs.com/archives/582.html

VC下提前注入进程的一些方法2——远线程带参数
在前一节中介绍了通过远线程不带参数的方式提前注入进程,现在介绍种远线程携带参数的方法。(转载请指明出处) 1.2 执行注入的进程需要传信息给被注入进程 因为同样采用的是远线程注入,所以大致的思路是一样的,只是在细…
芬兰开放“线上AI速成班”课程,全球网民均可免费观看
出品 | AI科技大本营(ID:rgznai100)去年,芬兰推出了一个免费的“人工智能线上速成班”项目,目的是向该国民众教授与新技术有关的知识。现在,作为送给全世界的圣诞节礼物,这个项目已面向全球网民开放访问&am…

deepin开通ssh
1、在终端打入下面命令进行安装sudo apt-get install openssh-server2、启用sshservice ssh start 反馈:start: Rejected send message, 1 matched rules; type"method_call", sender":1.56" (uid1000 pid2272 comm"start ssh ") int…

实现等待窗体的几种方式
实现等待窗体的几种方式:下面说明了五种可以实现等待窗体的方式,其中三种给出了代码。准备资料安全访问控件成员为了保证在创建控件的线程上调用控件成员,用下面的方式封装控件的属性、方法、其他自定义成员的访问。如: winWordControl.LoadD…
GitHub宝藏项目标星1.6w+,编程新手有福了
作者 | Rocky0429来源 | Python空间(ID: Devtogether)特别惭愧的是,虽然我很早就知道 GitHub,但是学会逛 GitHub 的时间特别晚。当时一方面是因为菜,看着这种全是英文的东西难受,不知道该怎么去玩ÿ…

VC下提前注入进程的一些方法3——修改程序入口点
前两节中介绍了通过远线程进行注入的方法。现在换一种方法——修改进程入口点。(转载请指明出处) 在PE文件中,其中有个字段标识程序入口点位置。我们通过这个字段,到达程序入口点。PE文件的结构我这儿不讨论(我会在之后…

如何产生签名applet能让applet能够访问本地资源
2019独角兽企业重金招聘Python工程师标准>>> 如何产生签名applet,以使applet能够访问本地资源? 在jdk1.1中,可以使用javakey命令来产生公钥,私钥,证书和签名的jar文件,详细资料请参考: http://java.sun.com/security/usingJavakey.html而java 2对签名机制做了比较大…

VC提前注入.net软件的方法
在之前几节介绍了各种注入方法,但是这些方法存在一些缺陷——对.net程序注入无效。(转载请指明出处) 这个可以理解,.net程序的代码不是汇编,而是微软自定义的IL中间语言。.net CLR如同虚拟机,解析并执行这些…
活动推荐:语音和语言技术在自然交互中的实践沙龙
智能语音技术已经渗透进家居生活、车载、金融服务等日常生活场景,在很大程度上解放了人们的双手和眼睛,语音交互成为连接人与信息/服务的新入口。根据IDC预测,国内对话式人工智能市场规模将在2022年达到78亿元。如何提供便捷、高效、高可用的…

JS字符串 window.open() window.opener window.name window对象总结
晚上总结了一下,发上来分享:字符串 window.open() window.opener window.name window对象等的一点总结 http://download1.csdn.net/down3/20070614/14012050509.rar

dedecms /member/reg_new.php SQL Injection Vul
catalog 1. 漏洞描述 2. 漏洞触发条件 3. 漏洞影响范围 4. 漏洞代码分析 5. 防御方法 6. 攻防思考 1. 漏洞描述 Dedecms会员中心注入漏洞 2. 漏洞触发条件 http://127.0.0.1/dedecms5.5/member/reg_new.php?dopostregbase&step1&mtype%B8%F6%C8%CB&mt…

VC下通过进程ID获取进程镜像文件路径的方法及其存在的缺陷
工作中经常会遇到通过进程ID获取进程镜像文件或者其他模块的路径的需求。(转载请指明出处)网上关于方案大致存在两种方案: OpenProcess->GetModuleFileNameOpenProcess->EnumProcessModules->GetModuleFileNameEx我试验了下&#x…
腾讯云100亿元目标达成,发阳光普照奖iPhone 11 Pro,你酸了吗?
12 月 19 日,鹅厂腾讯发钱的消息又像往年一样引来了一群柠檬精。除了微信支付团队获得 2 亿元奖金的消息之外,一张腾讯云团队每个员工奖励一部 iPhone 11 Pro 的 H5 页面截图也不断地轰炸着朋友圈。原来这张图说的是腾讯云在 Q3 已完成 2019 年全年 100 …

分享一个python cookbook的在线教程地址
分享一个python cookbook的在线教程地址:http://python3-cookbook.readthedocs.org/zh_CN/latest/翻译者:熊能转载于:https://blog.51cto.com/verdureorange/1653514

优化系统后VS启动不了问题的一种解决方案
本文只讨论使用第三方软件优化系统后,或者您主动禁止服务后导致VS不能启动的问题。(转载请指明出处) 记得大概是08年时,我使用一些软件对电脑启动项做了优化。后来打开VS2005时,发现VS2005会一直保持在“载入界面”,当时十分懊恼&…
懂数学的程序员能有多吃香?这是我听过最好的答案丨颠覆认知
懂数学的程序员能有多吃香?关于这个问题,我想每个程序员心中都有自己的答案。之前在网上看到一个很有意思的答案说:我是在做了2年的开发之后,才真正认识到数学对于程序员的重要性,开始系统的学习数学。理由无它&#x…
基于OpenCasCade的程序发布问题
基于OpenCasCade二次开发了一个程序,想采用简单的copy的发布(部署)方式。 但在发布时遇到了很多问题。总结一下。 首先将所有所需的dll拷贝到了执行目录下,然后将程序copy到一台未安装OpenCasCade的机器上运行出错,信…

Unity3D移植到自己的Android程序
用Unity3D开发需要把动画效果移植到现有的APP上面。Unity for Android 比较特殊,Unity for IOS 打包是将XCODE工程直接交给开发者,开发者可以在工程的基础上继续添加新的视图,最后由开发者自行打包生成IPA包,发布程序。而Unity fo…

一种注册表沙箱的思路、实现
从今年4月份开始,我接触到一个沙箱项目。该项目的需求要求我们的沙箱具有良好的安全性和兼容性。当时我们研究了SandBoxIE和360的沙箱,基本确定通过“重定向”思路来实现这款沙箱。而我主要负责研究注册表这块。(转载请指明出处)在…
PyTorch实现L2和L1正则化的方法 | CSDN博文精选
作者 | pan_jinquan来源 | CSDN博文精选目录1.torch.optim优化器实现L2正则化2.如何判断正则化作用了模型?2.1未加入正则化loss和Accuracy2.1加入正则化loss和Accuracy2.3正则化说明3.自定义正则化的方法3.1自定义正则化Regularization类3.2Regularization使用方法4…

构建插件式的应用程序框架(六)----通讯机制(ZT)
前天发了构建插件式的应用程序框架(五)----管理插件这篇文章,有几个朋友在回复中希望了解插件之间是如何通讯的。这个系列的文章写到这里,也该谈谈这个问题了,毕竟已经有了插件管理。不知道大家…

【翻译】将Ext JS Grid转换为Excel表格
原文:Converting an Ext 5 Grid to Excel Spreadsheet稍微迟来的礼物——Ext JS Grid转为Excel代码,现在支持Ext JS 5!功能包括: - 支持分组 - 数字的处理 VS 字符串数据类型 - 对于不支持客户端下载的浏览器会提交回服务器Enjoy&…