S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

将EXE程序的设置保存在EXE文件本身

Posted on 2009-10-25 16:54 S.l.e!ep.¢% 阅读(569) 评论(0)  编辑 收藏 引用 所属分类: VC
 

 因为是随便一想就想出的方法,没来得及用搜索引擎了解相关的情况,老神仙们见笑了。

    通常,程序把一些设置,配置保存在一个专门的文件中或者注册表中,但在一些情况下,这样非常不方便。比如偷OICQ号的那种程序(没用过,也叫不上名来),提前设置好邮箱,然后放在别人机子上运行,通过某种方法取得OICQ密码,最后把密码发往指定信箱。把设置的邮箱保存在一个配置文件中一起放到别人机子上,就不如保存在执行文件本身中用起来方便。这只是举个例子,在一些情况下,把配置,或者一些信息保存在可执行文件本身中是很有用处的。
    下面我通过一个例子,来讲一种实现的方法,这种方法简单易用。
    两个程序,一个叫 SettingInMe ,一个叫 SetYou 。SettingInMe 读取程序中的一个字符串,并把这个字符串的内容,用一个 MessageBox 显示出来,SettingInMe 相当于读取设置的程序,那个字符串就相当于我们的设置。SetYou 设置那个SettingInMe 中的字符串,相当于设置另一个程序中的设置或者参数。运行 SettingInMe 可以看到程序中原来的设置。退出 SettingInMe ,运行放在同一文件夹下的 SetYou 随便输入一些字符,然后退出 SetYou ,再运行 SettingInMe 看看,就会发现里面的设置被改了。
    大家可以先下载这两个可执行文件试一下。SettingInMe.exeSetYou.exe
    首先看一下 SettingInMe 的源程序。

SettingInMe
___________________________________________________________________
#include <windows.h>
#include <stdio.h>
#define cbMatchStr 55 //strlen("I'm JIURL,My HomePage is http://jiurl.yeah.net. Salute!")

char MagicStr[cbMatchStr+256]="I'm JIURL,My HomePage is http://jiurl.yeah.net. Salute!http://jiurl.yeah.net\n\nhttp://jiurl.nease.net\n\njiurl@mail.china.com";
//256用来存放参数的空间长度,不要超过。

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char* lpText = MagicStr+cbMatchStr;
MessageBox(NULL,lpText,"Yes!",NULL);
return 0;
}

    申请了一个全局变量 MagicStr ,我们要把设置放在它的里面,SettingInMe 会使用这个全局变量中的内容做为设置。程序编译之后,这个全局变量会在 EXE 文件中占相同的空间,只要设置程序 SetYou 能找到这个全局变量的在文件中的位置,然后写入相应的内容,就可以达到我们的目的。由于全局变量在编译好的 EXE 文件中也要占相同的空间,覆盖其中的内容,只是改变了全局变量的值,并不会破坏可执行程序。在这里我们用这个全局变量的前55个字节的内容,做为搜索串,来标明这个全局变量在文件中的位置,这个搜索串之后的256个字节,用来存放设置。关于这个,后面将有更多的讨论。
    下面看一下 SetYou 如何找到这个全局变量和设置它的内容,SetYou 的源程序。

SetYou
___________________________________________________________________
#include <windows.h>
#include <stdio.h>
#include "resource.h"

INT_PTR CALLBACK DialogProc(HWND,UINT,WPARAM,LPARAM);
char SetStr[256];

#define cbMatchStr 55//strlen("I'm JIURL,My HomePage is http://jiurl.yeah.net. Salute!")

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HANDLE hFile;
char Err[256];
char MatchStr[cbMatchStr+1]="I'm JIURL,My HomePage is http://jiurl.yeah.net. Salute!";
//字符串长度55,字符串的结束符1,共56字节

