1 前言
1.1 CEF的作用
1.2 CEF的下載和編譯
1.3 CEF結構
1.3.1 CEF進程和窗口之間的結構關系
1.3.2 Renderer進程的實現結構
1.3.3 browser進程的實現結構
1.4 CEF多進程和多線程
1.4.1 進程
1.4.2 線程
1.5 網頁嵌入應用程序結構
1.5.1 入口函數
1.5.2 CEF單實例進程
1.5.3 主子進程的模式
1.6 CefBrowser 瀏覽器窗口類
1.7 CefBrowserHost瀏覽器操作控制類
1.8 CefFrame網頁界面類
1.9 CefApp應用程序類
1.10 CEF引用計數
1.11 CEF自定義字符串
1.11.1 為什么自定義字符串類型
1.11.2 字符串操作函數CefString
1.11.3 CEF與String的轉換
前言
1.1 CEF的作用
CEF全稱Chromium Embedded Framework,是一個基於Google Chromium 的開源項目。Google Chromium項目主要是為Google Chrome應用開發的,而CEF的目標則是為第三方應用提供可嵌入瀏覽器支持。CEF作用是在客戶端嵌入網頁界面。
- 嵌入一個兼容HTML5的瀏覽器控件到一個已經存在的本地應用。
- 創建一個輕量化的殼瀏覽器,用以托管主要用Web技術開發的應用。
- 有些應用有獨立的繪制框架,使用CEF對Web內容做離線渲染。
- 使用CEF做自動化Web測試。
1.2 CEF的下載和編譯
https://blog.csdn.net/csdnyonghu123/article/details/87982333
如圖所示,CefClient工程是一個簡單版的網頁瀏覽器demo,有網址輸入、前進后退等。
CefSimple更簡單的網頁工程,網址在代碼設置,打開 直接渲染網頁。
CefTest測試工程。
AllBuild是一個偽工程,用來執行編譯其他工程。
libcef_dll_wrapper是cef的動態庫工程,。
include是頭文件
Release文件夾包含輸出的庫文件和依賴庫文件,自己開發項目時將include和release文件復制到工程即可。參考CefSimple和CefClient代碼實例。
1.3 CEF結構
1.3.1 CEF進程和窗口之間的結構關系
一個瀏覽器有很多個CefBrowser窗口,這些窗口都是在Browser進程中創建。browser進程用來管理和處理回調函數消息。
Renderer進程用來實現網頁的渲染,每個renderer進程包含有一個主網頁mainframe和多個子網頁subframe,。
1.3.2 Renderer進程的實現結構
renderer程序繼承CefApp和CefRenderProcessHandler類,在main函數中初始化。通過CefSettings.browser_subprocess_path配置render可執行程序路徑。browser進程就會去啟動這個進程去渲染網頁。
1.3.3 browser進程的實現結構
browserapp要繼承CefApp和CefBrowserProcessHandler類。實現browserapp的定義。同時要新建clienthandler類實現圖中的回調函數接口類,用來處理攔截響應請求、管理生命周期、下載、顯示加載、右鍵菜單等。在mian函數中初始化、啟動消息循環。調用CefBrowserHost的靜態方法創建browser窗口對象,在render進程的Frame中加載渲染內容。
1.4 CEF多進程和多線程
1.4.1 進程
CEF3是多進程架構的,CEF3進程主要有一個Browser(瀏覽器)進程和多個Renderer(渲染)進程。Browser被定義為主進程,負責窗口管理,網絡請求,網頁管理 、網絡交互。browser從服務器器請求到了響應,將html文本發送給Renderer 進程,render進程加載html,進行渲染,展示網頁的內容;除此之外,Renderer進程還負責Js Binding和對Dom節點的訪問。Browser和Renderer進程可以通過發送異步消息進行雙向通信。主應用程序很大,加載時間比較長,或者不能在非瀏覽器進程里使用,則宿主程序可使用獨立的可執行文件去運行這些Renderer進程。這可以通過配置CefSettings.browser_subprocess_path變量做到。
1.4.2 線程
Browser進程中包含如下主要的線程:
- TID_UI 線程是瀏覽器的主線程。如果應用程序在調用調用CefInitialize()時,傳遞CefSettings.multi_threaded_message_loop=false,這個線程也是應用程序的主線程。
- TID_IO 線程主要負責處理IPC消息以及網絡通信。
- TID_FILE 線程負責與文件系統交互。
1.5 網頁嵌入應用程序代碼構成和實例
每個CEF3應用程序都是相同的結構
- 提供入口函數,用於初始化CEF、運行子進程執行邏輯或者CEF消息循環。
- 提供CefApp實現,用於處理進程相關的回調。
- 提供CefClient實現,用於處理Browser實例相關的回調。
- 執行CefBrowserHost::CreateBrowser()創建一個Browser實例,使用CefLifeSpanHandler管理Browser對象生命周期。
1.5.1 入口函數
需要在程序的入口函數執行cef對象創建,初始化,命令行參數解析,CEF屬性設置,和CEF消息循環開啟等。CEF需要啟動一個主進程來管理網頁見面。這個主進程就是在man函數中啟動,進入消息循環,直到程序結束,才退出main函數。
1.5.2 CEF單實例進程
單例進程模式就是CEF的啟動,網頁的打開都在
int main(int argc, char* argv[]) {
// Structure for passing command-line arguments.
// The definition of this structure is platform-specific.
CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface.
CefRefPtr<MyApp> app(new MyApp);
// Execute the sub-process logic, if any. This will either return immediately for the browser
// process or block until the sub-process should exit.
int exit_code = CefExecuteProcess(main_args, app.get());
if (exit_code >= 0) {
// The sub-process terminated, exit now.
return exit_code;
}
// Populate this structure to customize CEF behavior.
CefSettings settings;
// Initialize CEF in the main process.
CefInitialize(main_args, settings, app.get());
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
CefRunMessageLoop();
// Shut down CEF.
CefShutdown();
return 0;
}
1.5.3 主子進程的模式
主進程和子進程分開的模式,主進程運行browser進程,網頁加載放在子進程render進程中。這是需要創建兩個進程和兩個主函數。
主程序的入口函數:
// Program entry-point function.
// 程序入口函數
int main(int argc, char* argv[]) {
// Structure for passing command-line arguments.
// The definition of this structure is platform-specific.
// 傳遞命令行參數的結構體。
// 這個結構體的定義與平台相關。
CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface.
// 可選擇性地實現CefApp接口
CefRefPtr<MyApp> app(new MyApp);
// Populate this structure to customize CEF behavior.
// 填充這個結構體,用於定制CEF的行為。
CefSettings settings;
// Specify the path for the sub-process executable.
// 指定子進程的執行路徑
CefString(&settings.browser_subprocess_path).FromASCII(“/path/to/subprocess”);
// Initialize CEF in the main process.
// 在主進程中初始化CEF
CefInitialize(main_args, settings, app.get());
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
// 執行消息循環,此時會堵塞,直到CefQuitMessageLoop()函數被調用。
CefRunMessageLoop();
// Shut down CEF.
// 關閉CEF
CefShutdown();
return 0;
}
子進程程序的入口函數:
// Program entry-point function.
// 程序入口函數
int main(int argc, char* argv[]) {
// Structure for passing command-line arguments.
// The definition of this structure is platform-specific.
// 傳遞命令行參數的結構體。
// 這個結構體的定義與平台相關。
CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface.
// 可選擇性地實現CefApp接口
CefRefPtr<MyApp> app(new MyApp);
// Execute the sub-process logic. This will block until the sub-process should exit.
// 執行子進程邏輯,此時會堵塞直到子進程退出。
return CefExecuteProcess(main_args, app.get());
}
1.6 CefBrowser 瀏覽器窗口類
CefBrowser是瀏覽器窗口類,相當於瀏覽器的外殼框架窗口,包含向前、向后、加載、獲取內部frame的等方法。調用CefBrowserHost的靜態方法創建一個CefBrowser對象,表示一個網頁窗口。
///
// Class used to represent a browser window. When used in the browser process
// the methods of this class may be called on any thread unless otherwise
// indicated in the comments. When used in the render process the methods of
// this class may only be called on the main thread.
///
/*--cef(source=library)--*/
class CefBrowser : public virtual CefBaseRefCounted {
public:
///
// Returns the browser host object. This method can only be called in the
// browser process.
///
/*--cef()--*/
virtual CefRefPtr<CefBrowserHost> GetHost() = 0;
///
// Returns true if the browser can navigate backwards.
///
/*--cef()--*/
virtual bool CanGoBack() = 0;
///
// Navigate backwards.
///
/*--cef()--*/
virtual void GoBack() = 0;
///
// Returns true if the browser can navigate forwards.
///
/*--cef()--*/
virtual bool CanGoForward() = 0;
///
// Navigate forwards.
///
/*--cef()--*/
virtual void GoForward() = 0;
///
// Returns true if the browser is currently loading.
///
/*--cef()--*/
virtual bool IsLoading() = 0;
///
// Reload the current page.
///
/*--cef()--*/
virtual void Reload() = 0;
///
// Reload the current page ignoring any cached data.
///
/*--cef()--*/
virtual void ReloadIgnoreCache() = 0;
///
// Stop loading the page.
///
/*--cef()--*/
virtual void StopLoad() = 0;
///
// Returns the globally unique identifier for this browser. This value is also
// used as the tabId for extension APIs.
///
/*--cef()--*/
virtual int GetIdentifier() = 0;
///
// Returns true if this object is pointing to the same handle as |that|
// object.
///
/*--cef()--*/
virtual bool IsSame(CefRefPtr<CefBrowser> that) = 0;
///
// Returns true if the window is a popup window.
///
/*--cef()--*/
virtual bool IsPopup() = 0;
///
// Returns true if a document has been loaded in the browser.
///
/*--cef()--*/
virtual bool HasDocument() = 0;
///
// Returns the main (top-level) frame for the browser window.
///
/*--cef()--*/
virtual CefRefPtr<CefFrame> GetMainFrame() = 0;
///
// Returns the focused frame for the browser window.
///
/*--cef()--*/
virtual CefRefPtr<CefFrame> GetFocusedFrame() = 0;
///
// Returns the frame with the specified identifier, or NULL if not found.
///
/*--cef(capi_name=get_frame_byident)--*/
virtual CefRefPtr<CefFrame> GetFrame(int64 identifier) = 0;
///
// Returns the frame with the specified name, or NULL if not found.
///
/*--cef(optional_param=name)--*/
virtual CefRefPtr<CefFrame> GetFrame(const CefString& name) = 0;
///
// Returns the number of frames that currently exist.
///
/*--cef()--*/
virtual size_t GetFrameCount() = 0;
///
// Returns the identifiers of all existing frames.
///
/*--cef(count_func=identifiers:GetFrameCount)--*/
virtual void GetFrameIdentifiers(std::vector<int64>& identifiers) = 0;
///
// Returns the names of all existing frames.
///
/*--cef()--*/
virtual void GetFrameNames(std::vector<CefString>& names) = 0;
///
// Send a message to the specified |target_process|. Returns true if the
// message was sent successfully.
///
/*--cef()--*/
virtual bool SendProcessMessage(CefProcessId target_process,
CefRefPtr<CefProcessMessage> message) = 0;
};
1.7 CefBrowserHost瀏覽器操作控制類
CefBrowserHost是CefBrowser的一個主對象,CefBrowser中有方法virtual CefRefPtr<CefBrowserHost> GetHost() = 0;返回CefBrowser的主CefBrowserHost對象。然而CefBrowser對象又是通過CefBrowserHost類的靜態方法來創建的。CefBrowserHost類包含一些CefBrowser操作方法,相當於是控制類,可以控制CefBrowser的創建、獲取、關閉;獲取打開CefBrowser窗口的窗口句柄、請求上下文(RequestContext);下載、查找、鼠標、鍵盤觸發事件、焦點控制、拖拽事件等。
class CefBrowserHost : public virtual CefBaseRefCounted {
public:
typedef cef_drag_operations_mask_t DragOperationsMask;
typedef cef_file_dialog_mode_t FileDialogMode;
typedef cef_mouse_button_type_t MouseButtonType;
typedef cef_paint_element_type_t PaintElementType;
///
// Create a new browser window using the window parameters specified by
// |windowInfo|. All values will be copied internally and the actual window
// will be created on the UI thread. If |request_context| is empty the
// global request context will be used. This method can be called on any
// browser process thread and will not block.
///
/*--cef(optional_param=client,optional_param=url,
optional_param=request_context)--*/
static bool CreateBrowser(const CefWindowInfo& windowInfo,
CefRefPtr<CefClient> client,
const CefString& url,
const CefBrowserSettings& settings,
CefRefPtr<CefRequestContext> request_context);
///
// Create a new browser window using the window parameters specified by
// |windowInfo|. If |request_context| is empty the global request context
// will be used. This method can only be called on the browser process UI
// thread.
///
/*--cef(optional_param=client,optional_param=url,
optional_param=request_context)--*/
static CefRefPtr<CefBrowser> CreateBrowserSync(
const CefWindowInfo& windowInfo,
CefRefPtr<CefClient> client,
const CefString& url,
const CefBrowserSettings& settings,
CefRefPtr<CefRequestContext> request_context);
///
// Returns the hosted browser object.
///
/*--cef()--*/
virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
///
// Request that the browser close. The JavaScript 'onbeforeunload' event will
// be fired. If |force_close| is false the event handler, if any, will be
// allowed to prompt the user and the user can optionally cancel the close.
// If |force_close| is true the prompt will not be displayed and the close
// will proceed. Results in a call to CefLifeSpanHandler::DoClose() if the
// event handler allows the close or if |force_close| is true. See
// CefLifeSpanHandler::DoClose() documentation for additional usage
// information.
///
/*--cef()--*/
virtual void CloseBrowser(bool force_close) = 0;
///
// Helper for closing a browser. Call this method from the top-level window
// close handler. Internally this calls CloseBrowser(false) if the close has
// not yet been initiated. This method returns false while the close is
// pending and true after the close has completed. See CloseBrowser() and
// CefLifeSpanHandler::DoClose() documentation for additional usage
// information. This method must be called on the browser process UI thread.
///
/*--cef()--*/
virtual bool TryCloseBrowser() = 0;
///
// Set whether the browser is focused.
///
/*--cef()--*/
virtual void SetFocus(bool focus) = 0;
///
// Retrieve the window handle for this browser. If this browser is wrapped in
// a CefBrowserView this method should be called on the browser process UI
// thread and it will return the handle for the top-level native window.
///
/*--cef()--*/
virtual CefWindowHandle GetWindowHandle() = 0;
///
// Retrieve the window handle of the browser that opened this browser. Will
// return NULL for non-popup windows or if this browser is wrapped in a
// CefBrowserView. This method can be used in combination with custom handling
// of modal windows.
///
/*--cef()--*/
virtual CefWindowHandle GetOpenerWindowHandle() = 0;
//……………………
}
1.8 CefFrame網頁界面類
每個CefBrowser窗口包含一個主CefFrame對象和若干個子Frame對象。主CefFrame相當於網頁的主界面,子CefFrame相當於主頁面的子頁面。CefFrame包含獲取網頁上的文字、HTML源碼字符串、網頁名字標題、加載的url、所屬的CefBrowser指針、V8Context等。還可以用LoadURL或LoadRequest加載頁面。
// Class used to represent a frame in the browser window. When used in the
// browser process the methods of this class may be called on any thread unless
// otherwise indicated in the comments. When used in the render process the
// methods of this class may only be called on the main thread.
///
/*--cef(source=library)--*/
class CefFrame : public virtual CefBaseRefCounted {
public:
///
// True if this object is currently attached to a valid frame.
///
/*--cef()--*/
virtual bool IsValid() = 0;
///
// Execute undo in this frame.
///
/*--cef()--*/
virtual void Undo() = 0;
///
// Execute redo in this frame.
///
/*--cef()--*/
virtual void Redo() = 0;
///
// Execute cut in this frame.
///
/*--cef()--*/
virtual void Cut() = 0;
///
// Execute copy in this frame.
///
/*--cef()--*/
virtual void Copy() = 0;
///
// Execute paste in this frame.
///
/*--cef()--*/
virtual void Paste() = 0;
///
// Execute delete in this frame.
///
/*--cef(capi_name=del)--*/
virtual void Delete() = 0;
///
// Execute select all in this frame.
///
/*--cef()--*/
virtual void SelectAll() = 0;
///
// Save this frame's HTML source to a temporary file and open it in the
// default text viewing application. This method can only be called from the
// browser process.
///
/*--cef()--*/
virtual void ViewSource() = 0;
///
// Retrieve this frame's HTML source as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual void GetSource(CefRefPtr<CefStringVisitor> visitor) = 0;
///
// Retrieve this frame's display text as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual void GetText(CefRefPtr<CefStringVisitor> visitor) = 0;
///
// Load the request represented by the |request| object.
///
/*--cef()--*/
virtual void LoadRequest(CefRefPtr<CefRequest> request) = 0;
///
// Load the specified |url|.
///
/*--cef()--*/
virtual void LoadURL(const CefString& url) = 0;
///
// Load the contents of |string_val| with the specified dummy |url|. |url|
// should have a standard scheme (for example, http scheme) or behaviors like
// link clicks and web security restrictions may not behave as expected.
///
/*--cef()--*/
virtual void LoadString(const CefString& string_val,
const CefString& url) = 0;
///
// Execute a string of JavaScript code in this frame. The |script_url|
// parameter is the URL where the script in question can be found, if any.
// The renderer may request this URL to show the developer the source of the
// error. The |start_line| parameter is the base line number to use for error
// reporting.
///
/*--cef(optional_param=script_url)--*/
virtual void ExecuteJavaScript(const CefString& code,
const CefString& script_url,
int start_line) = 0;
///
// Returns true if this is the main (top-level) frame.
///
/*--cef()--*/
virtual bool IsMain() = 0;
///
// Returns true if this is the focused frame.
///
/*--cef()--*/
virtual bool IsFocused() = 0;
///
// Returns the name for this frame. If the frame has an assigned name (for
// example, set via the iframe "name" attribute) then that value will be
// returned. Otherwise a unique name will be constructed based on the frame
// parent hierarchy. The main (top-level) frame will always have an empty name
// value.
///
/*--cef()--*/
virtual CefString GetName() = 0;
///
// Returns the globally unique identifier for this frame or < 0 if the
// underlying frame does not yet exist.
///
/*--cef()--*/
virtual int64 GetIdentifier() = 0;
///
// Returns the parent of this frame or NULL if this is the main (top-level)
// frame.
///
/*--cef()--*/
virtual CefRefPtr<CefFrame> GetParent() = 0;
///
// Returns the URL currently loaded in this frame.
///
/*--cef()--*/
virtual CefString GetURL() = 0;
///
// Returns the browser that this frame belongs to.
///
/*--cef()--*/
virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
///
// Get the V8 context associated with the frame. This method can only be
// called from the render process.
///
/*--cef()--*/
virtual CefRefPtr<CefV8Context> GetV8Context() = 0;
///
// Visit the DOM document. This method can only be called from the render
// process.
///
/*--cef()--*/
virtual void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) = 0;
};
1.9 CefApp應用程序類
CefApp是應用程序類,網頁嵌入程序都要實現這樣一個應用程序類。提供了一些簡單的接口:命令行參數修改,主題修改,獲取進程句柄等。還有很多的子類,例如SimpleApp、ClientApp等,clientapp又有很多子類ClientAppBrowser、ClientAppRenderer、ClientAppOther,表示不同的應用類型:應用程序類定義如下:
class CefApp : public virtual CefBaseRefCounted {
public:
///對命令行參數修改
// Provides an opportunity to view and/or modify command-line arguments before
// processing by CEF and Chromium. The |process_type| value will be empty for
// the browser process. Do not keep a reference to the CefCommandLine object
// passed to this method. The CefSettings.command_line_args_disabled value
// can be used to start with an empty command-line object. Any values
// specified in CefSettings that equate to command-line arguments will be set
// before this method is called. Be cautious when using this method to modify
// command-line arguments for non-browser processes as this may result in
// undefined behavior including crashes.
///
/*--cef(optional_param=process_type)--*/
virtual void OnBeforeCommandLineProcessing(
const CefString& process_type,
CefRefPtr<CefCommandLine> command_line) {}
///
// Provides an opportunity to register custom schemes. Do not keep a reference
// to the |registrar| object. This method is called on the main thread for
// each process and the registered schemes should be the same across all
// processes.
///
/*--cef()--*/注冊自定義主題
virtual void OnRegisterCustomSchemes(
CefRawPtr<CefSchemeRegistrar> registrar) {}
///
// Return the handler for resource bundle events. If
// CefSettings.pack_loading_disabled is true a handler must be returned. If no
// handler is returned resources will be loaded from pack files. This method
// is called by the browser and render processes on multiple threads.
///
/*--cef()--*/
virtual CefRefPtr<CefResourceBundleHandler> GetResourceBundleHandler() {
return NULL;
}
///
// Return the handler for functionality specific to the browser process. This
// method is called on multiple threads in the browser process.
///
/*--cef()--*/
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() {
return NULL;
}
///
// Return the handler for functionality specific to the render process. This
// method is called on the render process main thread.
///
/*--cef()--*/
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() {
return NULL;
}
};
1.10 CEF引用計數
CEF創建對象形式如CefRefPtr<SimpleApp> app(new SimpleApp);或者CefRefPtr<SimpleApp> app = new SimpleApp();創建的指針引用計數由CefRefPtr管理,CefRefPtr通過調用AddRef()和Release()方法自動管理引用計數。CefRefPtr定義如下:
using CefRefPtr = scoped_refptr<T>;
template <class T>
class scoped_refptr {
public:
typedef T element_type;
scoped_refptr() : ptr_(NULL) {}
scoped_refptr(T* p) : ptr_(p) {
if (ptr_)
ptr_->AddRef();
}
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
ptr_->AddRef();
}
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
ptr_->AddRef();
}
~scoped_refptr() {
if (ptr_)
ptr_->Release();
}
T* get() const { return ptr_; }
// Allow scoped_refptr<C> to be used in boolean expression
// and comparison operations.
operator T*() const { return ptr_; }
T* operator->() const {
assert(ptr_ != NULL);
return ptr_;
}
scoped_refptr<T>& operator=(T* p) {
// AddRef first so that self assignment should work
if (p)
p->AddRef();
T* old_ptr = ptr_;
ptr_ = p;
if (old_ptr)
old_ptr->Release();
return *this;
}
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
return *this = r.ptr_;
}
template <typename U>
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
return *this = r.get();
}
void swap(T** pp) {
T* p = ptr_;
ptr_ = *pp;
*pp = p;
}
void swap(scoped_refptr<T>& r) { swap(&r.ptr_); }
protected:
T* ptr_;
};
1.11 CEF自定義字符串
1.11.1 為什么自定義字符串類型
libcef包和宿主程序可能使用不同的運行時,對堆管理的方式也不同。所有的對象,包括字符串,需要確保和申請堆內存使用相同的運行時環境。所以需要自定義字符串類型。
1.11.2 字符串操作函數CefString
CEF提供了一批C語言的方法來操作字符串(通過#define的方式來適應不同的字符編碼)
cef_string_set 對制定的字符串變量賦值(支持深拷貝或淺拷貝)。
cef_string_clear 清空字符串。
cef_string_cmp 比較兩個字符串。
1.11.3 CEF與String的轉換
CefString支持與std::string(UTF8)、std::wstring(wide)類型的相互轉換。也可以用來包裹一個cef_string_t結構來對其進行賦值。
(1)string轉CefString
單字節
std::string str = “Some UTF8 string”;
CefString cef_str(str);
cef_str = str;
cef_str.FromString(str);
寬字節
std::wstring str = “Some wide string”;
CefString cef_str(str);
cef_str = str;
cef_str.FromWString(str);
ASCII碼
const char* cstr = “Some ASCII string”;
CefString cef_str;
cef_str.FromASCII(cstr);
(2)CefString轉string
單字節
str = cef_str;
str = cef_str.ToString();
寬字節
str = cef_str;
str = cef_str.ToWString();
自己開發了一個股票智能分析軟件,功能很強大,需要的點擊下面的鏈接獲取: