ctrl-x, ctrl-v and ctrl-c problems



I've writte a small program (see below), which embeds the webbrowser
control in a window. You can download the full project at
http://www.frank-buss.de/tmp/test.zip
The problem is, that the Ctrl-accelerator keys didn't work, for example for
this page: http://www.frank-buss.de/tmp/form.html
I've tried the workaround from
http://www.microsoft.com/mind/0499/faq/faq0499.asp :

Adding a new message handler:

MESSAGE_HANDLER( WM_KEYDOWN, OnKeydown )

LRESULT OnKeydown(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled)
{
CComQIPtr<IOleInPlaceActiveObject,
&IID_IOleInPlaceActiveObject> pIOIPAO(m_spBrowser);

HRESULT hr = S_FALSE;

if (pIOIPAO)
{
MSG msg;
msg.message = uMsg;
msg.wParam = wParam;
msg.lParam = lParam;

hr = pIOIPAO->TranslateAccelerator(&msg);
}

return 0;
}

but doesn't work, because the "Sometimes your application will not
automatically be sent WM_KEYDOWN messages for accelerator keys. " from the
FAQ applies, so I changed my message loop, too:

while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage(&msg);
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
::SendMessage(atlWnd, msg.message, msg.wParam, msg.lParam);
}
DispatchMessage(&msg);
}

Now I can use ctrl-c, ctrl-x and ctrl-v with the form.html sample, but when
I try to select text by holding down the shift-key and moving with the
cursor keys, it selects two chars at once.

The other problem is, when I try to use the accelerators in a Flash movie,
for example this one: http://www.frank-buss.de/tmp/flash.html .
Selecting with holding the shift key down works, but looks like ctrl-v
appends some garbage after the clipboard data, and ctrl-c and ctrl-x
substitutes the selected text with garbage.

Both work from Internet Explorer without problems. I want the same
behaviour in my program.

The source, without the Microsoft FAQ hack:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <string>

#include <atlbase.h>
#include <atlcom.h>
#include <atlwin.h>
#include <atltypes.h>
#include <atlctl.h>
#include <atlhost.h>
#include <comutil.h>

using namespace ATL;
using namespace std;

extern string wget(string host, string url);

int winWidth=800;
int winHeight=410;
const char* title = "Test";

CComModule _Module;

#define CHECK_HR(hr) if ( FAILED(hr) ) ATLTRACE( _T("FAILED! HR =
0x%08x\n"), hr )
#define RETURN_FAILED(hr) CHECK_HR(hr); if ( FAILED(hr) ) return hr

///////////////////////////////////////////////////////////////////////////////////////
// GetHTML - Takes an HTMLDocument2 object, and gets the HTML source code
// for it
// The caller is responsible for freeing the memory allocated
///////////////////////////////////////////////////////////////////////////////////////
HRESULT GetHTML( IHTMLDocument2* pDoc, LPSTR& lpData, DWORD& dwSize )
{
HRESULT hr;
CComPtr<IPersistStreamInit> spPersist;
CComPtr<IStream> spStream;
HGLOBAL hGlobal;
STATSTG stgstats;
LPVOID lpRawData;

// Get the right interface
hr = pDoc->QueryInterface( &spPersist );
RETURN_FAILED( hr );

// Create the stream object
hr = ::CreateStreamOnHGlobal( NULL, TRUE, &spStream );
RETURN_FAILED( hr );

// Save the HTML
hr = spPersist->Save( spStream, FALSE );
RETURN_FAILED( hr );

// Get the size of the stream
hr = spStream->Stat( &stgstats, STATFLAG_NONAME );
RETURN_FAILED( hr );

// Get the global memory
hr = ::GetHGlobalFromStream( spStream, &hGlobal );
RETURN_FAILED( hr );

lpRawData = ::GlobalLock(hGlobal);
if ( lpRawData != NULL )
{
dwSize = stgstats.cbSize.LowPart + 1;
lpData = new char[dwSize];

ZeroMemory( lpData, dwSize );
CopyMemory( lpData, lpRawData, dwSize-1 );
::GlobalUnlock( hGlobal );

hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}

return hr;
}

string url = "http://www.frank-buss.de/tmp/form.html";;

