您好我想知道我用ole弄完几张相片怎么弄成一起后在窗体中是这样出现的,怎么能让他直接显示照片呢

我的aceess在窗体显示图片不显示_百度知道
我的aceess在窗体显示图片不显示
我有更好的答案
出现这种情况可能有两种可能:1、图片放在ACCESS数据库所在文件夹中,但后来又移开到其他文件夹。2、图片输入方式不对,一般是通过超链输入的。
来自:求助得到的回答
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。在C++ Builder中用Ole控制Excel表
?----  笔者在实际工作中经常用Excel表做数据报表,大多数表格的数据都要从数据库中读取,这样我就用C++Builder做了一个报表程序,方便了很多,现在把它共享给C++Builder爱好者们,就算为丰富C++Builder的文档资料做点事情吧。  首先把Excel报表文件保存到一个指定目录下,最好放在可执行程序的子目录下,作为模板文件。可以把报表标题、表头等设置好。这里是保存在trpt子目录下。  然后建一个report目录,作为报表目标文件夹,存放填好数据的报表,可以由用户直接操作。  首先确定在你的机器中装有Office。这里一Office2000为例。  在C++Builder中新建一个工程,在窗体Form1上面放一个两个按钮SaveButton和ReadButton,分别用来保存数据到Excel表和显示刚刚保存的Excel表。  在SaveButton按钮的单击事件中把从数据库中取到的数据放入到指定的Excel表中并将改文件拷贝到report目录下。在ReadButto按钮的单击事件中显示report目录下的报表文件,方便用户修改和另外保存。  在Form1.h头文件中定义几个变量:
private:Variant Ex,Wb,Sheet,ERange,EB  并在文件头中包含如下语句:
#include "Excel_2K_SRVR.h"#include   在Form1.cpp的文件头中加入
#pragma link "Excel_2K_SRVR"  主要代码如下:
void __fastcall TForm1:: SaveButtonClick(TObject *Sender){try{SaveButton-&Enabled =ReadButton-&Enabled =//使两个按钮无效file://取报表文件CardSend.xls的完整目录名AnsiString ExcelFileName = GetCurrentDir()+"\\trpt\\table.xls"; if(!FileExists(ExcelFileName)){Application-&MessageBox("报表模板文件不存在,无法打开!","错误",MB_ICONSTOP|MB_OK);}file://建立Excel的Ole对象Extry{Ex = Variant::CreateObject("Excel.Application");}catch(...){Application-&MessageBox("无法启动Excel","错误",MB_ICONSTOP|MB_OK);}file://设置Excel为不可见Ex.OlePropertySet("Visible",false);file://打开指定的Excel报表文件。报表文件中最好设定只有一个Sheet。Ex.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());Wb = Ex.OlePropertyGet("ActiveWorkBook");Sheet = Wb.OlePropertyGet("ActiveSheet");//获得当前默认的Sheetfile://清空Excel表,这里是用循环清空到第300行。对于一般的表格已经足够了。AnsiString strRowT AnsiString strRint iCols,iR//记录列数和行数/*从第三行开始,到第300行止。一般第一行是表标题,第二行是副标题或者制表日期。*/for(iRows=3;iRows&300;iRows++){ file://假设只有6列。for (iCols = 1;iCols & 7; iCols++){file://清空行Sheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value","");}file://去掉表格边框strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);//获取操作范围ERange = Sheet.OlePropertyGet("Range",strRange.c_str());EBorders = ERange.OlePropertyGet("Borders");//获取边框对象EBorders.OlePropertySet("linestyle",xlNone);}AnsiString strPtrD file://存放当前日期,作为制表日期DateSeparator = '-';ShortDateFormat = "yyyy/m/d";//设置为年/月/日格式strPtrDate = DateToStr(Date());//取当前日期AnsiString strYear = strPtrDate.SubString(1,4);strPtrDate = strPtrDate.SubString(6,strPtrDate.Length()-5);AnsiString strMonth = strPtrDate.SubString(1,strPtrDate.Pos("-")-1);AnsiString strDay = strPtrDate.SubString(strPtrDate.Pos("-")+1,strPtrDate.Length()-strPtrDate.Pos("-"));strPtrDate = strYear+"年"+strMonth+"月"+strDay+"日";AnsiString strData = "报表标题";//报表标题file://将报表标题置于第一行第一列。在此之前,应将报表文件的标题格式设定好。Sheet.OlePropertyGet("Cells",1,1).OlePropertySet("Value",strData.c_str());file://将制表日期置于表格第二行的右侧。Sheet.OlePropertyGet("Cells",2,5).OlePropertySet("Value",strPtrDate.c_str());iRows = 3;//在第三行放置表格的列名Sheet.OlePropertyGet("Cells",iRows,1).OlePropertySet("Value","列名1");Sheet.OlePropertyGet("Cells",iRows,2).OlePropertySet("Value","列名2");Sheet.OlePropertyGet("Cells",iRows,3).OlePropertySet("Value","列名3");Sheet.OlePropertyGet("Cells",iRows,4).OlePropertySet("Value","列名4");Sheet.OlePropertyGet("Cells",iRows,5).OlePropertySet("Value","列名5");Sheet.OlePropertyGet("Cells",iRows,6).OlePropertySet("Value","列名6");file://画表格边框,在A3:F3之间取范围strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);ERange = Sheet.OlePropertyGet("Range",strRange.c_str());EBorders = ERange.OlePropertyGet("Borders");EBorders.OlePropertySet("linestyle",xlContinuous);EBorders.OlePropertySet("weight",xlThin);EBorders.OlePropertySet("colorindex",xlAutomatic);iRows++;file://从数据库中取数据(略),假设数据集放入Query1中。Query1-&Open();//打开数据集file://循环取数while(!Query1-&Eof){ file://循环取字段的数据放到Excel表对应的行列中for(iCols=1;iCols&7;iCols++){ strRowTemp = Query1-&Fields-&Fields[iCols-1]-&AsSSheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value",strRowTemp.c_str());}file://画该行的表格边框strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);ERange = Sheet.OlePropertyGet("Range",strRange.c_str());EBorders = ERange.OlePropertyGet("Borders");EBorders.OlePropertySet("linestyle",xlContinuous);EBorders.OlePropertySet("weight",xlThin);EBorders.OlePropertySet("colorindex",xlAutomatic);iRows++;Query1-&Next();}//while结束Wb.OleProcedure("Save");//保存表格Wb.OleProcedure("Close");关闭表格Ex.OleFunction("Quit");退出Excelfile://定义目标文件名AnsiString DestinationFile =GetCurrentDir()+"\\report\\table.xls";file://将刚刚修改的Excel表格文件table.xls拷贝到report目录下if(!CopyFile(ExcelFileName.c_str(),DestinationFile.c_str(),false)){Application-&MessageBox("复制文件操作失败,Excel文件可能正在使用中!","错误",MB_ICONSTOP|MB_OK);}Application-&MessageBox("成功完成报表保存!\n可以按\'打开Excel文件\'按钮进行报表工作","提示",MB_ICONINFORMATION|MB_OK);SaveButton -&Enabled =ReadButton -&Enabled=}//try结束catch(...){Application-&MessageBox("操作Excel表格失败!","错误",MB_ICONSTOP|MB_OK);Wb.OleProcedure("Close");Ex.OleFunction("Quit");SaveButton -&Enabled =ReadButton -&Enabled=}}  至此,完成报表数据的写入工作。如果要对完成的Excel表进行操作,可以点击"打开Excel表文件按钮"(ReadButton),进行修改,保存,打印等操作。ReadButton的单击事件如下实现:
void __fastcall TForm1:: ReadButtonClick(TObject *Sender){try{file://指定report目录下的报表文件用于用户操作AnsiString ExcelFileName = GetCurrentDir();+"\\report\\table.xls";if(!FileExists(ExcelFileName)){Application-&MessageBox("Excel表文件不存在,无法打开!","错误",MB_ICONSTOP|MB_OK);}try{Ex = Variant::CreateObject("Excel.Application");}catch(...){Application-&MessageBox("无法启动Excel","错误",MB_ICONSTOP|MB_OK);}file://使Excel可见Ex.OlePropertySet("Visible",true);file://打开Excel表格文件Table.xlsEx.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());}catch(...){Application-&MessageBox("操作Excel表格错误!","错误",MB_ICONSTOP|MB_OK);Ex.OleFunction("Quit");}}  以上关于C++BuilderExcel表格的操作仅作为个人观点和水平呈献给关心此问题的读者,如果有更好的方式方法,敬请指教,不胜感激。
【责任编辑:方舟】 ■ 相关内容当前位置:
access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!
access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!
来源:网络整理&&&&&时间: 18:13:45&&&&&关键词:access,ole对象
关于网友提出的“access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!”问题疑问,本网通过在网上对“access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!”有关的相关答案进行了整理,供用户进行参考,详细问题解答如下:
问题:access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!
access&ole对象字段存储图片信息。我在获取的时候出现问题(开发环境vs.net&2005):
1、直接在数据表中右键-》插入对象-》有文件创建-》选择文件(*.bmp);我用C#偏移74个字节,可以在PictureBox能显示图片
2、同步骤一,但在选择文件之后如果勾上“链接”选择框,我用循环偏移所有字节,都不能在PictureBox显示图片
3、把这两种情况的字段值保存成二进制文件比较了一下,差别很大;第二者根本不具备BMP文件格式(如头两个字节是0x424D)。
但是这两种保存的记录在ACCESS窗体的绑定对象框控件(olebound,&ole对象)都能正确显示。
我想问这个控件是怎么解析的。我想在VS2005中自己开发一个类似控件来显示图片,该如何实现解决方案1:
我目前遇到的问题,如何通过&.ashx动态获取数据库图片,愁死。。
解决方案2:
读文件按二进制方式!
解决方案3:
把二进制写成MemoryStream,然后用image从这里取图片,Image.From(。。。),注意从Access取出来的二进制是有编码的,我用的是Unicode,用特定的编码才能把数据还原
解决方案4:
楼主好问题啊,我也正需要这方面资料呢,谢谢,答案出来别人贴出来,大家学习啊
解决方案5:
具体是怎样实现把二进制流换成图像我也不清楚!!
你可以扩展其控件!!
解决方案6:
帮你顶!!
以上介绍了“access ole对象字段存储图片信息,在VSNET 2005中窗体中显示,不是论坛中问过的问题!”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:http://www.codes51.com/itwd/1569545.html
上一篇: 下一篇:博客分类:
在Windows中运行的程序,大多数都有一个或几个可以看得见的窗口,而在这些窗口被创建起来之前,操作系统怎么知道该怎样创建该窗口,以及用户操作该窗口的各种消息交给谁处理呢?所以VC在调用Windows的API(CreateWindow或者CreateWindowEx)创建窗口之前,要求程序员必须定义一个窗口类(不是传统C++意义上的类)来规定所创建该窗口所需要的各种信息,主要包括:窗口的消息处理函数、窗口的风格、图标、 鼠标、菜单等。其定义如下:
typedef struct tagWNDCLASSA(注:该结构为ANSII版本) { UINT WNDPROC
lpfnWndP int
cbClsE int
cbWndE HINSTANCE
hI HCURSOR
hbrB LPCSTR
lpszMenuN LPCSTR
lpszClassN }WNDCLASSA, * PWNDCLASSA, NEAR * NPWNDCLASSA, FAR * LPWNDCLASSA ;
style 表示该类窗口的风格,如style = CS_VREDRAW|CS_HREDRAW表示窗口在运动或者调整大小时需要重画,关于其它风格可在 MSDN中查到。 lpfnWndProc为一指针,指向用户定义的该窗口的消息处理函数。 cbClsExtra 用于在窗口类结构中保留一定空间,用于存在自己需要的某些信息。 cbWndExtra用于在Windows内部保存的窗口结构中保留一定空间。 hInstance 表示创建该窗口的程序的运行实体代号(WinMain的参数之一)。 hIcon、hCursor、hbrBackground、lpszMenuName分别表示该窗口的图标、鼠标形状、背景色以及菜单。 lpszClassName表示该窗口类别的名称,即标识该窗口类的标志。   从上面可以看出一个窗口类就对应一个WNDCLASSA结构(这里以ANSII为例),当程序员将该结构按自己要求填写完成后,就可以调用RegisterClass(或RegisterClassEx)函数将该类注册,这样以后凡是要创建该窗口,只需要以该类名(lpszClassName中指定)为参数调用CreateWindow,你看多方便呀,真是一举多得啊!
总结:但窗口结构注册(调用RegisterClass(或RegisterClassEx)函数)后,以后凡是要创建该窗口,只需要以该类名(lpszClassName中指定)为参数调用CreateWindow。二、传统SDK中的窗口类   既然我们知道了什么是窗口类,那我们就将它放到一个传统的SDK程序中,看看是怎样运行的。 #include &windows.h&
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLAS
wndclass.style
= CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndP wndclass.cbClsExtra
= 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance
= hI wndclass.hIcon
= LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor
= LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuNam = NULL ; wndclass.lpszClassName = szAppN
RegisterClass (&wndclass);
hwnd = CreateWindow( szAppName, // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle
// window menu handle
hInstance,
// program instance handle
// creation parameters
ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{ TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
} return msg.wP }
  这是一个标准的Windows程序代码,程序被启动后,填写一个窗口类,然后调用RegisterClass将该类注册,接着创建该窗口,最后显示窗口和进入消息循环。
三、MFC中的窗口类   当你看到这里,也许你可能会感到奇怪:我在用MFC向导做程序时,并没有进行什么窗口类的填写和注册吗?是的,你没有,但是向导帮你做了。在展示向导是怎么做的之前,请让我先介绍一下预先知识。   在MFC系统中定义了五个默认的窗口类(这里不包括AFX_WNDCOMMCTLS_REG),分别定义在AFXIMPL.h中:
#define AFX_WND_REG
#define AFX_WNDCONTROLBAR_REG
#define AFX_WNDMDIFRAME_REG
#define AFX_WNDFRAMEORVIEW_REG
#define AFX_WNDDOLECONTROL_REG
在WINCORE.cpp定义了这些窗口类对应的字符串名称:
const TCHAR _afxWnd[] = AFX_WND;
const TCHAR _afxWndControlBar[] = AFX_WNDCONTROLBAR;
const TCHAR _afxWndMDIFrame[] = AFX_WNDMDIFRAME;
const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;
const TCHAR _afxWndOleControl[] = AFX_WNDOLERONTROL;
在AFXIMPL.h中定义了五个AFX_XXX对应的字符串:
#define AFX_WND
AFX_WNDCLASS("WND")
#define AFX_WNDCONTROLBAR
AFX_WNDCLASS("ControlBar")
#define AFX_WNDMDIFRAME
AFX_WNDCLASS("MDIFrame")
#define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView")
#define AFX_WNDOLECONTROL
AFX_WNDCLASS("OleControl")
  看到这里也许有些心急了,其实上面一堆代码只是定义了五个默认窗口类的字符串名称和二进制名称,具体注册行为在全局函数AfxDeferRegisterClass中: #define AfxDeferRegisterClass(fClass) \ ((afxRegisteredClasses & fClass) ? TRUE:AfxEndDeferRegisterClass(fClass)
#define afxRegisteredClasses AfxGetModuleState()-&m_fRegisteredClasses
BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
WNDCLASS wndC
wndCls.lpfnWndProc = DefWindowP
if(fClass & AFX_WND_REG)
wndCls.lpszClassName=_afxW
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDOLECONTROL_REG)
wndCls.lpszClassName=_afxWndOleC
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDCONTROLBAR_REG)
wndCls.lpszClassName=_afxWndControlB
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDMDIFRAME_REG)
RegisterWithIcon(&wndCls,_afxWndMDIFrame,AFX_IDI_MDIFRAME);
}else if(fClass & AFX_WNDFRAMEORVIEW_REG)
RegisterWithIcon(&wndCls,_afxWndFrameOrView,AFX_IDI_STD_FRAME);
}else if(fClass & AFX_WNDCOMMCTLS_REG)
InitCommonControls();
} 从以上例子可以看出, AfxDeferRegisterClass函数用if/else结构实现各种不同窗口的注册,所所以MFC函数窗口注册的时候调用AfxDeferRegisterClass函数就可以了。  从上面的代码可以看出,AfxDeferRegisterClass函数首先判断该窗口类是否注册,如已注册则直接返回,否则调用AfxEndDeferRegisterClass进行注册,即注册要求的默认窗口类。其中RegisterWithIcon和InitCommonControls最终也是转化为调用AfxRegisterClass,而AfxRegisterClass函数调用RegisterClass进行注册,啊,终于看到SDK中的RegisterClass了,看到它总有一种亲切感!   有了上面的知识,我们就可以很容易摸清MFC是怎样注册窗口类的了!我们知道Windows上所有看得见的东西,在MFC中都是继承于CWnd类的,而CWnd类创建窗口的成员函数是Create和CreateEx,由于Create最终是调用CreateEx,所以我们只需要看CreateEx函数就行了: create()--&CreateEx()??CREATESTRUCT??
PreCreateWindow(cs);|?? AfxDeferRegisterClass(AFX_WND_REG)
?? CreateWindowEx()
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCSTSTR lpszClassName,
…… LPVOID lpParam)
CREATESTRUCT
cs.dwExStyle = dwExS
cs.lpCreateParams = lpP
PreCreateWindow(cs);
AfxHookWindowCreate(this);
HWND hWnd=::CreateWindowEx(cs.dwStyle,cs.lpszClass,…,cs.lpCreateParams);
  啊,一看到CreateWindowEx,亲切感又来了,这不是和SDK中的CreateWindow一样嘛,是创建窗口!既然这样,那么注册窗口肯定在该函数之前,会是谁呢?如果你做过一点MFC程序,你就会对将眼光停留PreCreateWindow上。对!就是它了。   PreCreateWindow函数是CWnd类的一个虚拟函数,提供程序设置待创建窗口的属性(包括窗口类),这样继承于CWnd的类都可以按照自己的要求在PreCreateWindow中设置自己的属性了,而且我们看到MFC也是这样做的: BOOL CWnd::PreCreateWindow(CREATESTRUCT &cs) {
if(cs.lpszClass = = NULL)
AfxDeferRegisterClass(AFX_WND_REG);
cs.lpszClass = _afxW
return TRUE; }
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs) {
if(cs.lpszClass = = NULL)
AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
cs.lpszClass = _afxWndFrameOrV
return TRUE; }
BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT &cs) {
if(cs.lpszClass = = NULL)
AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG);
cs.lpszClass = _afxWndMDIF
BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT &cs) {
return CFrameWnd::PreCreateWindow(cs); }
BOOL CView::PreCreateWindow(CREATESTRUCT &cs) {
if(cs.lpszClass = = NULL)
AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
cs.lpszClass = _afxWndFrameOrV
就是通过继承的方法,MFC实现常用类的窗口注册(代码并不完全,是从MFC中抽取对我们有意义的一部分代码)。
四、在MFC中注册自己的窗口类   在MFC中创建一个窗口,就必须是继承于CWnd类的,这样你的CMyWnd类自然就有了PreCreateWindow方法。你想注册有自己个性的窗口类,那么就在该函数中进行吧。也就是在PreCreateWindow函数中注册自己的窗口类,然后将窗口类的类名以及待创建窗口的其它属性(见CREATESTRUCT结构)填写cs,然后返回系统,供系统创建你的窗口。
用SDK建立类的过程:填写一个窗口类,然后调用RegisterClass将该类注册,接着创建该窗口,最后显示窗口和进入消息循环。 用MFC建立窗口的过程:我们知道Windows上所有看得见的东西,在MFC中都是继承于CWnd类的,而CWnd类创建窗口的成员函数是Create和CreateEx,由于Create最终是调用CreateEx,所以我们只需要看CreateEx函数就行了: create()--&CreateEx()??CREATESTRUCT??PreCreateWindow(cs);|?? AfxDeferRegisterClass(AFX_WND_REG)
?? AfxHookWindowCreate(this); //为窗口关联一个消息处理函数WndProc()
?? CreateWindowEx()**********************************************************************************************CWnd::CreateEX中HOOK函数作用
字号: 大大
小小 用最基本的一句话概述,钩子函数起了很大作用。故事是这样的,有些漫长,也需要些耐心。
MFC中消息分为3类:
1. WM_COMMAND:所有的UI组件和加速键都会产生这种消息,所有派生于CCmdTarget的类都有能力处理该消息
2. 标准消息:除WM_COMMAND之外的WM_xx消息都是标准消息,派生于CWnd的类都有能力处理该消息
3. 控件通知消息:用于子窗口控件向父窗口发送的消息
在MFC的消息映射表的建立中,通过一组宏,你就可以让自己的类先于父类处理某些Windows消息,这种行为很像虚函数,只是我们重载的内容不是虚函数,而是消息。
推动消息的泵
第一阶段 窗口过程在产生一个窗口的时候,会调用CFrameWnd::Create,所有的故事也都从这里展开。下面的代码为了简洁,去掉了不相关的代码
BOOL CFrameWnd::Create(…)
( ! CreateEx(…))
} BOOL CWnd::CreateEx(…)
AfxHookWindowCreate( this );
::CreateWindowEx(…);
AFXAPI AfxHookWindowCreate(CWnd *
(pThreadState -& m_hHookOldCbtFilter
pThreadState -& m_hHookOldCbtFilter
::SetWindowsHookEx(WH_CBT,
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
pThreadState -& m_pWndInit
这样,通过AfxHookWindowCreate,在当前线程中安装了一个钩子,用来拦截和窗口相关的事件,每当:1. 另一个窗口成为active;2. 产生或摧毁一个窗口3. Minimize或maximize一个窗口;4. 移动或缩放一个窗口;5. 完成一个来自系统菜单的命令;6. 从系统队列中取出一个消息;时,都会先调用_AfxCbtFilterHook(即每当有一个可能引发消息发生的事件的时候都会调用_AfxCbtFilterHook,然后这个函数对这些消息进行过滤,能够处理的就交给AfxGetAfxWndProc,不能处理的就交给全局的DefWndProc()函数),接下来看看钩子函数作了什么:
LRESULT CALLBACK_AfxCbtFilterHook( int
code, WPARAM wParam, LPARAM lParam)
WNDPROC afxWndProc
AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(DWORD_PTR)afxWndProc);
WNDPROC AFXAPI AfxGetAfxWndProc()
& AfxWndP}
这样,_AfxCbtFilterHook的工作总结起来就是通过窗口子类化,把新建的窗口的窗口过程设置成AfxWndProc。到这里,我们终于找到了窗口过程。结论CFrameWnd::Create创建窗口调用CWnd::CreateExCWnd::CreateEx调用AfxHookWindowCreate准备为窗口设置钩子AfxHookWindowCreate调用::SetWindowHookEx为窗口设置了一个WH_CBT类型的钩子来过滤消息,并把过滤函数设置成_AfxCbtFilterHook_AfxCbtFilterHook通过窗口子类化设置窗口的窗口过程为AfxWndProc这样,通过::DispatchMessage发送给窗口的消息就会源源不断地送到AfxWndProc中来,可以想到,AfxWndProc利用MFC的消息映射表,分门别类的对消息进行分流。
即每当有一个可能引发消息发生的事件的时候都会调用_AfxCbtFilterHook,然后这个函数对这些消息进行过滤,能够处理的就交给AfxGetAfxWndProc,不能处理的就交给全局的DefWndProc()函数OnNcCreate,当CWnd对象第一次被创建时,框架在WM_CREATE消息之前调用这个成员函数。可以修改CREATESTRUCT结构,PreCreateWindow也是可以修改CREATESTRUCT
结构,他们有什么区别?
PreCreateWindow用的比较多,OnNcCreate都用在什么地方??
OnNcCreate是响应WM_NCCREATE,
当窗口开始时先创建客户区,所以先发送WM_NCCREATE消息,
当非客户区都创建好了,再发送WM_CREATE,去创建窗口客户区,
WM_NCCREATE
意思是说,WM_NCCREATE比WM_CREATE先发给窗口程序,在窗口一创建的时候
CreateWindow/CreateWindowEx开始
PreCreateWindow
HOOK(窗口句柄无效)
WM_NCCREATE
(窗口句柄有效)
(窗口句柄有效)
CreateWindow/CreateWindowEx结束
这些很容易验证[转]CWnd中PreCreateWindow、PreSubclassWindow、SubclassWindow的区别 Posted on
16:35 天之骄子 阅读(503) 评论(0)
编辑 收藏 引用
MFC(VC6.0)的CWnd及其子类中,有如下三个函数:
class CWnd : public CCmdTarget {public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void PreSubclassWindow();
BOOL SubclassWindow(HWND hWnd);
};  让人很不容易区分,不知道它们究竟干了些什么,在什么情况下要改写哪个函数?  想知道改写函数?让我先告诉你哪个不能改写,那就是SubclassWindow。Scott Meyers的杰作&&Effective C++&&的第36条是这样的Differentiate between inheritance of interface and inheritance of implementation. 看了后你马上就知道,父类中的非虚拟函数是设计成不被子类改写的。根据有无virtual关键字,我们在排除了SubclassWindow后,也就知道PreCreateWindow和PreSubClassWindow是被设计成可改写的。接着的问题便是该在什么时候该写了。要知道什么时候该写,必须知道函数是在什么时候被调用,还有执行函数的想要达到的目的。我们先看看对这三个函数,MSDN给的解释:  PreCreateWindow:  Called by the framework before the creation of the Windows window   attached to this CWnd object.  (译:在窗口被创建并attach到this指针所指的CWnd对象之前,被framework调用)  PreSubclassWindow:  This member function is called by the framework to allow other necessary   subclassing to occur before the window is subclassed.  (译:在window被subclassed之前被framework调用,用来允许其它必要的subclassing发生)虽然我已有译文,但还是让我对CWnd的attach和窗口的subclass作简单的解释吧!要理解attach,我们必须要知道一个C++的CWnd对象和窗口(window)的区别:window就是实在的窗口,而CWnd就是MFC用类对window所进行C++封装。attach,就是把窗口附加到CWnd对象上操作。附加(attach)完成后,CWnd对象才和窗口发生了联系。窗口的subclass是指修改窗口过程的操作,而不是面向对象中的派生子类。  好了,PreCreateWindow由framework在窗口创建前被调用,函数名也说明了这一点,Pre应该是previous的缩写,PreSubclassWindow由framework在subclass窗口前调用。 这段话说了等于没说,你可能还是不知道,什么时候该改写哪个函数。罗罗嗦嗦的作者,还是用代码说话吧!源码之前,了无秘密(候捷语)。我们就看看MFC中的这三个函数都是这样实现的吧!
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
// allow modification of several common create parameters
CREATESTRUCT
cs.dwExStyle = dwExS
cs.lpszClass = lpszClassN
cs.lpszName = lpszWindowN
cs.style = dwS
cs.cx = nW
cs.cy = nH
cs.hwndParent = hWndP
cs.hMenu = nIDorHM
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpP
if (!PreCreateWindow(cs))
PostNcDestroy();
return FALSE;
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
return TRUE; }
// for child windowsBOOL CWnd::PreCreateWindow(CREATESTRUCT& cs){
if (cs.lpszClass == NULL)
// make sure the default window class is registered
VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
// no WNDCLASS provided - use child window default
ASSERT(cs.style & WS_CHILD);
cs.lpszClass = _afxW
return TRUE; }  CWnd::CreateEx先设定cs(CREATESTRUCT),在调用真正的窗口创建函数::CreateWindowEx之前,调用了CWnd::PreCreateWindow函数,并把参数cs以引用的方式传递了进去。而CWnd的PreCreateWindow函数也只是给cs.lpszClass赋值而已。毕竟,窗口创建函数CWnd::CreateEx的诸多参数中,并没有哪个指定了所要创建窗口的窗口类,而这又是不可缺少的(请参考&&windows程序设计&&第三章)。所以当你需要修改窗口的大小、风格、窗口所属的窗口类等cs成员变量时,要改写PreCreateWindow函数。
// From VS Install PathVC98MFCSRCWINCORE.CPP BOOL CWnd::SubclassWindow(HWND hWnd){
if (!Attach(hWnd))
return FALSE;
// allow any other subclassing to occur
PreSubclassWindow();
// now hook into the AFX WndProc
WNDPROC* lplpfn = GetSuperWndProcAddr();
WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
(DWORD)AfxGetAfxWndProc());
ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());
if (*lplpfn == NULL)
*lplpfn = oldWndP
// the first control of that type created #ifdef _DEBUG
else if (*lplpfn != oldWndProc){
::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
return TRUE; }
void CWnd::PreSubclassWindow(){
// no default processing }  CWnd::SubclassWindow先调用函数Attach(hWnd)让CWnd对象和hWnd所指的窗口发生关联。接着在用::SetWindowLong修改窗口过程(subclass)前,调用了PreSubclassWindow。CWnd::PreSubclassWindow则是什么都没有做。  在CWnd的实现中,除了CWnd::SubclassWindow会调用PreSubclassWindow外,还有一处。上面所列函数CreateEx的代码,其中调用了一个AfxHookWindowCreate函数,见下面代码:
// From VS Install PathVC98MFCSRCWINCORE.CPP BOOL CWnd::CreateEx( )
// allow modification of several common create parameters
if (!PreCreateWindow(cs))
PostNcDestroy();
return FALSE;
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
return TRUE; }  接着察看AfxHookWindowCreate的代码:
// From VS Install PathVC98MFCSRCWINCORE.CPP void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
if (pThreadState-&m_hHookOldCbtFilter == NULL)
pThreadState-&m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
if (pThreadState-&m_hHookOldCbtFilter == NULL)
AfxThrowMemoryException();
}   其主要作用的::SetWindowsHookEx函数用于设置一个挂钩函数(Hook函数)_AfxCbtFilterHook,每当Windows产生一个窗口时(还有许多其它类似,请参考&&深入浅出MFC&&第9章,563页),就会调用你设定的Hook函数。  这样设定完成后,回到CWnd::CreateEx函数中,执行::CreateWindowEx进行窗口创建,窗口一产生,就会调用上面设定的Hook函数_AfxCbtFilterHook。而正是在_AfxCbtFilterHook中对函数PreSubclassWindow进行了第二次调用。见如下代码: // From VS Install PathVC98MFCSRCWINCORE.CPP
/**////////////////////////////////////////////////////////////////////////////// // Window creation hooks
LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
// connect the HWND to pWndInit
pWndInit-&Attach(hWnd);
// allow other subclassing to occur first
pWndInit-&PreSubclassWindow();
// subclass the window with standard AfxWndProc
oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)afxWndProc);
ASSERT(oldWndProc != NULL);
*pOldWndProc = oldWndP
}  也在调用函数SetWindowLong进行窗口subclass前调用了PreSubclassWindow.通常情况下窗口是由用户创建的 CWnd::Create(..) ●在此流程中,MFC提供一个机会"PreCreateWindow()供用户在创建前作点手脚
而对于对话框等,窗口是通过subclass方式交给用户的 系统读入对话框模板,建立其中各个子窗口
然后将各子窗口的 消息处理函数替换成 对应的C++对象 的消息处理函数 (Subclass:子类化,或"接管") ,然后,这个子窗口就会按类中定义的方式来动作了。
在此过程中,调用的是CWnd:SubclassWindow( HWND hWnd ); ●在此流程中,MFC提供一个机会"PreSubclassWindow" 供用户在关联前作点手脚
具体来说,如果你定义一个窗口(如CButton派生类CMyButton),然后使用对话框数据交换将一个按钮与自己的派生类对象关联,这时候,一些"建立前"的处理就应该写在"PreSubclassWindow"中。
如果你用的不是"对话框数据关联",而是在OnInitDialg中自己创建m_mybtn.Create(...) 这时候,一些"建立前"的处理就应该写在 "PreCreateWindow"中。这里“建立前”的处理包括像那些处理,跟PreCreateWindows()做的一些窗口初始化的工作有什么不同?PreCreateWindows函数中没有窗口可以用——还没有创建 PreSubclassWindow函数中可以对窗口进行操作。******************************这些在窗口创建之初就加入了钩子,能否截获这些钩子。
------------------以下内容是对上面内容的具体解释,两部分必须结合着看--------------------------------------
MFC的窗口类(如CWnd)与窗口过程。 Windows是基于事件机制的,任何窗口都能发送和处理消息,每一个窗口都对应着自己的消息处理函数,即通常所说的窗口过程(WindowProc)。窗口过程通常是在WNDCLASSEX的lpfnWndProc变量中指定的,然后调用RegisterClassEx注册窗口类,lpfnWndProc要求是全局的或是类的静态成员,而MFC的窗口和类对象是一一对应的,在类中定义的窗口过程(CWnd::WindowProc)并非类的静态成员,那么窗口消息是怎样传给窗口对象的WindowProc函数去处理的呢?MFC中定义了一个全局的AfxWndProc函数,AfxWndProc是MFC中所有的窗口共用的窗口过程。这里要注意在AfxEndDeferRegisterClass中注册窗口类时并没有把AfxWndProc赋给lpfnWndProc,而是把DefWindowProc赋给了lpfnWndProc。真正把AfxWndProc指定为窗口过程的是在CWnd::CreateEx函数中,CWnd::CreateEx中先后调用了SetWindowsHookEx、CreateWindowEx和UnhookWindowsHookEx,SetWindowsHookEx安装了一个WH_CBT类型的钩子,在调用CreateWindowEx时(在CreateWindowEx返回之前)窗口会发送WM_CREATE、 WM_NCCREATE等消息,钩子过程CBTProc会在窗口消息WM_CREATE、 WM_NCCREATE等发送前被调用,并提前得到窗口的句柄值。钩子过程CBTProc的任务是把窗口句柄赋给窗口对象(CWnd::m_hWnd),并调用SetWindowLong把窗口过程替换成AfxWndProc(如是控件还要保留原窗口过程,用CallWindowProc进行默认处理)。在这有人可能会问,为什么不在AfxEndDeferRegisterClass中直接指定AfxWndProc呢?当然是有原因的:其一是控件的窗口过程必须用SetWindowLong来替换,其二是消息WM_CREATE、 WM_NCCREATE等是在CreateWindowEx返回前发送的,CWnd::WindowProc在处理这些消息时CWnd::m_hWnd必须是已经被初始化的,这个就是由前面的CBTProc完成的。 好现在我们只要关注AfxWndProc了。AfxWndProc是如何把消息分配给各个窗口对象的窗口过程的呢?在MFC中有一个全局的映射表(还没到消息映射,呵呵),这个表是窗口句柄到窗口对象的映射(即通过窗口句柄就能找到窗口对象的地址),找到了窗口对象就可以把消息处理的任务交给CWnd::WindowProc了(调用pWnd- &WindowProc)。
下面就是消息映射了 其实这就简单了,因为这时只需关注CWnd::WindowProc和消处理函数(如onCreate)了。在MFC中定义了几个宏:DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP等,其实把这几个宏换回来就很好理解了。为了便于理解,我把这些宏简化一下: // typedef struct _MSGMAP_ENTRY { UINT nM //消息 void (CWnd::*pfn)(); //消息处理函数据 }MSGMAP_ENTRY;
DECLARE_MESSAGE_MAP相当于 static MSGMAP_ENTRY _MessageEntry[]; //定义了一个映射表
BEGIN_MESSAGE_MAP、END_MESSAGE_MAP和两者之间的宏相当于 MSGMAP_ENTRY CWnd::_MessageEntry[] = { {WM_CREATE, &onCreate}, //第一个消息映射 {WM_CLOSE, &onClose}, //第二个消息映射 {0, 0} //消息映射结尾 };
CWnd::WindowProc之不过是在_MessageEntry[]查找有没有定义的消息,如有,则调用相应的处理函数,如没有则调用CWnd::DefWindowProc
还想提一下Delphi中的相关处理,Delphi是不是用了同样的方法呢?答案是否定的,Delphi用汇编语句把类的非静态成员函数的地址赋给lpfnWndProc,这个也很有意思,当然用C++也可这么做。
对于传递函做个解释如下:
AfxWndProc()
该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc
AfxCallWndProc()
该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数
WindowProc()
该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数
OnWndMsg()
该函数的功能首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数,对于WM_NOTIFY消息调用OnNotify()消息响应函数。任何被遗漏的消息将是一个窗口消息。OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数
OnCommand()
该函数查看这是不是一个控件通知(lParam参数不为NULL,如果lParam参数为空的话,说明该消息不是控件通知),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果他不是一个控件通知(或者如果控件拒绝映射的消息)OnCommand()就会调用OnCmdMsg()函数
OnNotify()也试图将消息映射到制造通知的控件;如果映射不成功,OnNotify()就调用相同的OnCmdMsg()函数
OnCmdMsg()
根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。例如:如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数
浏览: 1288856 次
来自: 北京
标示对java很陌生!
Java中\是转意字符, 可是你的这句话我没看懂,只要把得到的 ...
可以参考最新的文档:如何在eclipse jee中检出项目并转 ...
,非常好。
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 相片上加字怎么弄的 的文章

 

随机推荐