MFC嵌入CEF

2024-03-04 13:48
文章标签 mfc 嵌入 cef

本文主要是介绍MFC嵌入CEF,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这篇文章详细解说了如何把CEF嵌入到MFC对话框工程中,一步一步的从CEF提供的例子中分析代码,挑出必须的模块加入到MFC工程中去,有图有真相,很有学习和参考的价值。


原文地址:http://blog.csdn.net/chenlycly/article/details/53352208

(文中给出的原始的链接地址已经失效,文末的源码和库文件链接地址都可以正常使用,由于CEF版本和我用的不一样,所以本人没有下载)


上一篇文章中写道了关于CEF内核基本使用用法,这章我将带领大家讲CEF应用到MFC中,大家都知道libCEF自带的cefclient和cefsimple都是基于win32的Demon,那么在MFC中如何使用cef呢?正如duilib中自带的demon也是基于win32一样,同样的做法我将告诉大家如何在MFC中使用CEF,做法很简单,如果大家看了cefsimiple这个简单的Demon,我们就知道大概的做法了。首先分析一下cefsimple步骤:

[cpp]  view plain  copy
  1. // Entry point function for all processes.  
  2. int APIENTRY wWinMain(HINSTANCE hInstance,  
  3.                       HINSTANCE hPrevInstance,  
  4.                       LPTSTR    lpCmdLine,  
  5.                       int       nCmdShow) {  
  6.   UNREFERENCED_PARAMETER(hPrevInstance);  
  7.   UNREFERENCED_PARAMETER(lpCmdLine);  
  8.   
  9.   // Enable High-DPI support on Windows 7 or newer.  
  10.   CefEnableHighDPISupport();  
  11.   
  12.   void* sandbox_info = NULL;  
  13.   
  14. #if defined(CEF_USE_SANDBOX)  
  15.   // Manage the life span of the sandbox information object. This is necessary  
  16.   // for sandbox support on Windows. See cef_sandbox_win.h for complete details.  
  17.   CefScopedSandboxInfo scoped_sandbox;  
  18.   sandbox_info = scoped_sandbox.sandbox_info();  
  19. #endif  
  20.   
  21.   // Provide CEF with command-line arguments.  
  22.   CefMainArgs main_args(hInstance);  
  23.   
  24.   
  25.   // CEF applications have multiple sub-processes (render, plugin, GPU, etc)  
  26.   // that share the same executable. This function checks the command-line and,  
  27.   // if this is a sub-process, executes the appropriate logic.  
  28.   int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info);  
  29.   if (exit_code >= 0) {  
  30.     // The sub-process has completed so return here.  
  31.     return exit_code;  
  32.   }  
  33.   
  34.   // Specify CEF global settings here.  
  35.   CefSettings settings;  
  36.   
  37. #if !defined(CEF_USE_SANDBOX)  
  38.   settings.no_sandbox = true;  
  39. #endif  
  40.   // SimpleApp implements application-level callbacks for the browser process.  
  41.   // It will create the first browser instance in OnContextInitialized() after  
  42.   // CEF has initialized.  
  43.   CefRefPtr<SimpleApp> app(new SimpleApp);  
  44.   
  45.   // Initialize CEF.  
  46.   CefInitialize(main_args, settings, app.get(), sandbox_info);  
  47.   
  48.   // Run the CEF message loop. This will block until CefQuitMessageLoop() is  
  49.   // called.  
  50.   CefRunMessageLoop();  
  51.   
  52.   // Shut down CEF.  
  53.   CefShutdown();  
  54.   
  55.   return 0;  
  56. }  

综合以上代码,我们可以得出一下步骤(可要可不要的非关键步骤我们就略过了):

(1)CefExecuteProcess,根据英文解释是,CEF是多进程的,包括其他子进程如render、plugin、GPU等等,改函数检查命令行如果为子进程直接返回了。所以作用仅仅限于检查命令行参数是否是子进程,那么对于主进程browser来说可要可不要改步骤;

(2)CefInitialize,也就是cef初始化过程,这个肯定是必须的步骤,根据cef设置和对应初始化的APP来进程初始化,这里我要说明的事app,我们仔细观察app的代码

