1 | //一、打开CD-ROM |
定制自己的EXE文件
主要是为了实现像木马那样的生成自己需要配置的EXE文件。首先要自己写一个EXE,然后以资源的方式导入到工程中。
下边的例子是一个修改MessageBox标题和文字的程序.
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize, dwWritten;
LPBYTE pBuffer;
HANDLE hFile;
TCHAR szMsgBoxTitle[100],szMsgBoxText[100];
szMsgBoxTitle[0] ='\0';
szMsgBoxText[0] = '\0';
得到新数据,比如新的邮箱地址和密码
GetDlgItemText(IDC_EDIT_TITLE,szMsgBoxTitle,100);
GetDlgItemText(IDC_EDIT_TEXT,szMsgBoxText,100);
// 查找所需的资源
hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_DUMMY_EXE), "Dummy_Exe");
if (hResInfo == NULL)
{
::MessageBox(NULL, "查找资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 获得资源尺寸
dwSize = SizeofResource(NULL, hResInfo);
// 装载资源
hResData = LoadResource(NULL, hResInfo);
if (hResData == NULL)
{
::MessageBox(NULL, "装载资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 为数据分配空间
pBuffer = (LPBYTE)GlobalAlloc(GPTR, dwSize);
if (pBuffer == NULL)
{
::MessageBox(NULL, "分配内存失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 复制资源数据
CopyMemory((LPVOID)pBuffer, (LPCVOID)LockResource(hResData), dwSize);
// 获取标题和文本,并复制数据,具体偏移地址见你的那个EXE资源
CopyMemory((LPVOID)(pBuffer + 0x400), (LPCVOID)szMsgBoxTitle, 100);
CopyMemory((LPVOID)(pBuffer + 0x464), (LPCVOID)szMsgBoxText, 100);
// 创建文件,写数据
hFile = CreateFile("C:\\EnochShen.Exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile != NULL)
{
WriteFile(hFile, (LPCVOID)pBuffer, dwSize, &dwWritten;, NULL);
}
else
{
::MessageBox(NULL, "创建文件失败!", "错误", MB_OK | MB_ICONINFORMATION);
GlobalFree((HGLOBAL)pBuffer);
return;
}
// 收尾工作,释放资源
CloseHandle(hFile);
GlobalFree((HGLOBAL)pBuffer);
::MessageBox(NULL, "创建文件C:\\cooldog.Exe!", "成功" ,MB_OK | MB_ICONINFORMATION);
ShellExecute(m_hWnd, "open", "C:\\", NULL, NULL, SW_SHOWNORMAL);
下面是那个作为资源的EXE的源代码(MASM32写的):
; —————————————————————– ; 生成的exe只有1k,小巧玲珑,^O^ ; —————————————————————–
; #########################################################################
.386
.model flat, stdcall
option casemap :none ; case sensitive
; #########################################################################
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
; #########################################################################
.data
szMsgBoxTitle db 100 dup('E')
szMsgBoxText db 100 dup('S')
.code
start: ; —————————————————————– ; 下面的代码生成的Exe只有1k,但是打包会出错 ; ; szMsgBoxTitle db 100 dup(‘E’) ; szMsgBoxText db 100 dup(‘S’) ; ; —————————————————————–
invoke MessageBox,NULL,ADDR szMsgBoxText,ADDR szMsgBoxTitle,MB_OK or MB_ICONINFORMATION
invoke ExitProcess,NULL
end start
参考自CSDN开发高手第N期(具体哪一期我忘了)
VC下用ADO调用存储过程例程
_ConnectionPtr m_pConnection; _CommandPtr m_pCommand; .cpp中在函数中执行 //建立ado连接 HRESULT hr; hr=m_pConnection.CreateInstance(__uuidof(Connection)); try { if(SUCCEEDED(hr)) { hr=m_pConnection->Open(_bstr_t(L”Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=Viper;Data Source=Viper”),_bstr_t (L”sa”),_bstr_t (L””),adModeUnknown); } } catch(_com_error & err) { AfxMessageBox(err.Description(),MB_OK,0); AfxMessageBox(err.ErrorMessage(),MB_OK,0); AfxMessageBox(“无法连接SQL SERVER 服务器,程序将退出。请检查网络设备”,MB_OK,0); exit(0); }
//执行储存过程 CString cvar1,cvar2; int cvar3; cvar1=”ddd”; cvar2=””; cvar3=0; try { m_pCommand.CreateInstance(__uuidof(Command)); m_pCommand->ActiveConnection=app->m_pConnection; m_pCommand->CommandType=adCmdStoredProc; m_pCommand->CommandText=_bstr_t(“pr_zs_dzdy”);
_variant_t vvar1,vvar2,vvar3; vvar1=_variant_t(_bstr_t(cvar1)); vvar2=_variant_t(_bstr_t(cvar2)); vvar3=_variant_t(cvar3); _ParameterPtr mp_var1,mp_var2,mp_var3; mp_var1.CreateInstance(uuidof(Parameter)); mp_var2.CreateInstance(uuidof(Parameter)); mp_var3.CreateInstance(__uuidof(Parameter));
mp_var1=m_pCommand->CreateParameter ( _bstr_t(“var1”), adVarChar, adParamInput, 3, vvar1 ); m_pCommand->Parameters->Append(mp_var1);
mp_var2=m_pCommand->CreateParameter ( _bstr_t(“var2”), adVarChar, adParamOutput, 3, vvar2 ); m_pCommand->Parameters->Append(mp_var2);
mp_var3=m_pCommand->CreateParameter ( _bstr_t(“var3”), adIntger, adParamOutput, 9, vvar3 ); m_pCommand->Parameters->Append(mp_var3);
_variant_t vNull; vNull.vt=VT_ERROR; vNull.scode=DISP_E_PARAMNOTFOUND; m_pCommand->Execute(&vNull;,&vNull;,adCmdStoredProc); cvar2=mp_var2->Value.bstrVal; cvar3=mp_var3->Value; } catch(_com_error &error;) { MessageBox(error.ErrorMessage(),”ADO错误!”); MessageBox(error.Description(),”ADO错误!”); }
酒店管理系统V1.0
酒店管理系统V1.0 这是我个人完成的一个酒店管理系统模型,拥有客户预订,客户登记,空房查询,服务消费记录和客户结帐,房间管理等多种功能。采用VC++6.0和SQL SERVER开发,大部分业务逻辑采用存储过程实现提高了数据存储的可靠性和速度。 程序界面预览:(点击查看全图) 客户预订界面
客户登记界面
空房查询界面
VC中ADO连接字符串收集
1.ACCESS 2000
_ConnectionPtr m_pConn;
CString m_sConn="Provider=Microsoft.Jet.OLEDB.4.0.1;Data Source=d:\\db1.mdb";
m_pConn.CreateInstance("ADODB.Connection");
try
{
HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,"","",adConnectUnspecified);
if (FAILED(hr))
{
AfxMessageBox("不能连接数据库 source!");
return FALSE;
}
}
catch(_com_error e)
{
AfxMessageBox("不能连接数据库 error!");
return FALSE;
}
2.SQL Server 2000
_ConnectionPtr m_pConn;
CString m_sConn="Provider=SQLOLEDB.1;Data Source=192.168.3.9;Initial
Catalog=sode”; //sode是数据库服务器192.168.3.9上的一个数据库 m_pConn.CreateInstance(“ADODB.Connection”); try { HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,”sa”,”mapper”,adConnectUnspecified); if (FAILED(hr)) { AfxMessageBox(“不能连接数据库 source!”); return FALSE; } } catch(_com_error e) { AfxMessageBox(“不能连接数据库 error!”); return FALSE; }
3.Oracle 9i
_ConnectionPtr m_pConn;
CString m_sConn="Provider=MSDAORA.1;Data Source=sode_192.168.3.9"; //使用
ms连接库,sode为SID,192.168.3.9为机器ip m_pConn.CreateInstance(“ADODB.Connection”); try { HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,”sodeUser”,”sodePw”,adConnectUnspecified); if (FAILED(hr)) { AfxMessageBox(“不能连接数据库 source!”); return FALSE; } } catch(_com_error e) { AfxMessageBox(“不能打开数据库 error!”); return FALSE; }
改变对话框的背景色
方法一:调用CWinApp类的成员函数SetDialogBkColor来实现。 —- 其中函数的第一个参数指定了背景颜色,第二个参数指定了文本颜色。下面的例子是将应用程序对
话框设置为蓝色背景和红色文本,步骤如下: —- ① 新建一个基于Dialog的MFC AppWizard应用程序ExampleDlg。 —- ② 在CExampleDlgApp ::InitInstance()中添加如下代码: BOOL CExampleDlgApp: : InitInstance ( ) { … CExampleDlgDlg dlg; m_pMainWnd = &dlg; //先于DoModal()调用,将对话框设置为蓝色背景、红色文本 SetDialogBkColor(RGB(0,0,255),RGB(255,0,0)); int nResponse = dlg.DoModal(); …} —- 编译并运行,此时对话框的背景色和文本色已发生了改变。值得注意的是:在调用DoModal()之前必
须先调用SetDialogBkColor,且此方法是将改变应用程序中所有的对话框颜色,并不能针对某一个指定的
对话框。 —- 方法二:重载OnPaint(),即WM_PAINT消息。有关代码如下(以上例工程为准): void CExampleDlgDlg::OnPaint() { if (IsIconic()) … else { CRect rect; CPaintDC dc(this); GetClientRect(rect); dc.FillSolidRect(rect,RGB(0,255,0)); //设置为绿色背景 CDialog::OnPaint(); } —- 方法三:重载OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具体
步骤如下(以上例工程为准): —- ①在CExampleDlgDlg的头文件中,添加一CBrush的成员变量: class CExampleDlgDlg : public CDialog {… protected: CBrush m_brush; … }; —- ②在OnInitDialog()函数中添加如下代码: BOOL CExampleDlgDlg::OnInitDialog() { … // TODO: Add extra initialization here m_brush.CreateSolidBrush(RGB(0, 255, 0)); // 生成一绿色刷子 … } —- ③利用ClassWizard重载OnCtlColor(…),即WM_CTLCOLOR消息: HBRUSH CExampleDlgDlg::OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor) { / 这里不必编写任何代码! 下行代码要注释掉 ** HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); / return m_brush; //返加绿色刷子 } —- 方法四:还是重载OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。
具体步骤如下(以上例工程为准): —- 步骤①、②同上方法三中的步骤①、②。 —- 步骤③利用ClassWizard重载OnCtlColor(…)(即WM_CTLCOLOR消息)时则有些不同: HBRUSH CExampleDlgDlg::OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); //在这加一条是否为对话框的判断语句 if(nCtlColor ==CTLCOLOR_DLG) return m_brush; //返加绿色刷子 return hbr; }
删除、拷贝、移动文件夹及其文件
删除:
void COperationDlg::OnDel2(CString m_strFileDictory) //参数就是目录的路径 { if(m_strFileDictory.GetLength()==0) { ::AfxMessageBox (“目录名非法!”,MB_OK|MB_ICONEXCLAMATION); return; } char FromFileName[80]=”\0”; strcpy(FromFileName,m_strFileDictory); strcat(FromFileName,”\0”); SHFILEOPSTRUCT lpFileOp; lpFileOp.hwnd =GetSafeHwnd(); lpFileOp.wFunc =FO_DELETE; lpFileOp.pFrom =FromFileName; lpFileOp.pTo=NULL; lpFileOp.fFlags =FOF_SILENT|FOF_NOCONFIRMATION; lpFileOp.fAnyOperationsAborted =FALSE; lpFileOp.hNameMappings =NULL; lpFileOp.lpszProgressTitle =NULL; int rval=SHFileOperation(&lpFileOp;); if(rval==0) { if(lpFileOp.fAnyOperationsAborted ==TRUE) ::AfxMessageBox (“删除目录操作取消”,MB_OK); else ::AfxMessageBox(“删除目录操作成功!”,MB_OK|MB_ICONEXCLAMATION); } else { ::AfxMessageBox (“删除目录操作失败!”,MB_OK|MB_ICONEXCLAMATION); } }
拷贝 BOOL CCutfoldDlg::CopyDirectory(CString SourcePath,CString CopytoPath) { CFileFind tempFind; char tempFileFind[200]; char tempFileFind1[200];
SECURITY_ATTRIBUTES lpSecurityDescriptor;
CreateDirectory(CopytoPath,&lpSecurityDescriptor;);
/ { if(::MessageBox(0,”文件已经存在,是否覆盖?”,”警告”,MB_ICONQUESTION|MB_YESNO)==IDNO) return FALSE; } / sprintf(tempFileFind1,”%s\.“,CopytoPath); sprintf(tempFileFind,”%s\.“,SourcePath);
BOOL IsFinded=(BOOL)tempFind.FindFile(tempFileFind);
// BOOL IsFinded1=(BOOL)tempFind.FindFile(tempFileFind1); while(IsFinded) { IsFinded=(BOOL)tempFind.FindNextFile(); if(!tempFind.IsDots()) { char foundFileName[200]; // char foundFileName1[200]; strcpy(foundFileName,tempFind.GetFileName().GetBuffer(200)); // strcpy(foundFileName1,tempFind.GetFileName().GetBuffer(200)); if(tempFind.IsDirectory()) { char tempDir[200]; char tempDir1[200]; sprintf(tempDir,”%s\%s”,SourcePath,foundFileName); sprintf(tempDir1,”%s\%s”,CopytoPath,foundFileName); CopyDirectory(tempDir,tempDir1); } else { char tempFileName[200]; char tempFileName1[200]; sprintf(tempFileName,”%s\%s”,SourcePath,foundFileName); sprintf(tempFileName1,”%s\%s”,CopytoPath,foundFileName); //DeleteFile(tempFileName); CopyFile(tempFileName,tempFileName1,0); } } } tempFind.Close(); return TRUE; }
要实现移动,遍历文件+MoveFile+CreateDirectory 遍历方法参考: HANDLE hFind; WIN32_FIND_DATA dataFind; BOOL bMoreFiles=TRUE; hFind=FindFirstFile(sPath+”\*.txt”,&dataFind;);////sPath表示路径 while(hFind!=INVALID_HANDLE_VALUE && bMoreFiles==TRUE) { if(dataFind.dwFileAttributes==FILE_ATTRIBUTE_ARCHIVE) { MessageBox(dataFind.cFileName); } bMoreFiles=FindNextFile(hFind,&dataFind;); } FindClose(hFind);
模拟按键
模拟键盘我们用Keybd_event这个api函数,模拟鼠标按键用mouse_event函数。在VC里调用api函数是既简单又方便不过的事了。 首先介绍一下Keybd_event函数。Keybd_event能触发一个按键事件,也就是说回产生一个WM_KEYDOWN或WM_KEYUP消息。当然也可以用产生这两个消息来模拟按键,但是没有直接用这个函数方便。Keybd_event共有四个参数,第一个为按键的虚拟键值,如回车键为vk_return, tab键为vk_tab。第二个参数为扫描码,一般不用设置,用0代替就行第三个参数为选项标志,如果为keydown则置0即可,如果为keyup则设成“KEYEVENTF_KEYUP”,第四个参数一般也是置0即可。用如下代码即可实现模拟按下键,其中的XX表示XX键的虚拟键值,在这里也就是各键对应的键码,如’A’=65 keybd_event(65,0,0,0); keybd_event(65,0,KEYEVENTF_KEYUP,0); …
堆和栈的区别
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。 首先,我们举一个例子:
1 | void f() { int* p=new int[5]; } |
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
1
2
3
4
5
6
00401028 push 14h
0040102A call operator new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是```delete []p```,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。
好了,我们回到我们的主题:堆和栈究竟有什么区别?
主要的区别由以下几点:
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、分配方式不同;
6、分配效率不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:
打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。
注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。 从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。 虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。 无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:) 对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,清楚了?
获取CPU序列号
//取得IntelCPU的ID号:
void IntelCPUIDDlg::OnButtonCPUID() { unsigned long s1,s2; unsigned char vendor_id[]=”——————“; CString str1,str2,str3; asm { xor eax,eax cpuid mov dword ptr vendor_id,ebx mov dword ptr vendor_id[+4],edx mov dword ptr vendor_id[+8],ecx } str1.Format(“%s”,vendor_id); asm //取得CPU ID的高32位 { mov eax,01h xor edx,edx cpuid mov s2,eax } str2.Format(“%08X-“,s2);
__asm //取得CPU ID的低64位 { mov eax,03h xor ecx,ecx xor edx,edx cpuid mov s1,edx mov s2,ecx }
str3.Format(“%08X-%08X\n”,s1,s2); str2+=str3; m_editVendor.SetWindowText(str1); m_editCPUID.SetWindowText(str2); }
获取磁盘使用空间和剩余空间
char crDrv[3]; CStringArray strArray; _ULARGE_INTEGER n64TotalNumberOfBytes, n64TotalNumberOfFreeBytes; __int64 n64TotalFree = 0,n64TotalSpace = 0; float fTotalFree,fTotalSpace,fTempFree,fTempTotal; ULONG lTotalFree = 0,lTotalSpace = 0, lTempFree = 0,lTempTotal = 0; CString strInfo; BOOL bSuccess;
for(int n=2;n<=25;n++) { CString str; str.Format(“%c:\“,n+’A’); strcpy(crDrv,str); UINT nDrvType = GetDriveType(crDrv); switch(nDrvType) { case DRIVE_FIXED: { strArray.Add(crDrv); break; } default: { break; } } }
for(n = 0;n < strArray.GetSize();n ++) { bSuccess = SHGetDiskFreeSpace(strArray.GetAt(n), NULL,&n64TotalNumberOfBytes;, &n64TotalNumberOfFreeBytes;); n64TotalSpace += n64TotalNumberOfBytes.QuadPart; n64TotalFree += n64TotalNumberOfFreeBytes.QuadPart;
lTempTotal = (ULONG)(n64TotalNumberOfBytes.QuadPart/1024); lTempFree = (ULONG)(n64TotalNumberOfFreeBytes.QuadPart/1024); fTempTotal = (float)lTempTotal; fTempTotal = fTempTotal/1024/1024; fTempFree = (float)lTempFree; fTempFree = fTempFree/1024/1024;
strInfo.Format(“%s 容量: %4.2fGB,可用空间: %4.2fGB.”, strArray.GetAt(n),fTempTotal,fTempFree); AfxMessageBox(strInfo); }
lTotalSpace = (ULONG)(n64TotalSpace/1024); lTotalFree = (ULONG)(n64TotalFree/1024); fTotalSpace = (float)lTotalSpace; fTotalSpace = fTotalSpace/1024/1024; fTotalFree = (float)lTotalFree; fTotalFree = fTotalFree/1024/1024;
strInfo.Format(“总容量: %4.2fGB,总共可用空间: %4.2fGB.”, fTotalSpace,fTotalFree); AfxMessageBox(strInfo);
怎么在一个静态Picture控件中显示JPG文件
my example: HBITMAP CPicture::LoadImageFromID(UINT nIDRes) { try { HMODULE hInst=GetModuleHandle(NULL); LPCTSTR lpRes = MAKEINTRESOURCE(nIDRes); HRSRC hRsrc = ::FindResource(hInst, lpRes, “JPG”); if (NULL == hRsrc) return FALSE;
HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
if (NULL == hGlobal)
return FALSE;
DWORD dwSize = SizeofResource(hInst, hRsrc);
LPVOID lpData = LockResource(hGlobal);
if (NULL == lpData)
return FALSE;
// alloc memory based on file size
HGLOBAL hJPG = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
LPVOID lpJGP = ::GlobalLock(hJPG);
memcpy(lpJGP, lpData, dwSize);
::GlobalUnlock(hJPG);
//LPVOID pvData = GlobalLock(hGlobal);
//_ASSERTE(NULL != pvData);
// read file and store in global memory
LPSTREAM pstm = NULL;
// create IStream* from global memory
HRESULT hr = CreateStreamOnHGlobal(hJPG, TRUE, &pstm;);
_ASSERTE(SUCCEEDED(hr) && pstm);
// Create IPicture from image file
LPPICTURE gpPicture;
hr = ::OleLoadPicture(pstm, dwSize, FALSE, IID_IPicture, (LPVOID *)&gpPicture;);
_ASSERTE(SUCCEEDED(hr) && gpPicture);
pstm->Release();
OLE_HANDLE m_picHandle;
gpPicture->get_Handle(&m;_picHandle);
return (HBITMAP)m_picHandle;
}
catch (...)
{
}
return NULL;
} //call CPicture pic; HBITMAP hbmp=pic.LoadImageFromID(IDR_TODAY);//IDR_TODAY is jpg id (HBITMAP)::SendMessage(::GetDlgItem(this->m_hWnd,IDC_TODAY), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);