功能说明
在windows下做一些小工具的时候,希望做到根据配置文件来对pc做一些配置下发的操作(例如改主机名改网络等),这就需要做到每个一段时间检测配置文件,并执行相应配置,但是当我们配置文件没有修改时,就不需要做配置了,因此需要对配置文件进行md5检测判断文件是否有改变
获取md5值
此处是获取文件的md5值,文件名在new类的时候传入
BYTE* VeryAgent::getMd5()
{HANDLE hFile = CreateFile(mIniConfigPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);if (hFile == INVALID_HANDLE_VALUE)//如果CreateFile调用失败{LOGD("CreateFile go wrong: %s", GetLastError());//提示CreateFile调用失败,并输出错误号。visual studio中可在“工具”>“错误查找”中利用错误号得到错误信息CloseHandle(hFile);return NULL;}HCRYPTPROV hProv = NULL;if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE)//获得CSP中一个密钥容器的句柄{LOGD("CryptAcquireContext go wrong: %s", GetLastError());return NULL;}HCRYPTPROV hHash = NULL;if (CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash) == FALSE)//初始化对数据流的hash,创建并返回一个与CSP的hash对象相关的句柄。这个句柄接下来将被CryptHashData调用。{LOGD("CryptCreateHash go wrong: %s", GetLastError());return NULL;}DWORD dwFileSize = GetFileSize(hFile, 0); //获取文件的大小if (dwFileSize == 0xFFFFFFFF) //如果获取文件大小失败{LOGD("GetFileSize go wrong: %s", GetLastError());return NULL;}byte* lpReadFileBuffer = new byte[dwFileSize];DWORD lpReadNumberOfBytes;if (ReadFile(hFile, lpReadFileBuffer, dwFileSize, &lpReadNumberOfBytes, NULL) == 0)//读取文件{LOGD("ReadFile go wrong: %s", GetLastError());return NULL;}if (CryptHashData(hHash, lpReadFileBuffer, lpReadNumberOfBytes, 0) == FALSE)//hash文件{LOGD("CryptHashData go wrong: %s", GetLastError());return NULL;}delete[] lpReadFileBuffer;CloseHandle(hFile);//关闭文件句柄BYTE *pbHash;DWORD dwHashLen = sizeof(DWORD);if (CryptGetHashParam(hHash, HP_HASHVAL, NULL, &dwHashLen, 0))//我也不知道为什么要先这样调用CryptGetHashParam,这块是参照的msdn {}else{LOGD("get length wrong");return NULL;}if (pbHash = (byte*)malloc(dwHashLen)){}else{LOGD("allocation failed");return NULL;}if (CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0))//获得md5值{//for (DWORD i = 0; i<dwHashLen; i++)//输出md5值//{// printf("%02x", pbHash[i]);//}//LOGD("md5sum:%s", pbHash);//是乱码只有16进制打印才不是乱码}//善后工作if (CryptDestroyHash(hHash) == FALSE)//销毁hash对象{LOGD("CryptDestroyHash go wrong: %s", GetLastError());}if (CryptReleaseContext(hProv, 0) == FALSE){LOGD("CryptReleaseContext go wrong: %s", GetLastError());}//printMd5sum(pbHash);return pbHash;
}
判断文件是否改变逻辑
1、若未检测到md5值说明文件有问题
2、检测到文件md5值后
1、若保存的md5值为空,则说明是第一次检测,保存好md5值供下次对比,之后进行配置下发
2、原来就有md5值,则将现有md5与之前的做对比,相同则不做配置下发,不同则做配置下发,并且更新保存的md5值
bool VeryAgent::checkMd5() {//printMd5sum(mMd5sum);//类名为VeryAgent,记录一个成员变量为mMd5sumunsigned char *tmpMd5sum = getMd5();if (tmpMd5sum) {if (!mMd5sum) {LOGD("mMd5sum = null do agent config");mMd5sum = tmpMd5sum;return true;}if (memcmp(mMd5sum, tmpMd5sum, 16) == 0) {free(tmpMd5sum);tmpMd5sum = NULL;//LOGD("config not changed");return false;}else {free(mMd5sum);mMd5sum = tmpMd5sum;LOGD("config changed, do agent config");return true;}}else {LOGD("get new md5sum failed");return false;}return true;
}
最后是主函数循环
new的时候将文件名传入类成员变量mIniConfigPath以供使用
int main()
{const char* filename = "C:\\config.ini";VeryAgent *agent = new VeryAgent(filename);while (1){if (agent->checkMd5()) {agent->doAgentConfig();}Sleep(1000 * 1);}
}