[cpp]  view plain  copy
  1. // Implement application-level callbacks for the browser process.  
  2. class SimpleApp : public CefApp,  
  3.                   public CefBrowserProcessHandler {  
  4.  public:  
  5.   SimpleApp();  
  6.   
  7.   // CefApp methods:  
  8.   virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()  
  9.       OVERRIDE { return this; }  
  10.   
  11.   // CefBrowserProcessHandler methods:  
  12.   virtual void OnContextInitialized() OVERRIDE;  
  13.   
  14.  private:  
  15.   // Include the default reference counting implementation.  
  16.   IMPLEMENT_REFCOUNTING(SimpleApp);  
  17. };  
  18.   
  19. #endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_   
我们发现,这个app就是实现了两个方法,一个就是获取浏览器进程处理器,一个就是处理上下文初始化事件,在上下文初始化事件中将浏览器创建出来,所以这个步骤的app我们可以自己创建对应app并实现该方法,但是在mfc中这个app就没什么必要的,OnContextInitialized无非就是窗口初始化前我们要做的,所以我们直接不用实现app,传递NULL即可(这是我自己测试得到的,或者实现但是OnContextInitialized里面为空,不进行任何实现),至于初始化我们直接在mfc主窗口中OnInitDialog做就行(也就是浏览器的创建)。当然我们初始化做的工作就是创建浏览器:
[cpp]  view plain  copy
  1. // SimpleHandler implements browser-level callbacks.  
  2. CefRefPtr<SimpleHandler> handler(new SimpleHandler(false));  
  3.   
  4. // Specify CEF browser settings here.  
  5. CefBrowserSettings browser_settings;  
  6.   
  7. std::string url = "http://www.baidu.com";  
  8.   
  9. CefWindowInfo window_info;  
  10.   
  11. #if defined(OS_WIN)  
  12. // On Windows we need to specify certain flags that will be passed to  
  13. // CreateWindowEx().  
  14. window_info.SetAsPopup(NULL, "cefsimple");  
  15. #endif  
  16.   
  17. // Create the first browser window.  
  18. CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings,NULL);  
注意观察,这段初始化代码我们要在OnInitDialog中必须做的,那么我们是不是直接拷贝过去就可以了?答案是否定的,因为Demon中给的是自己创建窗口的,那么在MFC中,我们如何让自己的窗口显示对应的网页,也就是让自己的窗口创建浏览器内核(换句话说浏览器作为MFC窗口的子窗口或子控件)?所以我们改动的地方就是将cef窗口作为mfc主窗口的子窗口!!看红色区域cef自己定义的窗口就是CefWindow对象,红色方法SetAsPopup就是设置为popup弹出样式窗口,并且给定了标题,根据这个方法我们可以知道既然能将窗口设置为Popup的弹出窗口,那么肯定有设置为子窗口样式的方法,果不其然,我们跟进去就知道它还有另一个方法:SetAsChild,设置为某窗口的子窗口,并告知将cef窗口放置到主窗口的那个位置(位置相对于桌面而言的windowRect区域),也就是我们在OnInitDialog中改造SetAsPopup方法为SetAsChild方法即可达到内嵌到我们窗口的目的!!
(3)CefRunMessageLoop,顾名思义就是启动消息循环,mfc其实就是win32的封装,在theapp过程中就已经启动了自己的消息循环,cef定义这套接口,目的无非就是考虑后续windows以及linux等系统的兼容性,因为我们这里已经有了自己消息循环,所以cef的这个实现就没必要了(windows下的消息循环肯定都是一样的),同样我们就没必要停止消息循环了,因为MFC做了,也就是退出的时候没有必要调用CefQuitMessageLoop这个接口了。
(4)CefShutdown,就是cef的关闭以及资源释放,这个肯定是要做的,而且是必须的,我们在MFC中只要在Dialog关闭或销毁的时候调用CefShutdown即可释放cef内核资源;

根据以上分析,我们主要做的步骤就是:
(1)CefInitialize
(2)在OnitDialog中调用以上修正后的创建浏览器方法
好以下根据我们步骤一步一步学习在MFC中如何使用CEF内核:
(1)创建工程,工程名为Cef_Demon,基于Dialog,静态使用MFC