hFile = CreateFile("SettingInMe.exe",GENERIC_WRITE|GENERIC_READ,0,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
//SettingInMe.exe 和 本程序要在同一目录下
if(hFile==INVALID_HANDLE_VALUE)
{
sprintf(Err,"CreatFile Error: 0x%08x !",GetLastError());
MessageBox(NULL,Err,"CoNgRaTuLaTiOn!",NULL);
return 0;
}

char Data;
DWORD nRead;
int retval;
int i=0;

//这种效率不好,不过比较直观,
//如果一次读入1024字节,然后在内存中进行比较...
while(1)
{
retval = ReadFile(hFile,&Data,1,&nRead,NULL);
if(retval==0||nRead==0)
{
MessageBox(NULL,"Not Found Place to Set","CoNgRaTuLaTiOn!",NULL);
break;
}

if(Data==MatchStr[i])i++;
else i=0;

if(i==cbMatchStr)
{
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)DialogProc);

retval = WriteFile(hFile,SetStr,strlen(SetStr),
&nRead,NULL);
if(retval!=0)
MessageBox(NULL,"Set OK!","Yes!",NULL);
else
{
sprintf(Err,"WriteFile Error: 0x%08x !",GetLastError());
MessageBox(NULL,Err,"CoNgRaTuLaTiOn!",NULL);
}
break;
}
}

MessageBox(NULL,"OVER","OVER",NULL);

CloseHandle(hFile);
return 0;
}

INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg,
WPARAM wParam,LPARAM lParam)

switch(uMsg)
{
case WM_COMMAND:
switch(wParam)
{
case IDOK:
GetDlgItemText(hwndDlg,IDC_IN,SetStr,sizeof(SetStr));
//SetStr[]的长度不要超过256。
//在对话框中输入的串要是超过256,
//GetDlgItemText() 会截取范围内部分。
EndDialog(hwndDlg,TRUE);
break;
case IDCANCEL:
PostQuitMessage(0);
break;
}
break;
}
return 0;
}

    SetYou 首先用 CreateFile 打开相同文件夹下的 SettingInMe.exe 然后开始一个字节一个字节的读文件中的内容,每读一个字节,就把这个字节和用来标明全局变量位置的那个全局变量开始处的字符串进行比较,如此一直读到文件结束。读到一个字节,比较是否和标志串中第i个(最开始是0)相同,相同的话,就把i++;接着读和比较(再比较就是标志串中的第二个字节了),又相同,又i++,又...直到一部分相同之后,有一个不同,把i重新设为0,然后接着读文件,向后寻找。或者所读内容和整个标志串都相同,我们找到了要找的那个全局变量。找到全局变量之后,我们可以用 WriteFile 来改变这个全局变量中的内容。在 SetYou 这个程序中,会弹出一个对话框,来取得输入串。在 SetYou 中 WriteFile(hFile,SetStr,strlen(SetStr)),最后那个参数是个strlen,也就是说只会覆盖设置串中前面的部分。如果这里的参数是256(也就是sizeof(SetStr))的话,就会覆盖整个设置。

    这样,我们在一个程序中静态申请一个全局变量,来在EXE文件中保留一定的空间,来作为保存设置,配置,参数,信息的空间。并在这个空间的开始处放一个标志串,用来查找。另一个程序,查找那个标志串,找到这个全局变量的空间,对其相应位置进行设置,就实现了将EXE程序的设置保存在EXE文件本身。
    需要说明的是,程序一旦编译之后,EXE文件中的内容就固定了,所以文件中要不然有其他地方和标志串一样,要不然没有其他地方和标志串一样。如果有地方和标志串内容一样的话,只要换个标志串就可以了。只要标志串有一定长度,要和其他内容不一样是很容易的。更进一步说,编译之后,EXE文件内容固定,全局变量在EXE文件中的位置也是固定的,只要能找到这个位置,是没有必要有一个标志串的,本文例子用标志串,只是为了便于说明和理解。
    最后总结一下,程序中静态申请一块全局空间,使用这个空间中的内容作为参数,设置,配置或者某些信息。在编译生成的EXE文件中就相应的也存在相同大小的一个空间。在另一个程序中打开这个程序的EXE文件,用某种方法找到这块空间在EXE文件中的位置,就可以进行设置。
    唉,这篇文章写的真烂啊,大家凑合看吧。本来还说拿它得个诺贝尔文学奖玩玩,看来也没戏了。

下载SettingInMe和SetYou的源程序 
下载SettingInMe的可执行文件
下载SetYou的可执行文件



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=1044749


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理