之前美化Windows系统,在更改屏幕锁定图片的时候,发现每次手动更改比较麻烦,并且发现其中原理也非常简单,所用到的技术也清晰明了:对注册表的操作,突破权限复制文件,调用系统函数锁屏和简单的MFC界面操作,于是索性写个小软件,以后再用的时候方便,我的系统是win7系统,在其上可以使用。原理浅析我们从网上可以看到一些方法介绍,首先我们要修改注册表,注册表是MicrosoftWindows用于存储系统和应用程序的设置信息的一个重要的数据库。进入注册表:
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Authentication/LogonUI/Background
看是否有OEMBackground这个键,没有就新建,数据类型为REG_DWORD,将其值设置为1,然后选择图片,命名为backgroundDefault.jpg放置在C:\Windows\System32\oobe\info\backgrounds目录下。如果没有这个目录就新建,然后把图片复制过去。
最后检查一下计算机配置-管理模块-系统-登录模块是否始终选择自定义登录背景,没有的话就勾选上,然后就可以了。原理就是这样了,我们可以猜到在代码中我们要对注册表进行操作,对文件目录操作,由于是系统目录,还需要突破系统权限。还需要调用系统函数,来进行锁屏测试,下面是代码的详细说明。代码解析我们先说说选择图像目录的功能,选择图像目录我们可以调用CFileDialog类,在这个类中我们可以使用GetPathName()等函数来获取所选图片的路径,继而自己写个函数来获取它的文件名,路径等信息。
核心代码如下:
CFileDialogccFileDlg(TRUE,NULL,NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT, _T("Imagefiles(*.png;*.jpg)|*.png;*.jpg|Allfiles(*.*)|*.*||"),NULL); if(ccFileDlg.DoModal()==IDOK) { CStringstrPathName=ccFileDlg.GetPathName(); CStringstrDir=strPathName.Left(strPathName.ReverseFind('\\')); strPathName.Replace("\\","\\\\"); CStrings=GetFileName(strPathName); CopyFile(strPathName,"C:\\backgroundDefault.jpg",false); SHFILEOPSTRUCTfileop; fileop.hwnd=this->m_hWnd; fileop.wFunc=FO_COPY;//拷贝 fileop.pFrom="C:\\backgroundDefault.jpg";//从哪里拷贝 fileop.pTo= "C:\\Windows\\System32\\oobe\\info\\backgrounds\\backgroundDefault.jpg";//拷贝到哪里 fileop.fFlags=FOF_NOCONFIRMMKDIR;//FOF_SILENT; SHFileOperation(&fileop);//执行 AfxMessageBox("图片选择成功!"); }
经过测试,如果用copyfile函数来直接将文件复制到windows目录下,虽然不会有错误信息,但是文件不能被复制过去,这与系统目录的权限保护有关,那么我们如何突破呢?经过测试,在Windows的shellapi文件中定义了一个名为SHFileOperation()的外壳函数,用它可以实现各种文件操作,并且不会因为权限限制而复制不过去。
而这里我是先把任何名字的图片复制到C盘目录下,自动重命名为backgroundDefault,而如果先重命名的话,若再次选通目录下的图片重命名会有冲突问题,所有copyfile第三个参数设为false,这样自动覆盖就没有了这个冲突,然后再把C盘目录下的文件复制到指定目录下。接下来是对注册表的操作,对注册表的打开、删除、查询、新建、设置等都有对应的windowsAPI,下面是核心代码,看看函数名也知道是对应干什么的了:
LONGRegOpenKeyEx( HKEYhKey,//需要打开的主键的名称 LPCTSTRlpSubKey,//需要打开的子键的名称 DWORDulOptions,//保留,设为0 REGSAMsamDesired,//安全访问标记,也就是权限 PHKEYphkResult//得到的将要打开键的句柄 ); LONGRegSetValueEx( HKEYhKey, LPCTSTRlpValueName, DWORDReserved, DWORDdwType, CONSTBYTE*lpData, DWORDcbData ); 核心代码如下: LONG HKEY lRetCode,mRetCode,nRetCode; hKey1,hKey; DWORD dwDisposition; char*b=(LPSTR)(LPCTSTR)"OEMBackground"; LONG lRetCode1; lRetCode1=RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\Backgr ound", 0, KEY_SET_VALUE|KEY_WOW64_64KEY,&hKey1); if(lRetCode1!=ERROR_SUCCESS){ AfxMessageBox(_T("子键不存在,正在创建!")); mRetCode=RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\Background",0, b,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL,&hKey1,&dwDisposition); if(mRetCode!=ERROR_SUCCESS) { AfxMessageBox(_T("创建失败!"));return;} } DWORDdwData; dwData=1; DWORDdwSize=sizeof(DWORD); nRetCode=RegSetValueEx(hKey1,"OEMBackground",0,REG_DWORD,(LPBYTE) &dwData,dwSize); if(nRetCode!=ERROR_SUCCESS) { AfxMessageBox(_T("修改失败!")); return; }
else{MessageBox("操作完成!注意图像大小必须大于等于屏幕大小,程序不提供图像扩放功能!");}GetDlgItem(IDC_BUTTON3)->EnableWindow(true);这里注意RegOpenKeyEx里要加入KEY_WOW64_64KEY来指出是32位操作系统还是64位操作系统,这样写入注册表不会出错,否则会因为重定向问题而不能向注册表内写入值,即使最后RegSetValueEx()函数返回的值为0。接着执行锁屏测试的代码只需要一行,非常好懂:system("rundll32.exeuser32.dll,LockWorkStation");而MFC界面设计与美化之类的没什么技术含量,就不多讲了,所有的核心代码就是这些了。测试截图打开软件界面
点击选择目录按钮,选择要更换的图片,,因为已经存在,所以会有如图提示,接着会出现所示的提示。接着我们打开注册表可以看到一开始所指定键值为0,我们要将其修改为1,点击修改按钮
接着点击锁屏测试,会调用系统函数,来执行锁屏功能,我们就可以看到自己所更改的锁屏图片的效果了。
经过测试,本程序可以实现Win7系统的锁屏图片更改,通过这次MFC编程写了一个小的软件,其意义不仅是方便了操作,更重要的是在于温习了一些编程技术,温故而知新。