利用InjectedBundle定制自己的Webkit(二)
来源:互联网 发布:苹果软件开发工资 编辑:程序博客网 时间:2024/04/28 20:24
在上一篇利用InjectedBundle定制自己的Webkit(一)中,我们完成了一个自己的InjectedBundle,接下来我们就要在Webkit中加载我们自己的InjectedBundle。
为了测试方便先给出一个示例的InjectedBundle代码,项目名称MyInjectedBundle
#include <WebKit2/WKBundleInitialize.h>#include <WebKit2/WKBundleFrame.h>#include <Webkit2/WKBundlePage.h>#include <WebKit2/WKBundle.h>#include <Webkit2/WKUrl.h>#include <Webkit2/WKString.h>#include <windows.h>#include <string.h>#include <wchar.h>#pragma comment(lib, "WebKit.lib")// 框架加载完毕后调用void didFinishLoadForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef*, const void*){ if (WKBundleFrameIsMainFrame(frame)) // 如果是主框架 { WKURLRef url = WKBundleFrameCopyURL(frame); // 获得URL WKStringRef str = WKURLCopyString(url); // 得到URL字符串 size_t length = WKStringGetLength(str); wchar_t* urlBuffer = new wchar_t[length + 1]; size_t size = WKStringGetCharacters(str, urlBuffer, length); // 转成wchar_t* urlBuffer[length] = 0; WKRect rect = WKBundleFrameGetContentBounds(frame); // 得到边界范围 wchar_t info[1024]; swprintf(info, L"url: %s\nx=%f, y=%f, width=%f, height=%f", urlBuffer, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); // 生成结果 ::MessageBoxW(0, info, L"FrameBound", MB_OK); // 显示 delete[] urlBuffer; }}// page创建完后调用void didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void*){ WKBundlePageLoaderClient loaderClient = { 0 }; loaderClient.version = kWKBundlePageLoaderClientCurrentVersion; loaderClient.didFinishLoadForFrame = didFinishLoadForFrame; // 注册回调 WKBundlePageSetPageLoaderClient(page, &loaderClient);}extern "C" __declspec(dllexport)void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData){ WKBundleClient client = { 0 }; client.version = kWKBundleClientCurrentVersion; client.didCreatePage = didCreatePage; WKBundleSetClient(bundle, &client);}
以上InjectedBundle首先注册page创建后的回调didCreatePage,然后在page创建之后注册框架加载完毕的回调didFinishLoadForFrame,当框架加载完毕之后再获得框架的url和区域坐标显示出来。
在InjectedBundle编译生成完毕之后得到MyInjectedBundle.dll,之后我们开始写客户进程调用的代码。
创建一个空项目WebkitDemo,准备工作同InjectedBundle,不过配置类型是应用程序(.exe)
然后开始写代码
首先需要建立一个让View对象依附的Window,Window是怎样的不重要,主要是需要一个载体和消息队列,所以这里直接不显示Window了。
#include <Windows.h>#include <Webkit2/WKType.h>#include <WebKit2/WKStringCF.h>#include <Webkit2/WKString.h>#include <Webkit2/WKUrl.h>#include <Webkit2/WKView.h>#include <Webkit2/WKContext.h>#include <Webkit2/WKPage.h>#include <shlwapi.h>#include <WebKit2/WKURLCF.h>#pragma comment(lib, "Shlwapi.lib")#pragma comment(lib, "CoreFoundation.lib")#pragma comment(lib, "WebKit.lib")LRESULT CALLBACK runLoopProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam){ if (message == WM_CREATE) { createView(window); // 创建view这里之后介绍 return 0; } return ::DefWindowProc(window, message, wParam, lParam);}int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow){ MSG msg; BOOL bRet; WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = runLoopProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION); wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = L"MyWebkitToolRunLoop"; if (!RegisterClass(&wc)) return 0; HWND hwnd = ::CreateWindow(L"MyWebkitToolRunLoop", L"MyWebkitTool", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0); if (!hwnd) return 0; // 开始消息循环 while ( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if (bRet == -1) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0;}
然后在WM_CREATE事件的响应中创建view,创建view需要一个WKContextRef参数,这个参数能够指定view在什么上下文中创建,即利用哪个WebProcess进程来创建。所以我们就可以在WKContextRef中设置使用我们的InjectedBundle。
WKStringRef getBundlePath(){ const wchar_t* THIS_FILE_NAME = L"WebkitDemo.exe"; // 客户程序文件名 const wchar_t* BUNDLE_FILE_NAME = L"MyInjectedBundle.dll"; // InjectedBundle文件名 HMODULE thisModule = ::GetModuleHandleW(THIS_FILE_NAME); if (!thisModule) return 0; WCHAR pathStr[MAX_PATH]; if (!::GetModuleFileNameW(thisModule, pathStr, (DWORD)wcslen(pathStr))) // 得到客户程序文件路径 return 0; ::PathRemoveFileSpecW(pathStr); // 去掉文件名 if (!::PathAppendW(pathStr, BUNDLE_FILE_NAME)) // 加上InjectedBundle文件名 return 0; CFStringRef cf = CFStringCreateWithCharacters(0, (const UniChar*)pathStr, (CFIndex)wcslen(pathStr)); WKStringRef res = WKStringCreateWithCFString(cf); CFRelease(cf); return res;}void goToURL(const wchar_t* wcurl, WKViewRef view){ CFStringRef string = CFStringCreateWithCharacters(0, (const UniChar*)wcurl, (CFIndex)wcslen(wcurl)); CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(0, string, 0, 0, kCFStringEncodingUTF8); CFRelease(string); CFURLRef cfURL = CFURLCreateWithString(0, escapedString, 0); CFRelease(escapedString); WKURLRef url = WKURLCreateWithCFURL(cfURL); // 创建一个URL对象 CFRelease(cfURL); WKPageRef page = WKViewGetPage(view); WKPageLoadURL(page, url); // 开始加载 WKRelease(url);}void createView(HWND window){ RECT webViewRect = { 0, 0, 0, 0 }; WKStringRef path = getBundlePath(); WKContextRef context = WKContextCreateWithInjectedBundlePath(path); // 利用InjectedBundle创建context对象 WKRelease(path); WKViewRef view = WKViewCreate(webViewRect, context, 0, window); // 创建view对象 WKViewSetIsInWindow(view, true); // 这里可以用WKPageSetXXXClient注册一些回调函数 goToURL(L"http://www.baidu.com", view);}
我们需要给将WKContextCreateWithInjectedBundlePath传入bundle文件的路径,为方便我们将MyInjectedBundle.dll和客户端程序放在一起,利用getBundlePath()得到bundle文件的路径。在创建完成之后调用goToURL让Webkit加载页面,这里以百度为例。
以上代码用到了Shlwapi和CoreFoundation,所以加上头文件和链接库。
编译运行,大功告成了!
之后附上源码文件InjectedBundleDemo.zip
小小尝试,欢迎大家多提意见和建议!下一期准备为大家介绍利用定制的Webkit来爬取动态页面内容和动态生成的链接。
- 利用InjectedBundle定制自己的Webkit(二)
- 利用InjectedBundle定制自己的Webkit(一)
- 利用javadoc定制自己的接口文档(二)
- 利用javadoc定制自己的接口文档(一)
- 利用javadoc定制自己的接口文档(三)
- 利用Debian定制适合自己的系统
- 利用MJRefresh定制自己的刷新动画
- 手把手教你定制自己的RTC(二)
- 手把手教你定制自己的RTC(一)------ 利用RTC扩展点定制自己的服务
- Android 利用BaseAdapter定制属于自己的adapter
- 利用c++11,简单定制自己的线程类
- 用webparts个性化定制自己的网店风格(二)
- (2)定制自己的IntelliJ IDEA
- 定制自己的linux
- 定制自己的DataGridView
- 定制自己的Form
- 定制自己的infoTemplate
- 定制自己的launch
- 判断是否为素数
- ubuntu下计划任务cron
- Myeclipse引入schema文件
- 最字头之三:最长重复子串
- Linux常用的网络命令
- 利用InjectedBundle定制自己的Webkit(二)
- [ACM]a+b problem
- 第十一周项目二:三角形类 直线类
- GKD可以直顯示qemu的screen了
- 九段经理的带队阶梯
- 利用Webkit抓取动态网页和链接
- 转帖:C# 中的委托和事件
- FAQ:BI与BA的区别及联系
- 数据结构算法书籍推荐