(2)去掉关于对话框和系统菜单(我的习惯,不喜欢这两个经常没用的功能),然后点击完成


3删除所有按钮,拖入一个Edit编辑框和一个按钮和一个Picture并设置为Rectangle类型,背景为白色,运行Demon如下,对应控件IDC_EDIT_URL,ID_BUTTON_GO,ID_STATIC_BODY,分别代表编辑框、按钮以及图像控件,其中图像控件引入的目的就是将浏览器控件放置到图像控件的位置,仅仅起占位的作用。


注意,这里PIC控件属性visible是隐藏的,仅仅是用其位置;

(4)接着就是关键的步骤了,那就是引入cef库,我的cef库在e盘,首先引用头文件。为了其他项目能够使用,我直接在vs2008菜单中的“工具-->选项”弹出的对话框中设置对应的VC++目录为libcef所在的目录,如下:

5然后引入cef对应的lib库,这里我遇到一个问题,我们用的是Debug,运行库也是MTD的,按照常理讲Debug的使用libcef对应的Debug(运行库也是MTD的),Release下编译就使用libcef中Release对应的libcef.lib和对应的libcef_dll_wrapper.lib即可(Release运行库也是MT的),这样才能对应,但是我试了,引入后编译没有问题,但是跑起来就报错,错误就是定位在CefInitialize中,所以看来是有问题,那么怎么办呢? 既然如此为了防止编译错误,Debug下我们依然用libcef下Debug中的lib,但是实际的dll库我们依然用libcef下Release中的Dll,这样我们编译和运行都没有问题!!(补充说明一下,这个说法我后来验证了是错误的,而是因为我第一次没有将libcef中的Resources目录下的所有需要的资源拷贝到我的cef_demon中导致的错误!!

 所以按照这个想法,我们将libcef下的Debug目录的以及libcef_dll_wrapper\Debug下的lib



拷贝到cef_demon下我们的源码目录:


(6)将Release或Debug下的Dll以及Resources下的所有资源文件全部拷贝到cef_demon的Debug目录下(原因就是刚才说的)



注意资源文件不可或缺!否则运行不起来!CefInitialize会报错!

(7)在cef_demon中使用cef,包含头文件和lib库,编译确定是包含使用libcef没有问题;


编译结果:


(8)按照分析的步骤编写浏览器并嵌入到我们的MFC主窗口中,首先就是在cef_demon.cpp的InitInstance中初始化cef,代码如下


初始化cef主参数和对应浏览器全局设置,全局设置为no_sanbox为真(具体含义自己百度一下),使用多线程消息循环(刚说了是多线程的),初始化得时候可以使用cef app,以便在cef初始化完成后回调通知(OnContextInitialized)通知您,但是你可以在通知你的函数中实现为空或者直接传递cefInitialize第三个参数为NULL,这里我试过,是不影响的,为了全面,我这里实现了一个CCefBrowserApp继承自CefApp,因为是browser进程,所以我也继承了CefBrowserProcessHandle(browser进程处理器,如果是Render你可以继承Render process处理器,捕获对应消息),对应的app实现如下:



代码:

[cpp]  view plain  copy
  1. #pragma once  
  2.   
  3. class CCefBrowserApp : public CefApp, public CefBrowserProcessHandler  
  4. //, public CefRenderProcessHandler  
  5.     {  
  6.     public:  
  7.     CCefBrowserApp(void);  
  8.     virtual ~CCefBrowserApp(void);  
  9.   
  10.     public:  
  11.     virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE;  
  12.   
  13.     public:  
  14.     virtual void OnContextInitialized();  
  15.   
  16.     protected:  
  17.     IMPLEMENT_REFCOUNTING(CCefBrowserApp);  
  18.     };  
  19.   
  20.     #include "StdAfx.h"  
  21.     #include "CefBrowserApp.h"  
  22.     CCefBrowserApp::CCefBrowserApp(void)  
  23.     {  
  24.     }  
  25.     CCefBrowserApp::~CCefBrowserApp(void)  
  26.     {  
  27.     }  
  28.     CefRefPtr<CefBrowserProcessHandler> CCefBrowserApp::GetBrowserProcessHandler() OVERRIDE  
  29.     {  
  30.     return this;  
  31.     }  
  32.     void CCefBrowserApp::OnContextInitialized()  
  33.     {  
  34.     // do nothing here, because we will create browser in my own dialog  
  35.     }  
    (9)调试运行发现cef初始化完成后掉调用到OnContextInitialized方法中,这里我们什么都没有实现,因为我们将实现(浏览器创建)放到了DlgCef_Demon中的OnInitDialog中了,具体代码如下:

[cpp]  view plain  copy
  1. BOOL CCef_DemonDlg::OnInitDialog()  
  2.    {  
  3.    CDialog::OnInitDialog();  
  4.    SetIcon(m_hIcon, TRUE);// 设置大图标  
  5.    SetIcon(m_hIcon, FALSE);// 设置小图标  
  6.    // position here  
  7.    CRect rtBody;  
  8.    GetDlgItem(IDC_STATIC_BODY)->GetWindowRect(&rtBody);  
  9.    CefWindowInfo cefWindowInfo;  
  10.    cefWindowInfo.SetAsChild(GetSafeHwnd(), rtBody);  
  11.    CefBrowserSettings browserSetting;  
  12.    CefRefPtr<CCefBrowserEventHandler> objEventHandler(new CCefBrowserEventHandler());  
  13.    CefBrowserHost::CreateBrowser(cefWindowInfo, objEventHandler.get(), _T("http://www.baidu.com"), browserSetting, NULL);  
  14.    return TRUE;   
  15.    }   
           这里注意,CreateBrowser创建浏览器对象的时候,第二个参数必须为原始指针,不是引用计数对象,否则导致CPU到达100%,这个应该与其内部实现有关,具体参数含义如下:
    1、窗口信息描述了要创建的浏览器的窗口样式信息,这里设置窗口信息为child子窗口,父窗口为我的Dialog,且将创建的浏览器窗口位置放置到pic控件位置
    2、第二个参数为事件处理对象,这里所有的处理了所有浏览器对象的所有事件,包括 : public CefClient
    , public CefDisplayHandler// 显示变化事件
    , public CefLoadHandler   // 加载错误事件
    , public CefLifeSpanHandler   // 声明周期事件
    //, public CefContextMenuHandler// 上下文菜单事件
    //, public CefDialogHandler// 对话框事件
    //, public CefDownloadHandler// 下载事件
    //, public CefDragHandler// 拖拽事件
    //, public CefFindHandler// 查找事件
    等等事件,需要处理对应子浏览器事件都可以添加对应事件的处理器,我们只实现了显示事件、加载事件、声明周期事件;
    3、第三个参数表示加载的URL是什么
    4、第四个加载URL对应的请求参数数据
    具体的Handler实现如下:

[cpp]  view plain  copy
  1. #pragma once  
  2. #include <list>  
  3. using namespace std;  
  4.   
  5. typedef std::list<CefRefPtr<CefBrowser>> BrowserList;  
  6. class CCefBrowserEventHandler  
  7. public CefClient  
  8. public CefDisplayHandler// 显示变化事件  
  9. public CefLoadHandler   // 加载错误事件  
  10. public CefLifeSpanHandler   // 声明周期事件  
  11. //, public CefContextMenuHandler// 上下文菜单事件  
  12. //, public CefDialogHandler// 对话框事件  
  13. //, public CefDownloadHandler// 下载事件  
  14. //, public CefDragHandler// 拖拽事件  
  15. //, public CefFindHandler// 查找事件  
  16. //, public ...  
  17. {  
  18. public:  
  19. CCefBrowserEventHandler(void);  
  20. virtual ~CCefBrowserEventHandler(void);  
  21. public:  
  22. // CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器  
  23. virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE;  
  24. virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE;  
  25. virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE;  
  26.   
  27. public:   
  28. // display handler method  
  29. virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE;  
  30.   
  31. public:  
  32. // load handler method  
  33. virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE;  
  34.   
  35. public:  
  36. // display handler meethod  
  37. virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;  
  38. virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;  
  39. virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;  
  40. public:  
  41. // own method of cef browser event handler  
  42. void CloseAllBrowser(bool bForceClose = true);  
  43. protected:  
  44. BrowserList m_browser_list;  
  45.   
  46. IMPLEMENT_REFCOUNTING(CCefBrowserEventHandler);  
  47. };  
  48.   
  49. #include "StdAfx.h"  
  50. #include "CefBrowserEventHandler.h"  
  51. #include <sstream>  
  52. #include <string>  
  53. #include "include/base/cef_bind.h"  
  54. #include "include/views/cef_browser_view.h"  
  55. #include "include/views/cef_window.h"  
  56. #include "include/wrapper/cef_closure_task.h"  
  57. #include "include/wrapper/cef_helpers.h"  
  58.   
  59. CCefBrowserEventHandler::CCefBrowserEventHandler(void)  
  60. {  
  61. }  
  62.   
  63. CCefBrowserEventHandler::~CCefBrowserEventHandler(void)  
  64. {  
  65. }  
  66.   
  67. CefRefPtr<CefDisplayHandler> CCefBrowserEventHandler::GetDisplayHandler() OVERRIDE  
  68. {  
  69. return this;  
  70. }  
  71.   
  72. CefRefPtr<CefLifeSpanHandler> CCefBrowserEventHandler::GetLifeSpanHandler() OVERRIDE  
  73. {  
  74. return this;  
  75. }  
  76.   
  77. CefRefPtr<CefLoadHandler> CCefBrowserEventHandler::GetLoadHandler() OVERRIDE  
  78. {  
  79. return this;  
  80. }  
  81.   
  82. void CCefBrowserEventHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE  
  83. {  
  84. CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();  
  85. if (GetParent(hwnd) == AfxGetApp()->m_pMainWnd->GetSafeHwnd())  
  86. {  
  87. AfxGetApp()->m_pMainWnd->SetWindowText(std::wstring(title).c_str());  
  88. }  
  89. else  
  90. {  
  91. ::SetWindowText(hwnd, std::wstring(title).c_str());  
  92. }  
  93. }  
  94.   
  95. void CCefBrowserEventHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode,   
  96.  const CefString& errorText, const CefString& failedUrl) OVERRIDE  
  97. {  
  98. CEF_REQUIRE_UI_THREAD();  
  99. if (ERR_ABORTED == errorCode)  
  100. return ;  
  101.   
  102. std::stringstream ss;  
  103. ss << "<html><body bgcolor=\"white\">"  
  104. "<h2>Failed to load URL " << std::string(failedUrl) <<  
  105. " with error " << std::string(errorText) << " (" << errorCode <<  
  106. ").</h2></body></html>";  
  107. frame->LoadString(ss.str(), failedUrl);  
  108. }  
  109.   
  110. void CCefBrowserEventHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE  
  111. {  
  112. CEF_REQUIRE_UI_THREAD();  
  113. m_browser_list.push_back(browser);  
  114. }  
  115.   
  116. bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE  
  117. {  
  118. CEF_REQUIRE_UI_THREAD();  
  119. if (1 == m_browser_list.size())  
  120. {  
  121. }  
  122. return false;  
  123. }  
  124.   
  125. void CCefBrowserEventHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE  
  126. {  
  127. CEF_REQUIRE_UI_THREAD();  
  128. for (BrowserList::iterator bit = m_browser_list.begin(); bit != m_browser_list.end(); ++bit)   
  129. {  
  130. if ((*bit)->IsSame(browser)) {  
  131. m_browser_list.erase(bit);  
  132. break;  
  133. }  
  134. }  
  135.   
  136. if (m_browser_list.empty())   
  137. {  
  138. CefQuitMessageLoop();  
  139. }  
  140. }  
  141.   
  142. void CCefBrowserEventHandler::CloseAllBrowser(bool force_close)   
  143. {  
  144. if (!CefCurrentlyOn(TID_UI))   
  145. {  
  146. CefPostTask(TID_UI,base::Bind(&CCefBrowserEventHandler::CloseAllBrowser, this, force_close));  
  147. return;  
  148. }  
  149.   
  150. if (m_browser_list.empty())  
  151. return;  
  152.   
  153. BrowserList::const_iterator it = m_browser_list.begin();  
  154. for (; it != m_browser_list.end(); ++it)  
  155. {  
  156. (*it)->GetHost()->CloseBrowser(force_close);  
  157. }  
  158. }  
