I know there are a lot of articles about this on the internet, and I tried many of them. Although I can make my browser load a webpage on internet, somehow I can't manage to make it load HTML from memory.
Most of the time, the two methods below just don't have any visible effect; other times, they throw errors. Although other people say that "neither pPSI nor pHtmlDoc2 point to a valid object", I don't know if this is true. I have marked the lines that cause the error with a comment.
At the end of my question is the fully working code if you want to reproduce the problem.
Method 1
void WebBrowser::setHTML(const wchar_t *htmlSource) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;
Navigate(L"about:blank");
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
//BSTR p = 0;
//if (SUCCEEDED(hr)) hr = pHtmlDoc2->get_readyState(&p);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource); // Debbug: p_content contains HTML string
GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
{
hr = pPSI->InitNew(); //////////// <- Sometime throw error.
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}
The error:
Exception thrown at 0x51539FB1 (mshtml.dll) in Test.exe: 0xC0000005:
Access violation reading location 0x00000030
Method 2
This one is modified from this article on CodeProject. In that source, it works perfectly, but it doesn't work when I try to adapt to my code:
void WebBrowser::setHTML2(const wchar_t *htmlSource) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
this->Navigate(L"about:blank");
hr = this->webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2)
{
BSTR bstr = SysAllocString(htmlSource);
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (psaStrings)
{
VARIANT *param;
hr = SafeArrayAccessData(psaStrings, (LPVOID*)¶m);
if (SUCCEEDED(hr) && param)
{
param->vt = VT_BSTR;
param->bstrVal = bstr;
//if (SUCCEEDED(hr)) hr = SafeArrayUnaccessData(psaStrings);
if (SUCCEEDED(hr))
{
hr = pHtmlDoc2->write(psaStrings); //////////// <- Sometime throw error.
}
}
SafeArrayDestroy(psaStrings);
}
}
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}
The error:
Exception thrown at 0x51577F2E (mshtml.dll) in Test.exe: 0xC0000005:
Access violation reading location 0x000002C4
A possible third method, Loading HTML content from a Stream from Microsoft, suggests I load from the stream on a DWebBrowserEvents2::DocumentComplete event, which I have tried and failed to figure out how to implement.
Full Source Code
Below is full code. I create a new Win32 project and create/modify the following files:
Browser.h
#include <comdef.h>
#include <Exdisp.h>
#include <ExDispid.h>
#include <MsHTML.h>
#include <Mshtmhst.h>
#include <string>
#include <tchar.h>
#include <Windows.h>
using namespace std;
class WebBrowser :
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{
public:
WebBrowser(HWND hWndParent);
bool CreateBrowser();
void SetText(const wchar_t* t);
void setHTML(const wchar_t *htmlSource);
void setHTML2(const wchar_t *htmlSource);
RECT PixelToHiMetric(const RECT& _rc);
virtual void SetRect(const RECT& _rc);
// ----- Control methods -----
void GoBack();
void GoForward();
void Refresh();
void Navigate(wstring szUrl);
// ----- IUnknown -----
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void**ppvObject) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
// ---------- IOleWindow ----------
virtual HRESULT STDMETHODCALLTYPE GetWindow(
__RPC__deref_out_opt HWND *phwnd) override;
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
BOOL fEnterMode) override;
// ---------- IOleInPlaceSite ----------
virtual HRESULT STDMETHODCALLTYPE CanInPlaceActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE OnUIActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE GetWindowContext(
__RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
__RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
__RPC__out LPRECT lprcPosRect,
__RPC__out LPRECT lprcClipRect,
__RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo) override;
virtual HRESULT STDMETHODCALLTYPE Scroll(
SIZE scrollExtant) override;
virtual HRESULT STDMETHODCALLTYPE OnUIDeactivate(
BOOL fUndoable) override;
virtual HWND GetControlWindow();
virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(void) override;
virtual HRESULT STDMETHODCALLTYPE DiscardUndoState(void) override;
virtual HRESULT STDMETHODCALLTYPE DeactivateAndUndo(void) override;
virtual HRESULT STDMETHODCALLTYPE OnPosRectChange(
__RPC__in LPCRECT lprcPosRect) override;
// ---------- IOleClientSite ----------
virtual HRESULT STDMETHODCALLTYPE SaveObject(void) override;
virtual HRESULT STDMETHODCALLTYPE GetMoniker(
DWORD dwAssign,
DWORD dwWhichMoniker,
__RPC__deref_out_opt IMoniker **ppmk) override;
virtual HRESULT STDMETHODCALLTYPE GetContainer(
__RPC__deref_out_opt IOleContainer **ppContainer) override;
virtual HRESULT STDMETHODCALLTYPE ShowObject(void) override;
virtual HRESULT STDMETHODCALLTYPE OnShowWindow(
BOOL fShow) override;
virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(void) override;
// ----- IStorage -----
virtual HRESULT STDMETHODCALLTYPE CreateStream(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStream **ppstm) override;
virtual HRESULT STDMETHODCALLTYPE OpenStream(
const OLECHAR *pwcsName,
void *reserved1,
DWORD grfMode,
DWORD reserved2,
IStream **ppstm) override;
virtual HRESULT STDMETHODCALLTYPE CreateStorage(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStorage **ppstg) override;
virtual HRESULT STDMETHODCALLTYPE OpenStorage(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgPriority,
DWORD grfMode,
__RPC__deref_opt_in_opt SNB snbExclude,
DWORD reserved,
__RPC__deref_out_opt IStorage **ppstg) override;
virtual HRESULT STDMETHODCALLTYPE CopyTo(
DWORD ciidExclude,
const IID *rgiidExclude,
__RPC__in_opt SNB snbExclude,
IStorage *pstgDest) override;
virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
__RPC__in_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgDest,
__RPC__in_string const OLECHAR *pwcsNewName,
DWORD grfFlags) override;
virtual HRESULT STDMETHODCALLTYPE Commit(
DWORD grfCommitFlags) override;
virtual HRESULT STDMETHODCALLTYPE Revert(void) override;
virtual HRESULT STDMETHODCALLTYPE EnumElements(
DWORD reserved1,
void *reserved2,
DWORD reserved3,
IEnumSTATSTG **ppenum) override;
virtual HRESULT STDMETHODCALLTYPE DestroyElement(
__RPC__in_string const OLECHAR *pwcsName) override;
virtual HRESULT STDMETHODCALLTYPE RenameElement(
__RPC__in_string const OLECHAR *pwcsOldName,
__RPC__in_string const OLECHAR *pwcsNewName) override;
virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt const FILETIME *pctime,
__RPC__in_opt const FILETIME *patime,
__RPC__in_opt const FILETIME *pmtime) override;
virtual HRESULT STDMETHODCALLTYPE SetClass(
__RPC__in REFCLSID clsid) override;
virtual HRESULT STDMETHODCALLTYPE SetStateBits(
DWORD grfStateBits,
DWORD grfMask) override;
virtual HRESULT STDMETHODCALLTYPE Stat(
__RPC__out STATSTG *pstatstg,
DWORD grfStatFlag) override;
protected:
IOleObject* oleObject;
IOleInPlaceObject* oleInPlaceObject;
IWebBrowser2* webBrowser2;
LONG iComRefCount;
RECT rObject;
HWND hWndParent;
HWND hWndControl;
};
Browser.cpp
#include "stdafx.h"
#include "Browser.h"
namespace tkString
{
wchar_t* Format(const wchar_t* format, ...)
{
va_list args;
va_start(args, format);
wchar_t *w = NULL;
int len = _vsnwprintf(NULL, 0, format, args) + 1;
if (len > 0)
{
w = new wchar_t[len];
w[0] = 0;
_vsnwprintf_s(w, len, len, format, args);
}
va_end(args);
return w;
}
}
void WebBrowser::SetText(const wchar_t* t)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";
if (t)
{
wchar_t *w = tkString::Format(html, t);
setHTML(w);
//setHTML2(w);
delete[] w;
}
else this->Navigate(L"https://google.com.vn");
}
void WebBrowser::setHTML(const wchar_t *htmlSource) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;
Navigate(L"about:blank");
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
//BSTR p = 0;
//if (SUCCEEDED(hr)) hr = pHtmlDoc2->get_readyState(&p);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource);
GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}
void WebBrowser::setHTML2(const wchar_t *htmlSource) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
this->Navigate(L"about:blank");
hr = this->webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2)
{
BSTR bstr = SysAllocString(htmlSource);
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (psaStrings)
{
VARIANT *param;
hr = SafeArrayAccessData(psaStrings, (LPVOID*)¶m);
if (SUCCEEDED(hr) && param)
{
param->vt = VT_BSTR;
param->bstrVal = bstr;
//if (SUCCEEDED(hr)) hr = SafeArrayUnaccessData(psaStrings);
if (SUCCEEDED(hr)) hr = pHtmlDoc2->write(psaStrings);
}
SafeArrayDestroy(psaStrings);
}
}
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}
WebBrowser::WebBrowser(HWND _hWndParent)
{
iComRefCount = 0;
::SetRect(&rObject, 0, 0, 600, 400);
hWndParent = _hWndParent;
if (CreateBrowser() == FALSE)
{
return;
}
webBrowser2->put_Visible(TRUE);
ShowWindow(GetControlWindow(), SW_SHOW);
this->Navigate(_T("about:blank"));
}
bool WebBrowser::CreateBrowser()
{
HRESULT hr;
hr = ::OleCreate(CLSID_WebBrowser,
IID_IOleObject, OLERENDER_DRAW, 0, this, this,
(void**)&oleObject);
if (FAILED(hr))
{
MessageBox(NULL, _T("Cannot create oleObject CLSID_WebBrowser"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}
hr = oleObject->SetClientSite(this);
hr = OleSetContainedObject(oleObject, TRUE);
RECT posRect;
::SetRect(&rObject, 0, 0, 600, 400);
hr = oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE,
NULL, this, -1, hWndParent, &posRect);
if (FAILED(hr))
{
MessageBox(NULL, _T("oleObject->DoVerb() failed"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}
hr = oleObject->QueryInterface(&webBrowser2);
if (FAILED(hr))
{
MessageBox(NULL, _T("oleObject->QueryInterface(&webBrowser2) failed"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}
return TRUE;
}
RECT WebBrowser::PixelToHiMetric(const RECT& _rc)
{
static bool s_initialized = false;
static int s_pixelsPerInchX, s_pixelsPerInchY;
if (!s_initialized)
{
HDC hdc = ::GetDC(0);
s_pixelsPerInchX = ::GetDeviceCaps(hdc, LOGPIXELSX);
s_pixelsPerInchY = ::GetDeviceCaps(hdc, LOGPIXELSY);
::ReleaseDC(0, hdc);
s_initialized = true;
}
RECT rc;
rc.left = MulDiv(2540, _rc.left, s_pixelsPerInchX);
rc.top = MulDiv(2540, _rc.top, s_pixelsPerInchY);
rc.right = MulDiv(2540, _rc.right, s_pixelsPerInchX);
rc.bottom = MulDiv(2540, _rc.bottom, s_pixelsPerInchY);
return rc;
}
void WebBrowser::SetRect(const RECT& _rc)
{
rObject = _rc;
{
RECT hiMetricRect = PixelToHiMetric(rObject);
SIZEL sz;
sz.cx = hiMetricRect.right - hiMetricRect.left;
sz.cy = hiMetricRect.bottom - hiMetricRect.top;
oleObject->SetExtent(DVASPECT_CONTENT, &sz);
}
if (oleInPlaceObject != 0)
{
oleInPlaceObject->SetObjectRects(&rObject, &rObject);
}
}
// ----- Control methods -----
void WebBrowser::GoBack()
{
this->webBrowser2->GoBack();
}
void WebBrowser::GoForward()
{
this->webBrowser2->GoForward();
}
void WebBrowser::Refresh()
{
this->webBrowser2->Refresh();
}
void WebBrowser::Navigate(wstring szUrl)
{
bstr_t url(szUrl.c_str());
variant_t flags(0x02u); //navNoHistory
this->webBrowser2->Navigate(url, &flags, 0, 0, 0);
}
// ----- IUnknown -----
HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid,
void**ppvObject)
{
if (riid == __uuidof(IUnknown))
{
(*ppvObject) = static_cast<IOleClientSite*>(this);
}
else if (riid == __uuidof(IOleInPlaceSite))
{
(*ppvObject) = static_cast<IOleInPlaceSite*>(this);
}
else
{
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE WebBrowser::AddRef(void)
{
iComRefCount++;
return iComRefCount;
}
ULONG STDMETHODCALLTYPE WebBrowser::Release(void)
{
iComRefCount--;
return iComRefCount;
}
// ---------- IOleWindow ----------
HRESULT STDMETHODCALLTYPE WebBrowser::GetWindow(
__RPC__deref_out_opt HWND *phwnd)
{
(*phwnd) = hWndParent;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::ContextSensitiveHelp(
BOOL fEnterMode)
{
return E_NOTIMPL;
}
// ---------- IOleInPlaceSite ----------
HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate(void)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceActivate(void)
{
OleLockRunning(oleObject, TRUE, FALSE);
oleObject->QueryInterface(&oleInPlaceObject);
oleInPlaceObject->SetObjectRects(&rObject, &rObject);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate(void)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::GetWindowContext(
__RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
__RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
__RPC__out LPRECT lprcPosRect,
__RPC__out LPRECT lprcClipRect,
__RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
HWND hwnd = hWndParent;
(*ppFrame) = NULL;
(*ppDoc) = NULL;
(*lprcPosRect).left = rObject.left;
(*lprcPosRect).top = rObject.top;
(*lprcPosRect).right = rObject.right;
(*lprcPosRect).bottom = rObject.bottom;
*lprcClipRect = *lprcPosRect;
lpFrameInfo->fMDIApp = false;
lpFrameInfo->hwndFrame = hwnd;
lpFrameInfo->haccel = NULL;
lpFrameInfo->cAccelEntries = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(
SIZE scrollExtant)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(
BOOL fUndoable)
{
return S_OK;
}
HWND WebBrowser::GetControlWindow()
{
if (hWndControl != 0)
return hWndControl;
if (oleInPlaceObject == 0)
return 0;
oleInPlaceObject->GetWindow(&hWndControl);
return hWndControl;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceDeactivate(void)
{
hWndControl = 0;
oleInPlaceObject = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState(void)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo(void)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnPosRectChange(
__RPC__in LPCRECT lprcPosRect)
{
return E_NOTIMPL;
}
// ---------- IOleClientSite ----------
HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject(void)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::GetMoniker(
DWORD dwAssign,
DWORD dwWhichMoniker,
__RPC__deref_out_opt IMoniker **ppmk)
{
if ((dwAssign == OLEGETMONIKER_ONLYIFTHERE) &&
(dwWhichMoniker == OLEWHICHMK_CONTAINER))
return E_FAIL;
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::GetContainer(
__RPC__deref_out_opt IOleContainer **ppContainer)
{
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject(void)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(
BOOL fShow)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::RequestNewObjectLayout(void)
{
return E_NOTIMPL;
}
// ----- IStorage -----
HRESULT STDMETHODCALLTYPE WebBrowser::CreateStream(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStream **ppstm)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OpenStream(
const OLECHAR *pwcsName,
void *reserved1,
DWORD grfMode,
DWORD reserved2,
IStream **ppstm)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::CreateStorage(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStorage **ppstg)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::OpenStorage(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgPriority,
DWORD grfMode,
__RPC__deref_opt_in_opt SNB snbExclude,
DWORD reserved,
__RPC__deref_out_opt IStorage **ppstg)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::CopyTo(
DWORD ciidExclude,
const IID *rgiidExclude,
__RPC__in_opt SNB snbExclude,
IStorage *pstgDest)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::MoveElementTo(
__RPC__in_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgDest,
__RPC__in_string const OLECHAR *pwcsNewName,
DWORD grfFlags)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::Commit(
DWORD grfCommitFlags)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::Revert(void)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::EnumElements(
DWORD reserved1,
void *reserved2,
DWORD reserved3,
IEnumSTATSTG **ppenum)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::DestroyElement(
__RPC__in_string const OLECHAR *pwcsName)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::RenameElement(
__RPC__in_string const OLECHAR *pwcsOldName,
__RPC__in_string const OLECHAR *pwcsNewName)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::SetElementTimes(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt const FILETIME *pctime,
__RPC__in_opt const FILETIME *patime,
__RPC__in_opt const FILETIME *pmtime)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(
__RPC__in REFCLSID clsid)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(
DWORD grfStateBits,
DWORD grfMask)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE WebBrowser::Stat(
__RPC__out STATSTG *pstatstg,
DWORD grfStatFlag)
{
return E_NOTIMPL;
}
Win32Project1.cpp
#include "stdafx.h"
#include "Win32Project1.h"
#include "Browser.h"
HWND mainHWND;
WebBrowser* myBrowser = NULL;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
OleInitialize(NULL);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
myBrowser = new WebBrowser(mainHWND);
//myBrowser->Navigate(L"https://google.com.vn");
myBrowser->SetText(L"Hello!");
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32PROJECT1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
mainHWND = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!mainHWND)
{
return FALSE;
}
ShowWindow(mainHWND, nCmdShow);
UpdateWindow(mainHWND);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
// Removed
return (INT_PTR)FALSE;
}
Other source files created by Visual Studio remain untouched.
Question
What problem causes my program to fail to load the HTML string, and how do I fix it? Or do you have any working example (no MFC or ATL) to load an HTML string to the WebBrowser?
Note: I know I can write the HTML string to hard drive and pass the file path to the browser, but I don't want the hard disk involved at all.
Note 2: To win the bounty, please give a complete example of working code, using as much of my code as possible. The browser should load HTML string successfully. Even when it's loading an online web page, it should stop to process this new command.
Navigate(L"about:blank");
The posted source code does not demonstrate the problem well. It shows no errors, but also no "Hello". Only by omitting the Navigate() call does it get close to failing on nullptr errors. The code is simply not finished, it is missing the required plumbing to capture the DocumentComplete event. Only after this event is fired can the code inside WebBrowser::setHtml() work.
Have the WebBrowser class implement the IDispatch and IUnknown interfaces:
class WebBrowser :
public IDispatch,
public IUnknown,
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{
private:
HRESULT OnCompleted(DISPPARAMS* args);
wchar_t* htmlSource;
IConnectionPoint* callback;
DWORD eventCookie;
// etc...
};
Note how the htmlSource variable is now a class member, the string needs to be stored until the DocumentComplete event fires.
We need to implement IDispatch. That's pretty easy to do, I put the code inline:
// ---------- IDispatch ----------
HRESULT GetTypeInfoCount(UINT *pctinfo) { return E_FAIL; }
HRESULT GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; }
HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_FAIL; }
HRESULT Invoke(DISPID dispIdMember, REFIID, LCID, WORD,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO*, UINT*) {
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams);
else return S_OK;
}
QueryInterface() needs to be tweaked:
HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid, void**ppvObject)
{
if (riid == __uuidof(IUnknown)) *ppvObject = static_cast<IUnknown*>(this);
else if (riid == __uuidof(IDispatch)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IOleClientSite)) *ppvObject = static_cast<IOleClientSite*>(this);
else if (riid == __uuidof(IOleInPlaceSite)) *ppvObject = static_cast<IOleInPlaceSite*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
The constructor needs to subscribe the event interface:
WebBrowser::WebBrowser(HWND _hWndParent)
{
//...
// appended:
htmlSource = nullptr;
IConnectionPointContainer* container = nullptr;
webBrowser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container);
container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback);
IUnknown* punk = nullptr;
this->QueryInterface(IID_IUnknown, (void**)&punk);
callback->Advise(punk, &eventCookie);
punk->Release();
container->Release();
}
The setText() function becomes very simple, we're not going to worry about setHtml() at all. We'll just set the htmlSource member so we know what to do when the DocumentComplete event fires:
void WebBrowser::SetText(const wchar_t* t)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";
if (htmlSource) delete[] htmlSource;
htmlSource = tkString::Format(html, t);
this->Navigate(L"about::blank");
}
And finally the added function that runs when the DocumentComplete event fires. Most of the code got moved from setHtml:
HRESULT WebBrowser::OnCompleted(DISPPARAMS* args) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;
if (!htmlSource) return S_OK;
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource);
GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
delete[] htmlSource;
htmlSource = nullptr;
return S_OK;
}
I'll leave proper cleanup as a // todo. Running this code now produces the desired outcome:
Based on Hans Passant's answer, bellow is the full working code, for anyone want to test.
Create new Win32 project named "Win32Project1" and add/edit following files:
WebBrowser.h
#pragma once
#include <comdef.h>
#include <Exdisp.h>
#include <ExDispid.h>
#include <MsHTML.h>
#include <Mshtmhst.h>
#include <string>
#include <tchar.h>
#include <Windows.h>
class WebBrowser :
public IDispatch,
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{
public:
WebBrowser(HWND hWndParent);
void SetText(const wchar_t* t);
void setHTML(const wchar_t *htmlText, bool shouldWrapinBODYtag = true);
// ----- Create Browser -----
HRESULT RegisterGIWebBrowser();
HRESULT GetGIWebBrowser(IWebBrowser2** pwb);
bool CreateBrowser();
// ----- For Resize Window -----
RECT PixelToHiMetric(const RECT& _rc);
virtual void SetRect(const RECT& _rc);
virtual HWND GetControlWindow();
// ----- Control methods -----
void GoBack();
void GoForward();
void Refresh();
void Navigate(const wchar_t *szUrl);
// ----- IUnknown -----
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void**ppvObject) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
// ---------- IOleWindow ----------
virtual HRESULT STDMETHODCALLTYPE GetWindow(__RPC__deref_out_opt HWND *phwnd) override;
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override;
// ---------- IOleInPlaceSite ----------
virtual HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceActivate(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::GetWindowContext(__RPC__deref_out_opt IOleInPlaceFrame **ppFrame, __RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc, __RPC__out LPRECT lprcPosRect, __RPC__out LPRECT lprcClipRect, __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(SIZE scrollExtant) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(BOOL fUndoable) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnPosRectChange(__RPC__in LPCRECT lprcPosRect) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceDeactivate(void) override;
// ---------- IOleClientSite ----------
virtual HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::GetContainer(__RPC__deref_out_opt IOleContainer **ppContainer) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(BOOL fShow) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::RequestNewObjectLayout(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, __RPC__deref_out_opt IMoniker **ppmk) override;
// ----- IStorage -----
virtual HRESULT STDMETHODCALLTYPE WebBrowser::CreateStream(__RPC__in_string const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, __RPC__deref_out_opt IStream **ppstm) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::CreateStorage(__RPC__in_string const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, __RPC__deref_out_opt IStorage **ppstg) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::OpenStorage(__RPC__in_opt_string const OLECHAR *pwcsName, __RPC__in_opt IStorage *pstgPriority, DWORD grfMode, __RPC__deref_opt_in_opt SNB snbExclude, DWORD reserved, __RPC__deref_out_opt IStorage **ppstg) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, __RPC__in_opt SNB snbExclude, IStorage *pstgDest) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::MoveElementTo(__RPC__in_string const OLECHAR *pwcsName, __RPC__in_opt IStorage *pstgDest, __RPC__in_string const OLECHAR *pwcsNewName, DWORD grfFlags) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::Commit(DWORD grfCommitFlags) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::Revert(void) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::DestroyElement(__RPC__in_string const OLECHAR *pwcsName) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::RenameElement(__RPC__in_string const OLECHAR *pwcsOldName, __RPC__in_string const OLECHAR *pwcsNewName) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::SetElementTimes(__RPC__in_opt_string const OLECHAR *pwcsName, __RPC__in_opt const FILETIME *pctime, __RPC__in_opt const FILETIME *patime, __RPC__in_opt const FILETIME *pmtime) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(__RPC__in REFCLSID clsid) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(DWORD grfStateBits, DWORD grfMask) override;
virtual HRESULT STDMETHODCALLTYPE WebBrowser::Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag) override;
// ---------- IDispatch ----------
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo) override;
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, LCID, __RPC__deref_out_opt ITypeInfo **) override;
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0, 16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId) override;
virtual HRESULT STDMETHODCALLTYPE Invoke(_In_ DISPID dispIdMember, _In_ REFIID, _In_ LCID, _In_ WORD, _In_ DISPPARAMS *pDispParams, _Out_opt_ VARIANT *pVarResult, _Out_opt_ EXCEPINFO*, _Out_opt_ UINT*) override;
private:
IOleObject* oleObject;
IOleInPlaceObject* oleInPlaceObject;
IWebBrowser2* webBrowser2;
LONG iComRefCount;
RECT rObject;
HWND hWndParent;
HWND hWndControl;
HRESULT OnCompleted(DISPPARAMS* args);
wchar_t* htmlSource;
IConnectionPoint* callback;
DWORD eventCookie;
DWORD dwGIWebBrowserCookie;
bool isFullyCreated;
};
WebBrowser.cpp
#include "stdafx.h"
#include "WebBrowser.h"
namespace tkString
{
wchar_t* Format(const wchar_t* format, ...)
{
va_list args;
va_start(args, format);
wchar_t* w = NULL;
int len = _vscwprintf(format, args) + 1;
if (len > 1)
{
w = new wchar_t[len];
w[0] = 0;
_vsnwprintf_s(w, len, len, format, args);
}
va_end(args);
return w;
}
}
void WebBrowser::SetText(const wchar_t* t)
{
if (isFullyCreated)
{
// TODO: escape text
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";
if (htmlSource) delete[] htmlSource;
htmlSource = tkString::Format(html, t);
this->Navigate(L"about:blank");
}
else {}
}
void WebBrowser::setHTML(const wchar_t* htmlText, bool shouldWrapinBODYtag)
{
if (isFullyCreated)
{
if (htmlSource) delete[] htmlSource;
htmlSource = NULL;
if (shouldWrapinBODYtag)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body>%ls</body></html>";
htmlSource = tkString::Format(html, htmlText);
}
else
{
if (htmlText)
{
size_t len = wcslen(htmlText) + 1;
htmlSource = new wchar_t[len];
wmemcpy(htmlSource, htmlText, len);
}
}
this->Navigate(L"about:blank");
}
else {}
}
HRESULT WebBrowser::OnCompleted(DISPPARAMS* args)
{
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;
if (!htmlSource) return S_OK;
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
// allocate global memory to copy the HTML content to
size_t len = wcslen(htmlSource) + 1;
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, len * sizeof(wchar_t));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
wmemcpy_s(p_content, len, htmlSource, len);
GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
delete[] htmlSource;
htmlSource = nullptr;
return S_OK;
}
// ----- Control methods -----
void WebBrowser::Navigate(const wchar_t *szUrl)
{
HRESULT hr = E_FAIL;
IWebBrowser2 *pwb = NULL;
hr = GetGIWebBrowser(&pwb);
if (SUCCEEDED(hr) && pwb)
{
bstr_t url(szUrl);
variant_t flags(0x02u); //navNoHistory
pwb->Navigate(url, &flags, 0, 0, 0);
}
else { /* Handle error */ }
}
void WebBrowser::GoBack() { this->webBrowser2->GoBack(); }
void WebBrowser::GoForward() { this->webBrowser2->GoForward(); }
void WebBrowser::Refresh() { this->webBrowser2->Refresh(); }
WebBrowser::WebBrowser(HWND _hWndParent) :
isFullyCreated(false)
{
HRESULT hr = E_FAIL;
htmlSource = nullptr;
IConnectionPointContainer* container = nullptr;
IUnknown* punk = nullptr;
iComRefCount = 0;
::SetRect(&rObject, 0, 0, 300, 300);
hWndParent = _hWndParent;
if (CreateBrowser())
{
this->Navigate(L"about:blank");
hr = RegisterGIWebBrowser();
if (SUCCEEDED(hr))
{
webBrowser2->put_Visible(TRUE);
ShowWindow(GetControlWindow(), SW_SHOW);
hr = webBrowser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container);
if (SUCCEEDED(hr) && container) hr = container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback);
if (SUCCEEDED(hr) && container) hr = this->QueryInterface(IID_IUnknown, (void**)&punk);
if (SUCCEEDED(hr) && container) hr = callback->Advise(punk, &eventCookie);
if (SUCCEEDED(hr) && eventCookie) isFullyCreated = true;
if (punk) punk->Release();
if (container) container->Release();
}
}
}
bool WebBrowser::CreateBrowser()
{
HRESULT hr;
hr = ::OleCreate(CLSID_WebBrowser, IID_IOleObject, OLERENDER_DRAW, 0, this, this, (void**)&oleObject);
if (SUCCEEDED(hr) && oleObject)
{
if (SUCCEEDED(hr)) hr = oleObject->SetClientSite(this);
if (SUCCEEDED(hr)) hr = OleSetContainedObject(oleObject, TRUE);
if (SUCCEEDED(hr))
{
RECT posRect;
::SetRect(&posRect, -300, -300, 300, 300);
hr = oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, -1, hWndParent, &posRect);
}
hr = oleObject->QueryInterface(&webBrowser2);
}
if (FAILED(hr) || !webBrowser2)
{
MessageBox(NULL, L"Create Browser failed!", L"Error", MB_ICONERROR);
return false;
}
return true;
}
RECT WebBrowser::PixelToHiMetric(const RECT& _rc)
{
static bool s_initialized = false;
static int s_pixelsPerInchX, s_pixelsPerInchY;
if (!s_initialized)
{
HDC hdc = ::GetDC(0);
s_pixelsPerInchX = ::GetDeviceCaps(hdc, LOGPIXELSX);
s_pixelsPerInchY = ::GetDeviceCaps(hdc, LOGPIXELSY);
::ReleaseDC(0, hdc);
s_initialized = true;
}
RECT rc;
rc.left = MulDiv(2540, _rc.left, s_pixelsPerInchX);
rc.top = MulDiv(2540, _rc.top, s_pixelsPerInchY);
rc.right = MulDiv(2540, _rc.right, s_pixelsPerInchX);
rc.bottom = MulDiv(2540, _rc.bottom, s_pixelsPerInchY);
return rc;
}
void WebBrowser::SetRect(const RECT& _rc)
{
rObject = _rc;
{
RECT hiMetricRect = PixelToHiMetric(rObject);
SIZEL sz;
sz.cx = hiMetricRect.right - hiMetricRect.left;
sz.cy = hiMetricRect.bottom - hiMetricRect.top;
oleObject->SetExtent(DVASPECT_CONTENT, &sz);
}
if (oleInPlaceObject != 0)
{
oleInPlaceObject->SetObjectRects(&rObject, &rObject);
}
}
HWND WebBrowser::GetControlWindow() { if (!hWndControl && oleInPlaceObject) oleInPlaceObject->GetWindow(&hWndControl); return hWndControl; }
// Register IWebBrowser2 instance for use in threads
HRESULT WebBrowser::RegisterGIWebBrowser()
{
HRESULT hr = E_FAIL;
IUnknown* pIUnknown = NULL;
IGlobalInterfaceTable* pIGlobalInterfaceTable = NULL;
dwGIWebBrowserCookie = 0;
hr = ::CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pIGlobalInterfaceTable);
if (SUCCEEDED(hr) && pIGlobalInterfaceTable) hr = webBrowser2->QueryInterface(IID_IUnknown, (void**)&pIUnknown);
if (SUCCEEDED(hr) && pIUnknown) hr = pIGlobalInterfaceTable->RegisterInterfaceInGlobal(pIUnknown, __uuidof(IWebBrowser2), &dwGIWebBrowserCookie);
if (pIUnknown) pIUnknown->Release();
if (pIGlobalInterfaceTable) pIGlobalInterfaceTable->Release();
if (SUCCEEDED(hr) && dwGIWebBrowserCookie) return hr;
return E_FAIL;
}
// Get IWebBrowser2 instance from threads
HRESULT WebBrowser::GetGIWebBrowser(IWebBrowser2** pwb)
{
HRESULT hr = E_FAIL;
IGlobalInterfaceTable* pIGlobalInterfaceTable = NULL;
*pwb = NULL;
if (dwGIWebBrowserCookie) hr = ::CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pIGlobalInterfaceTable);
if (SUCCEEDED(hr) && pIGlobalInterfaceTable) hr = pIGlobalInterfaceTable->GetInterfaceFromGlobal(dwGIWebBrowserCookie, __uuidof(IWebBrowser2), (void **)pwb);
if (pIGlobalInterfaceTable) pIGlobalInterfaceTable->Release();
return hr;
}
// ----- IUnknown -----
ULONG STDMETHODCALLTYPE WebBrowser::AddRef(void) { return ++iComRefCount; }
ULONG STDMETHODCALLTYPE WebBrowser::Release(void) { return --iComRefCount; }
HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid, void**ppvObject)
{
if (riid == __uuidof(IUnknown)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IDispatch)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IOleClientSite)) *ppvObject = static_cast<IOleClientSite*>(this);
else if (riid == __uuidof(IOleInPlaceSite)) *ppvObject = static_cast<IOleInPlaceSite*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
// ---------- IOleInPlaceSite ----------
HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate(void){ return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate(void){ return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceActivate(void)
{
OleLockRunning(oleObject, TRUE, FALSE);
oleObject->QueryInterface(&oleInPlaceObject);
oleInPlaceObject->SetObjectRects(&rObject, &rObject);
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::GetWindowContext(__RPC__deref_out_opt IOleInPlaceFrame **ppFrame, __RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc, __RPC__out LPRECT lprcPosRect, __RPC__out LPRECT lprcClipRect, __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
HWND hwnd = hWndParent;
(*ppFrame) = NULL;
(*ppDoc) = NULL;
(*lprcPosRect).left = rObject.left;
(*lprcPosRect).top = rObject.top;
(*lprcPosRect).right = rObject.right;
(*lprcPosRect).bottom = rObject.bottom;
*lprcClipRect = *lprcPosRect;
lpFrameInfo->fMDIApp = false;
lpFrameInfo->hwndFrame = hwnd;
lpFrameInfo->haccel = NULL;
lpFrameInfo->cAccelEntries = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(SIZE scrollExtant) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(BOOL fUndoable) { return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState(void) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo(void) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnPosRectChange(__RPC__in LPCRECT lprcPosRect) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceDeactivate(void) { hWndControl = 0; oleInPlaceObject = 0; return S_OK; }
// ---------- IDispatch ----------
HRESULT WebBrowser::GetTypeInfoCount(__RPC__out UINT *pctinfo) { return E_FAIL; }
HRESULT WebBrowser::GetTypeInfo(UINT, LCID, __RPC__deref_out_opt ITypeInfo **) { return E_FAIL; }
HRESULT WebBrowser::GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0, 16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId) { return E_FAIL; }
HRESULT STDMETHODCALLTYPE WebBrowser::Invoke(_In_ DISPID dispIdMember, _In_ REFIID, _In_ LCID, _In_ WORD, _In_ DISPPARAMS *pDispParams, _Out_opt_ VARIANT *pVarResult, _Out_opt_ EXCEPINFO*, _Out_opt_ UINT*)
{
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams);
else return S_OK;
}
// ---------- IOleWindow ----------
HRESULT STDMETHODCALLTYPE WebBrowser::GetWindow(__RPC__deref_out_opt HWND *phwnd) { (*phwnd) = hWndParent; return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
// ---------- IOleClientSite ----------
HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject(void) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::GetContainer(__RPC__deref_out_opt IOleContainer **ppContainer) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject(void) { return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(BOOL fShow) { return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::RequestNewObjectLayout(void) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, __RPC__deref_out_opt IMoniker **ppmk) { if ((dwAssign == OLEGETMONIKER_ONLYIFTHERE) && (dwWhichMoniker == OLEWHICHMK_CONTAINER))return E_FAIL; return E_NOTIMPL; }
// ----- IStorage -----
HRESULT STDMETHODCALLTYPE WebBrowser::CreateStream(__RPC__in_string const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, __RPC__deref_out_opt IStream **ppstm) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::CreateStorage(__RPC__in_string const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, __RPC__deref_out_opt IStorage **ppstg) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::OpenStorage(__RPC__in_opt_string const OLECHAR *pwcsName, __RPC__in_opt IStorage *pstgPriority, DWORD grfMode, __RPC__deref_opt_in_opt SNB snbExclude, DWORD reserved, __RPC__deref_out_opt IStorage **ppstg) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, __RPC__in_opt SNB snbExclude, IStorage *pstgDest) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::MoveElementTo(__RPC__in_string const OLECHAR *pwcsName, __RPC__in_opt IStorage *pstgDest, __RPC__in_string const OLECHAR *pwcsNewName, DWORD grfFlags) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::Commit(DWORD grfCommitFlags) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::Revert(void) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::DestroyElement(__RPC__in_string const OLECHAR *pwcsName) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::RenameElement(__RPC__in_string const OLECHAR *pwcsOldName, __RPC__in_string const OLECHAR *pwcsNewName) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::SetElementTimes(__RPC__in_opt_string const OLECHAR *pwcsName, __RPC__in_opt const FILETIME *pctime, __RPC__in_opt const FILETIME *patime, __RPC__in_opt const FILETIME *pmtime) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(__RPC__in REFCLSID clsid) { return S_OK; }
HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(DWORD grfStateBits, DWORD grfMask) { return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE WebBrowser::Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag) { return E_NOTIMPL; }
Win32Project1.cpp
#include "stdafx.h"
#include "Win32Project1.h"
#include "WebBrowser.h"
HWND hWnd = NULL;
HWND tkWebBrowserHWND = NULL;
WebBrowser* tkWebBrowser = NULL;
void callFromThread();
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
OleInitialize(NULL);
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow)) return FALSE;
tkWebBrowserHWND = CreateWindow(L"Static", NULL, WS_CHILD | WS_VISIBLE, 221, 0, 300, 300, hWnd, NULL, hInstance, 0);
tkWebBrowser = new WebBrowser(tkWebBrowserHWND);
// Use one of following command
//tkWebBrowser->SetText(L"Hello!");
//tkWebBrowser->setHTML(L"<h1>Title</h1><div>Content</div>");
//tkWebBrowser->setHTML(L"<html><body><h1>Title 2</h1><div>Content 2</div></body></html>", false);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)callFromThread, 0, 0, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
void callFromThread()
{
OleInitialize(NULL);
// Use one of following command
//tkWebBrowser->SetText(L"Hello from thread!");
//tkWebBrowser->setHTML(L"<h1>Title from thread</h1><div>Content from thread</div>");
tkWebBrowser->setHTML(L"<html><body><h1>Title 2 from thread</h1><div>Content 2 from thread</div></body></html>", false);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
HINSTANCE hInst;
const wchar_t* szTitle = L"Title";
const wchar_t* szWindowClass = L"Window Class";
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
i'm trying to make exe packer
5
extract exe to buffer(in my case: vector)
add new section
get offset of new EP and run
but after call newmain i got 0xC0000005
main.cpp:
pastebin
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "main.h"
typedef struct _BASE_RELOCATION_ENTRY
{
WORD Offset : 12;
WORD Type : 4;
} BASE_RELOCATION_ENTRY;
BOOL applyRelocBlock(BASE_RELOCATION_ENTRY* block, size_t entriesNum, DWORD page, PVOID newBase)
{
PVOID ImageBaseAddress = NtCurrentTeb()->Peb->ImageBaseAddress;
BASE_RELOCATION_ENTRY* entry = block;
for (int i = 0; i < entriesNum; i++)
{
DWORD offset = entry->Offset;
DWORD type = entry->Type;
if (entry == NULL || type == 0 || offset == 0)
{
//printf("Applied relocations: %d\n", i);
return TRUE; //finish
}
if (type != 3)
{
printf("Not supported relocations format at %d: %d\n", i, type);
return FALSE;
}
uint32_t* relocateAddr = (uint32_t*)((ULONG_PTR)newBase + page + offset);
(*relocateAddr) = ((*relocateAddr) - (ULONG_PTR)ImageBaseAddress) + (ULONG_PTR)newBase;
entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(uint16_t));
}
return TRUE;
}
BOOL applyRelocations(PIMAGE_NT_HEADERS NtHeaders, PVOID newBase)
{
PVOID ImageBaseAddress = NtCurrentTeb()->Peb->ImageBaseAddress;
//fetch relocation table from current image:
IMAGE_DATA_DIRECTORY relocDir = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (relocDir.VirtualAddress == NULL)
{
printf("Cannot relocate - application have no relocation table!");
return FALSE;
}
DWORD maxSize = relocDir.Size;
DWORD parsedSize = 0;
DWORD relocAddr = relocDir.VirtualAddress;
IMAGE_BASE_RELOCATION* reloc = NULL;
while (parsedSize < maxSize)
{
reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR)ImageBaseAddress);
parsedSize += reloc->SizeOfBlock;
if (reloc->VirtualAddress == NULL || reloc->SizeOfBlock == 0)
{
continue;
}
printf("RelocBlock: %p %p\n", reloc->VirtualAddress, reloc->SizeOfBlock);
size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(uint32_t)) / sizeof(uint16_t);
DWORD page = reloc->VirtualAddress;
BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)reloc + sizeof(uint32_t) + sizeof(uint32_t));
if (applyRelocBlock(block, entriesNum, page, newBase) == FALSE)
{
return FALSE;
}
}
return TRUE;
}
bool checkLibs()
{
return load_ntdll_functions() && load_kernel32_functions();
}
bool mapAndRun()
{
HANDLE hSection = NULL;
PVOID ImageBaseAddress = NtCurrentTeb()->Peb->ImageBaseAddress;
PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ImageBaseAddress);
if (NtHeaders == NULL)
{
printf("[ERROR] RtlImageNtHeader failed, error : %d\n", GetLastError());
return false;
}
LARGE_INTEGER MaximumSize;
ULONG ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
MaximumSize.LowPart = ImageSize;
MaximumSize.HighPart = 0;
NTSTATUS Status = NULL;
if ((Status = ZwCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != STATUS_SUCCESS)
{
printf("[ERROR] ZwCreateSection failed, status : %x\n", Status);
system("pause");
return false;
}
printf("Section handle: %x\n", hSection);
HANDLE hProcess = NULL;
PVOID pSectionBaseAddress = NULL;
SIZE_T ViewSize = 0;
DWORD dwInheritDisposition = 1; //VIEW_SHARE
// map the section in context of current process:
if ((Status = NtMapViewOfSection(hSection, GetCurrentProcess(), &pSectionBaseAddress, NULL, NULL, NULL, &ViewSize, dwInheritDisposition, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS)
{
printf("[ERROR] NtMapViewOfSection failed, status : %x\n", Status);
system("pause");
return false;
}
printf("Created new section, BaseAddress: %p ViewSize: %p\n", pSectionBaseAddress, ViewSize);
printf("Mapping into: %p <- current image: %p %p\n", pSectionBaseAddress, ImageBaseAddress, ImageSize);
RtlCopyMemory(pSectionBaseAddress, ImageBaseAddress, ImageSize);
ZwClose(hSection);
hSection = NULL;
if (applyRelocations(NtHeaders, pSectionBaseAddress) == FALSE) {
printf("Applying relocations failed, cannot continue!");
ZwTerminateProcess(GetCurrentProcess(), STATUS_FAILURE);
}
printf("Applied relocations!\n");
//
std::vector<unsigned char> extractedData = unpackExe(); //packe exe
IMAGE_NT_HEADERS INH;
IMAGE_DOS_HEADER IDH;
memcpy(&IDH, &extractedData[0], sizeof(IDH));
memcpy(&INH, (void*)((DWORD)&extractedData[0] + IDH.e_lfanew), sizeof(INH));
LARGE_INTEGER MaximumSizeEX;
ULONG ImageSizeEX = INH.OptionalHeader.SizeOfImage;
MaximumSizeEX.LowPart = ImageSizeEX;
MaximumSizeEX.HighPart = 0;
ULONG_PTR exEP = INH.OptionalHeader.AddressOfEntryPoint;
ULONG_PTR offsetFromBase = exEP - (ULONG_PTR)ImageBaseAddress;
printf("extracted EP offset: %p\n", offsetFromBase);
ULONG_PTR newMain = ((ULONG_PTR)pSectionBaseAddress + offsetFromBase);
printf("extracted EP address in new section: %p\n", newMain);
__asm {
call newMain
};
return true;
}
bool mapAndExecute()
{
if (checkLibs())
{
if (mapAndRun())
{
}
}
return true;
}
int main()
{
mapAndExecute();
std::cin.get();
}
main.h:pastebin: pastebin.com/Spc5WTsQ
#pragma once
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#if !defined NTSTATUS
typedef LONG NTSTATUS;
#endif
#define STATUS_SUCCESS 0
#define STATUS_FAILURE (-1)
#define NtCurrentProcess() ((HANDLE)-1)
typedef struct _CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef LONG NTSTATUS, *PNTSTATUS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA
{
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _PEB
{
BYTE Reserved1[2]; /* 00 */
BYTE BeingDebugged; /* 02 */
BYTE Reserved2[5]; /* 03 */
HMODULE ImageBaseAddress; /* 08 */
PPEB_LDR_DATA LdrData; /* 0c */
DWORD ProcessParameters; /* 10 */
PVOID __pad_14; /* 14 */
HANDLE ProcessHeap; /* 18 */
BYTE __pad_1c[36]; /* 1c */
DWORD TlsBitmap; /* 40 */
ULONG TlsBitmapBits[2]; /* 44 */
BYTE __pad_4c[24]; /* 4c */
ULONG NumberOfProcessors; /* 64 */
BYTE __pad_68[128]; /* 68 */
PVOID Reserved3[59]; /* e8 */
ULONG SessionId; /* 1d4 */
} PEB, *PPEB;
typedef struct _TEB
{
NT_TIB Tib; /* 000 */
PVOID EnvironmentPointer; /* 01c */
CLIENT_ID ClientId; /* 020 */
PVOID ActiveRpcHandle; /* 028 */
PVOID ThreadLocalStoragePointer; /* 02c */
PPEB Peb; /* 030 */
ULONG LastErrorValue; /* 034 */
BYTE __pad038[140]; /* 038 */
ULONG CurrentLocale; /* 0c4 */
BYTE __pad0c8[1752]; /* 0c8 */
PVOID Reserved2[278]; /* 7a0 */
UNICODE_STRING StaticUnicodeString; /* bf8 used by advapi32 */
WCHAR StaticUnicodeBuffer[261]; /* c00 used by advapi32 */
PVOID DeallocationStack; /* e0c */
PVOID TlsSlots[64]; /* e10 */
LIST_ENTRY TlsLinks; /* f10 */
PVOID Reserved4[26]; /* f18 */
PVOID ReservedForOle; /* f80 Windows 2000 only */
PVOID Reserved5[4]; /* f84 */
PVOID TlsExpansionSlots; /* f94 */
} TEB, *PTEB;
typedef
void
(*PKNORMAL_ROUTINE) (
void* NormalContext,
void* SystemArgument1,
void* SystemArgument2
);
typedef struct {
int info;
PKNORMAL_ROUTINE fun;
} *PIO_STATUS_BLOCK;
// Make sure we print the __stdcall properly
typedef
void
(__stdcall *PIO_APC_ROUTINE) (
void* ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
long Reserved
);
#if !defined PROCESSINFOCLASS
typedef LONG PROCESSINFOCLASS;
#endif
#if !defined THREADINFOCLASS
typedef LONG THREADINFOCLASS;
#endif
#if !defined PPEB
typedef struct _PEB *PPEB;
#endif
#if !defined PROCESS_BASIC_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
#endif;
/*
typedef LONG NTSTATUS, *PNTSTATUS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
*/
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef NTSTATUS(WINAPI * PFN_ZWQUERYINFORMATIONPROCESS)(HANDLE, PROCESSINFOCLASS,
PVOID, ULONG, PULONG);
//ntdll api:
NTSTATUS(NTAPI *ZwQueryInformationProcess)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength OPTIONAL
);
NTSTATUS(NTAPI *ZwCreateSection)(
__out PHANDLE SectionHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in PLARGE_INTEGER MaximumSize,
__in ULONG SectionPageProtection,
__in ULONG AllocationAttributes,
__in HANDLE FileHandle
);
NTSTATUS(NTAPI *NtMapViewOfSection)(
__in HANDLE SectionHandle,
__in HANDLE ProcessHandle,
__inout PVOID *BaseAddress,
__in ULONG_PTR ZeroBits,
__in SIZE_T CommitSize,
__inout PLARGE_INTEGER SectionOffset,
__inout PSIZE_T ViewSize,
__in DWORD InheritDisposition,
__in ULONG AllocationType,
__in ULONG Win32Protect
);
NTSTATUS(NTAPI *ZwCreateThreadEx) (
__out PHANDLE ThreadHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in HANDLE ProcessHandle,
__in PVOID StartRoutine,
__in PVOID Argument,
__in ULONG CreateFlags,
__in ULONG_PTR ZeroBits,
__in SIZE_T StackSize,
__in SIZE_T MaximumStackSize,
__in PVOID AttributeList
);
NTSTATUS(NTAPI *ZwUnmapViewOfSection) (
__in HANDLE ProcessHandle,
__in PVOID BaseAddress
);
NTSTATUS(NTAPI *ZwClose) (
__in HANDLE Handle
);
NTSTATUS(NTAPI *ZwTerminateProcess) (
__in HANDLE ProcessHandle,
__in NTSTATUS ExitStatus
);
NTSTATUS(NTAPI *NtQueueApcThread)(
__in HANDLE ThreadHandle,
__in PVOID ApcRoutine,
__in PVOID ApcRoutineContext OPTIONAL,
__in PVOID ApcStatusBlock OPTIONAL,
__in ULONG ApcReserved OPTIONAL
);
NTSTATUS(NTAPI *ZwSetInformationThread) (
__in HANDLE ThreadHandle,
__in THREADINFOCLASS ThreadInformationClass,
__in PVOID ThreadInformation,
__in ULONG ThreadInformationLength
);
PIMAGE_NT_HEADERS(NTAPI *RtlImageNtHeader) (
__in PVOID ModuleAddress
);
//kernel32 api
BOOL
(WINAPI *CreateProcessInternalW)(HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
PHANDLE hNewToken
);
trying to adoptate source from here
https://github.com/hasherezade/snippets/tree/master/inject4
The data you have loaded is in the loading application's data space and execution of data is blocked in modern memory protected operating systems - because that was previously a common and rather easy exploit for viruses.
In order to run, an executable must have been loaded and located by the operating system.
Not sure how to post a large code snippet in response to a request that was a remark. Michael Haephrati asked for an x64 example of executing data as x64 code. Here's the code (x64 only for this code, the calling conventions differ in 32 bit code):
#include <windows.h>
#include <iostream>
typedef int(*PMULFUNC)(int l, int r);
PMULFUNC buildFunction()
{
LPVOID pMem = VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
unsigned char *pNext = (unsigned char *)pMem;
*pNext = 0x8b; ++pNext; // mov eax, ecx
*pNext = 0xc1; ++pNext;
*pNext = 0x0f; ++pNext; // imul eax, edx
*pNext = 0xaf; ++pNext;
*pNext = 0xc2; ++pNext;
*pNext = 0xc3; ++pNext; // ret
return (PMULFUNC)pMem;
}
int main()
{
using namespace std;
PMULFUNC pMul = buildFunction();
int l = 5;
for (int r=1; r<=12; ++r)
{
cout << l << "x" << r << "=" << (*pMul)(l, r) << endl;
}
return 0;
}
typedef int(__stdcall *PMULFUNC)(int l, int r);
PMULFUNC buildFunction()
{
LPVOID pMem = VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
unsigned char *pNext = (unsigned char *)pMem;
*pNext = 0x8b; ++pNext; // mov eax, ecx
*pNext = 0xc1; ++pNext;
*pNext = 0x0f; ++pNext; // imul eax, edx
*pNext = 0xaf; ++pNext;
*pNext = 0xc2; ++pNext;
*pNext = 0xc3; ++pNext; // ret
return (PMULFUNC)pMem;
}
int main()
{
using namespace std;
PMULFUNC pMul = buildFunction();
int l = 5;
for (int r=1; r<=12; ++r)
{
cout << l << "x" << r << "=" << (*pMul)(l, r) << endl;
}
return 0;
}
In response to the specific question, it's possible but advanced. EXEs aren't simply copied into memory: references to other DLL's are resolved, sections that are adjacent in the image may be separated in memory, and many other things. In short you would have to re-implement the loader. But one thing is certain, if a page has the correct permissions it can be executed,
It would be impossible to run an executable from memory without having the executable data reside in a physical file. Windows won't allow it. No windows API provides mechanism to execute file directly from memory. All windows API like CreateProcess() or ShellExcute() require a physical file to be present. If there is a way, it would be considered a vulnerability and will be soon patched.