class CWebWindow : public CWindowImpl<CWebWindow>
{
// START MESSAGE_MAP
BEGIN_MSG_MAP( CWebWindow )
MESSAGE_HANDLER( WM_CREATE, OnCreate )
MESSAGE_HANDLER( WM_CREATE, OnCreate )
MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
MESSAGE_HANDLER( WM_KEYDOWN, OnKeydown )
END_MSG_MAP()
// END MESSAGE_MAP

LRESULT OnKeydown(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled)
{
CComQIPtr<IOleInPlaceActiveObject,
&IID_IOleInPlaceActiveObject> pIOIPAO(m_spBrowser);

HRESULT hr = S_FALSE;

if (pIOIPAO)
{
MSG msg;
msg.message = uMsg;
msg.wParam = wParam;
msg.lParam = lParam;

hr = pIOIPAO->TranslateAccelerator(&msg);
}

return 0;
}


LRESULT OnCreate( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,
BOOL& /*bHandled*/ )
{
HRESULT hr;
RECT cr;

GetClientRect(&cr);
int dx = winWidth - (cr.right-cr.left);
int dy = winHeight - (cr.bottom-cr.top);
int breite = GetSystemMetrics(SM_CXSCREEN);
int hoehe = GetSystemMetrics(SM_CYSCREEN);
int px = breite/2-((winWidth+dx)/2)-5;
int py = hoehe/2-((winHeight+dy)/2)-5;
MoveWindow(px, py, winWidth + dx, winHeight + dy);
GetClientRect(&cr);
m_wndAx.Create( m_hWnd, cr, NULL, WS_CHILD|WS_VISIBLE);

hr = m_wndAx.CreateControl( _bstr_t(url.c_str()) );
CHECK_HR( hr );
if ( SUCCEEDED(hr) )
{
hr = m_wndAx.QueryControl( IID_IWebBrowser2, (void**)&m_spBrowser );
CHECK_HR( hr );
ShowHTML();
} else {
::MessageBox(NULL, "Fehler beim Starten des Internet Explorers.\nBitte installieren Sie eine aktuelle Internet Explorer Version.", title, MB_ICONWARNING);
}

return SUCCEEDED(hr) ? 0 : -1;
}

LRESULT OnDestroy( UINT, WPARAM, LPARAM, BOOL& )
{
PostQuitMessage( 0 );
return 0;
}

HRESULT ShowHTML()
{
HRESULT hr;
CComPtr<IDispatch> spDocDispatch;
CComPtr<IHTMLDocument2> spDocument;
READYSTATE rs;
MSG msg;
LPSTR lpData;
DWORD dwSize;

// Wait for the page to finish loading
do
{
hr = m_spBrowser->get_ReadyState( &rs );
RETURN_FAILED( hr );
if ( rs != READYSTATE_COMPLETE )
{
if ( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
} while ( rs != READYSTATE_COMPLETE );

hr = m_spBrowser->get_Document( &spDocDispatch );
RETURN_FAILED( hr );

hr = spDocDispatch->QueryInterface( &spDocument );
RETURN_FAILED( hr );

// Call the main function
hr = GetHTML( spDocument, lpData, dwSize );
RETURN_FAILED( hr );

// Display the HTML
//::OutputDebugString( lpData );
//::MessageBoxA( m_hWnd, lpData, "HTML Display", MB_OK );
delete [] lpData;

return S_OK;
}

private:
CComPtr<IWebBrowser2> m_spBrowser;
CAxWindow m_wndAx;
};



int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;

::CoInitialize( NULL );
_Module.Init(NULL, hInstance, &LIBID_ATLLib);

// Create an instance of CWebWindow
CWebWindow atlWnd;
int breite = GetSystemMetrics(SM_CXSCREEN);
int hoehe = GetSystemMetrics(SM_CYSCREEN);
int px = breite/2-(winWidth/2)-5;
int py = hoehe/2-(winHeight/2)-5;
RECT wr;
wr.left = px;
wr.top = py;
wr.right = winWidth + wr.left;
wr.bottom = winHeight + wr.top;
atlWnd.Create( NULL, wr, title, WS_TILED | WS_VISIBLE | WS_SYSMENU);

while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
exit(0);
}



--
Frank Buß, fb@xxxxxxxxxxxxx
http://www.frank-buss.de, http://www.it4-systems.de
.