(10)关闭主窗口时,关闭浏览器
[cpp]  view plain  copy
  1. void CCef_DemonDlg::OnDestroy()  
  2. {  
  3. CDialog::OnDestroy();  
  4. CefShutdown();  
  5. }  
(11)运行效果


(12)实现代码示例
    Demon示例代码:http://download.csdn.net/detail/lixiang987654321/9597481
    相关的libCEf库: http://pan.baidu.com/s/1dFG5v0l



这篇关于MFC嵌入CEF的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/773371

相关文章

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

MFC中Spin Control控件使用,同时数据在Edit Control中显示

实现mfc spin control 上下滚动,只需捕捉spin control 的 UDN_DELTAPOD 消息,如下:  OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult) {  LPNMUPDOWN pNMUpDown = reinterpret_cast(pNMHDR);  // TODO: 在此添加控件通知处理程序代码    if

控制台和MFC中内存泄露工具vld的使用

最近想检测下项目中内存泄露的情况,选中了vld这款。在查找使用方法的时候,大都是控制台下的示例,添加到main函数所在的源文件上。换成MFC就纠结了,不知道添加到哪里去。本文记录控制台和MFC中的使用vld过程。    vld资源:    1)、大家可以移步下边的网址下载:     http://vld.codeplex.com/releases/view/82311    2

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

PNG透明背景按钮的实现(MFC)

问题描述: 当前要在对话框上添加一个以两个PNG图片作为背景的按钮,PNG图的背景是透明的,按钮也要做出相同的透明效果。并且鼠标不在按钮上时,按钮显示"bg1.png";鼠标移动到按钮上时,按钮显示"bg2.png" 开发环境为VS2010。 解决办法: 使用GDI+库装载PNG图片,并使用MFC Button Control和CMFCButton类结合,调用CMFCButton

MFC 控件重绘(2) NM_CUSTOMDRAW, WM_DRAWITEM, 虚函数DrawItem

控件重绘有三种方法: 1 设定界面属性 2 利用Windows的消息机制,通过Windows消息映射(Message Mapping)和反映射(Message Reflecting),在合适的时机修改控件的状态和行为。此方式涉及NM_CUSTOMDRAW和WM_DRAWITEM 3 利用虚函数机制,重载虚函数。即DrawItem虚函数。 对于NM_CUSTOMDRAW,某些支持此消息的控件

几种MFC对话框的隐藏方法

修改CXXAPP中的InitInstance函数,将原来的模态对话框改为非模态对话框,及修改 [cpp]  view plain copy INT_PTR nResponse = dlg.DoModal();     为 [cpp]  view plain copy dlg.Create(CModalHideDlg::IDD);

Base64编码 及 在HTML中用Base编码直接显示图片或嵌入其他文件类型

1.为什么要用到BASE64编码的图片信息      Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。Base64 主要不是加密,它主要的用途是把一些二进制数转成普通字符用于网络传输。由于一些二进制字符在传输协议中属于控制字符,不能直接传送需要转换一下。最常见的用途是作为电子邮件或WebService附件的传输编码.  2.base64编码定义    目前的internet

专业远程控制SDK嵌入,贝锐向日葵助力保利物业实现智能设备运维

为了实现更高质量的物业服务,很多物业企业在社区一线部署了大量的数字化自助式终端设备。这些设备可以为居民提供自助式的基础物业服务,有效提升了服务效率,居民满意度也得以提高。 一方面,物业企业通过引入此类设备,也逐步开始数字化转型,进而实现管理体系的迭代和降本增效;另一方面,面对数量多,分布广的智能设备,也需要企业构建对应的专业远程运维和技术支持体系,对其实施有效的管理,同时在用户自助使用出现问

MFC首先要知道的--程序执行顺序

MFC的程序执行顺序 很多刚学MFC的人都会被MFC给弄的晕头转向。以前传统的C语言中的main()不见了,window sdk api 中的WinMain()函数也不见了,到底用MFC编写的程序是如何开始运行的呢?到底MFC有没有遵从最基本的C++的标准呢?到底MFC的代码运行的顺序又是怎么样的呢?那么多个文件,那么多函数,到底哪一个先运行,哪一个后运行,哪一个调用哪一个,哪一个又被哪一个调用