alt: Host component implementation: IOleClientSite.
[wine/wine64.git] / dlls / atl / atl_ax.c
blobc2b5812e2420740885f960285d5eb01b89bf0321
1 /*
2 * Active Template Library ActiveX functions (atl.dll)
4 * Copyright 2006 Andrey Turkin
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "winuser.h"
31 #include "wine/debug.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "ole2.h"
35 #include "exdisp.h"
36 #include "atlbase.h"
37 #include "atliface.h"
38 #include "atlwin.h"
40 #include "wine/unicode.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(atl);
44 typedef struct IOCS {
45 const IOleClientSiteVtbl *lpOleClientSiteVtbl;
47 LONG ref;
48 HWND hWnd;
49 IOleObject *control;
50 WNDPROC OrigWndProc;
51 } IOCS;
53 /**********************************************************************
54 * AtlAxWin class window procedure
56 static LRESULT CALLBACK AtlAxWin_wndproc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
58 if ( wMsg == WM_CREATE )
60 DWORD len = GetWindowTextLengthW( hWnd ) + 1;
61 WCHAR *ptr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
62 if (!ptr)
63 return 1;
64 GetWindowTextW( hWnd, ptr, len );
65 AtlAxCreateControlEx( ptr, hWnd, NULL, NULL, NULL, NULL, NULL );
66 HeapFree( GetProcessHeap(), 0, ptr );
67 return 0;
69 return DefWindowProcW( hWnd, wMsg, wParam, lParam );
72 /***********************************************************************
73 * AtlAxWinInit [ATL.@]
74 * Initializes the control-hosting code: registering the AtlAxWin,
75 * AtlAxWin7 and AtlAxWinLic7 window classes and some messages.
77 * RETURNS
78 * TRUE or FALSE
81 BOOL WINAPI AtlAxWinInit(void)
83 WNDCLASSEXW wcex;
84 const WCHAR AtlAxWin[] = {'A','t','l','A','x','W','i','n',0};
86 FIXME("semi-stub\n");
88 if ( FAILED( OleInitialize(NULL) ) )
89 return FALSE;
91 wcex.cbSize = sizeof(wcex);
92 wcex.style = 0;
93 wcex.cbClsExtra = 0;
94 wcex.cbWndExtra = 0;
95 wcex.hInstance = GetModuleHandleW( NULL );
96 wcex.hIcon = NULL;
97 wcex.hCursor = NULL;
98 wcex.hbrBackground = NULL;
99 wcex.lpszMenuName = NULL;
100 wcex.hIconSm = 0;
102 wcex.lpfnWndProc = AtlAxWin_wndproc;
103 wcex.lpszClassName = AtlAxWin;
104 if ( !RegisterClassExW( &wcex ) )
105 return FALSE;
107 return TRUE;
110 /***********************************************************************
111 * Atl container component implementation
115 static ULONG WINAPI IOCS_AddRef(IOCS *This)
117 ULONG ref = InterlockedIncrement(&This->ref);
119 TRACE( "(%p) : AddRef from %d\n", This, ref - 1 );
121 return ref;
124 #define THIS2IOLECLIENTSITE(This) ((IOleClientSite*)&This->lpOleClientSiteVtbl)
126 static HRESULT WINAPI IOCS_QueryInterface(IOCS *This, REFIID riid, void **ppv)
128 *ppv = NULL;
130 if ( IsEqualIID( &IID_IUnknown, riid )
131 || IsEqualIID( &IID_IOleClientSite, riid ) )
133 *ppv = THIS2IOLECLIENTSITE(This);
136 if (*ppv)
138 IOCS_AddRef( This );
139 return S_OK;
142 WARN("unsupported interface %s\n", debugstr_guid( riid ) );
143 *ppv = NULL;
144 return E_NOINTERFACE;
147 static HRESULT IOCS_Detach( IOCS *This );
148 static ULONG WINAPI IOCS_Release(IOCS *This)
150 ULONG ref = InterlockedDecrement(&This->ref);
152 TRACE( "(%p) : ReleaseRef to %d\n", This, ref );
154 if (!ref)
156 IOCS_Detach( This );
157 HeapFree( GetProcessHeap(), 0, This );
160 return ref;
163 #define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl)))
165 #undef IFACE2THIS
166 #define IFACE2THIS(iface) DEFINE_THIS(IOCS,OleClientSite, iface)
167 static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
169 IOCS *This = IFACE2THIS(iface);
170 return IOCS_QueryInterface(This, riid, ppv);
172 static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
174 IOCS *This = IFACE2THIS(iface);
175 return IOCS_AddRef(This);
177 static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
179 IOCS *This = IFACE2THIS(iface);
180 return IOCS_Release(This);
182 static HRESULT WINAPI OleClientSite_SaveObject(IOleClientSite *iface)
184 IOCS *This = IFACE2THIS(iface);
185 FIXME( "(%p) - stub\n", This );
186 return E_NOTIMPL;
188 static HRESULT WINAPI OleClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
190 IOCS *This = IFACE2THIS(iface);
192 FIXME( "(%p, 0x%x, 0x%x, %p)\n", This, dwAssign, dwWhichMoniker, ppmk );
193 return E_NOTIMPL;
195 static HRESULT WINAPI OleClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer)
197 IOCS *This = IFACE2THIS(iface);
198 FIXME( "(%p, %p)\n", This, ppContainer );
199 return E_NOTIMPL;
201 static HRESULT WINAPI OleClientSite_ShowObject(IOleClientSite *iface)
203 IOCS *This = IFACE2THIS(iface);
204 FIXME( "(%p) - stub\n", This );
205 return S_OK;
207 static HRESULT WINAPI OleClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow)
209 IOCS *This = IFACE2THIS(iface);
210 FIXME( "(%p, %s) - stub\n", This, fShow ? "TRUE" : "FALSE" );
211 return E_NOTIMPL;
213 static HRESULT WINAPI OleClientSite_RequestNewObjectLayout(IOleClientSite *iface)
215 IOCS *This = IFACE2THIS(iface);
216 FIXME( "(%p) - stub\n", This );
217 return E_NOTIMPL;
219 #undef IFACE2THIS
223 static const IOleClientSiteVtbl OleClientSite_vtbl = {
224 OleClientSite_QueryInterface,
225 OleClientSite_AddRef,
226 OleClientSite_Release,
227 OleClientSite_SaveObject,
228 OleClientSite_GetMoniker,
229 OleClientSite_GetContainer,
230 OleClientSite_ShowObject,
231 OleClientSite_OnShowWindow,
232 OleClientSite_RequestNewObjectLayout
235 static HRESULT IOCS_Detach( IOCS *This ) /* remove subclassing */
237 if ( This->hWnd )
239 SetWindowLongPtrW( This->hWnd, GWLP_WNDPROC, (ULONG_PTR) This->OrigWndProc );
240 SetWindowLongPtrW( This->hWnd, GWLP_USERDATA, (LONG_PTR) NULL );
241 This->hWnd = NULL;
243 if ( This->control )
245 IOleObject *control = This->control;
247 This->control = NULL;
248 IOleObject_SetClientSite( control, NULL );
249 IOleObject_Release( control );
251 return S_OK;
254 static void IOCS_OnSize( IOCS* This, LPCRECT rect )
256 SIZEL inPix, inHi;
258 if ( !This->control )
259 return;
261 inPix.cx = rect->right - rect->left;
262 inPix.cy = rect->bottom - rect->top;
263 AtlPixelToHiMetric( &inPix, &inHi );
264 IOleObject_SetExtent( This->control, DVASPECT_CONTENT, &inHi );
267 static LRESULT IOCS_OnWndProc( IOCS *This, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
269 WNDPROC OrigWndProc = This->OrigWndProc;
271 switch( uMsg )
273 case WM_DESTROY:
274 IOCS_Detach( This );
275 break;
276 case WM_SIZE:
278 RECT r;
279 r.left = r.top = 0;
280 r.right = LOWORD( lParam );
281 r.bottom = HIWORD( lParam );
282 IOCS_OnSize( This, &r );
284 break;
287 return OrigWndProc( hWnd, uMsg, wParam, lParam );
290 static LRESULT CALLBACK AtlHost_wndproc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
292 IOCS *This = (IOCS*) GetWindowLongPtrW( hWnd, GWLP_USERDATA );
293 return IOCS_OnWndProc( This, hWnd, wMsg, wParam, lParam );
296 static HRESULT IOCS_Attach( IOCS *This, HWND hWnd, IUnknown *pUnkControl ) /* subclass hWnd */
298 This->hWnd = hWnd;
299 IUnknown_QueryInterface( pUnkControl, &IID_IOleObject, (void**)&This->control );
300 IOleObject_SetClientSite( This->control, THIS2IOLECLIENTSITE( This ) );
301 This->OrigWndProc = (WNDPROC) GetWindowLongPtrW( This->hWnd, GWLP_WNDPROC );
302 SetWindowLongPtrW( hWnd, GWLP_USERDATA, (ULONG_PTR) This );
303 SetWindowLongPtrW( hWnd, GWLP_WNDPROC, (ULONG_PTR) AtlHost_wndproc );
305 return S_OK;
308 static HRESULT IOCS_Init( IOCS *This )
310 RECT rect;
311 static const WCHAR AXWIN[] = {'A','X','W','I','N',0};
313 IOleObject_SetHostNames( This->control, AXWIN, AXWIN );
315 GetClientRect( This->hWnd, &rect );
316 IOCS_OnSize( This, &rect );
318 return S_OK;
321 /**********************************************************************
322 * Create new instance of Atl host component and attach it to window *
324 static HRESULT IOCS_Create( HWND hWnd, IUnknown *pUnkControl, IOCS **ppSite )
326 HRESULT hr;
327 IOCS *This;
329 *ppSite = NULL;
330 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IOCS));
332 if (!This)
333 return E_OUTOFMEMORY;
335 This->lpOleClientSiteVtbl = &OleClientSite_vtbl;
336 This->ref = 1;
338 This->OrigWndProc = NULL;
339 This->hWnd = NULL;
341 hr = IOCS_Attach( This, hWnd, pUnkControl );
342 if ( SUCCEEDED( hr ) )
343 hr = IOCS_Init( This );
344 if ( SUCCEEDED( hr ) )
345 *ppSite = This;
346 else
347 IOCS_Release( This );
349 return hr;
353 /***********************************************************************
354 * AtlAxCreateControl [ATL.@]
356 HRESULT WINAPI AtlAxCreateControl(LPCOLESTR lpszName, HWND hWnd,
357 IStream *pStream, IUnknown **ppUnkContainer)
359 return AtlAxCreateControlEx( lpszName, hWnd, pStream, ppUnkContainer,
360 NULL, NULL, NULL );
363 /***********************************************************************
364 * AtlAxCreateControlEx [ATL.@]
366 * REMARKS
367 * See http://www.codeproject.com/com/cwebpage.asp for some background
370 HRESULT WINAPI AtlAxCreateControlEx(LPCOLESTR lpszName, HWND hWnd,
371 IStream *pStream, IUnknown **ppUnkContainer, IUnknown **ppUnkControl,
372 REFIID iidSink, IUnknown *punkSink)
374 CLSID controlId;
375 HRESULT hRes;
376 IOleObject *pControl;
377 IUnknown *pUnkControl;
378 IPersistStreamInit *pPSInit;
379 IUnknown *pContainer;
380 enum {IsGUID=0,IsHTML=1,IsURL=2} content;
382 TRACE("(%s %p %p %p %p %p %p)\n", debugstr_w(lpszName), hWnd, pStream,
383 ppUnkContainer, ppUnkControl, iidSink, punkSink);
385 hRes = CLSIDFromString( (LPOLESTR) lpszName, &controlId );
386 if ( FAILED(hRes) )
387 hRes = CLSIDFromProgID( lpszName, &controlId );
388 if ( SUCCEEDED( hRes ) )
389 content = IsGUID;
390 else {
391 /* FIXME - check for MSHTML: prefix! */
392 content = IsURL;
393 memcpy( &controlId, &CLSID_WebBrowser, sizeof(controlId) );
396 hRes = CoCreateInstance( &controlId, 0, CLSCTX_ALL, &IID_IOleObject,
397 (void**) &pControl );
398 if ( FAILED( hRes ) )
400 WARN( "cannot create ActiveX control %s instance - error 0x%08x\n",
401 debugstr_guid( &controlId ), hRes );
402 return hRes;
405 hRes = IOleObject_QueryInterface( pControl, &IID_IPersistStreamInit, (void**) &pPSInit );
406 if ( SUCCEEDED( hRes ) )
408 if (!pStream)
409 IPersistStreamInit_InitNew( pPSInit );
410 else
411 IPersistStreamInit_Load( pPSInit, pStream );
412 IPersistStreamInit_Release( pPSInit );
413 } else
414 WARN("cannot get IID_IPersistStreamInit out of control\n");
416 IOleObject_QueryInterface( pControl, &IID_IUnknown, (void**) &pUnkControl );
417 IOleObject_Release( pControl );
420 hRes = AtlAxAttachControl( pUnkControl, hWnd, &pContainer );
421 if ( FAILED( hRes ) )
422 WARN("cannot attach control to window\n");
424 if ( content == IsURL )
426 IWebBrowser2 *browser;
428 hRes = IOleObject_QueryInterface( pControl, &IID_IWebBrowser2, (void**) &browser );
429 if ( !browser )
430 WARN( "Cannot query IWebBrowser2 interface: %08x\n", hRes );
431 else {
432 VARIANT url;
434 IWebBrowser2_put_Visible( browser, VARIANT_TRUE ); /* it seems that native does this on URL (but do not on MSHTML:! why? */
436 V_VT(&url) = VT_BSTR;
437 V_BSTR(&url) = SysAllocString( lpszName );
439 hRes = IWebBrowser2_Navigate2( browser, &url, NULL, NULL, NULL, NULL );
440 if ( FAILED( hRes ) )
441 WARN( "IWebBrowser2::Navigate2 failed: %08x\n", hRes );
442 SysFreeString( V_BSTR(&url) );
444 IWebBrowser2_Release( browser );
448 if (ppUnkContainer)
450 *ppUnkContainer = pContainer;
451 if ( pContainer )
452 IUnknown_AddRef( pContainer );
454 if (ppUnkControl)
456 *ppUnkControl = pUnkControl;
457 if ( pUnkControl )
458 IUnknown_AddRef( pUnkControl );
461 IUnknown_Release( pUnkControl );
462 if ( pContainer )
463 IUnknown_Release( pContainer );
465 return S_OK;
468 /***********************************************************************
469 * AtlAxAttachControl [ATL.@]
471 HRESULT WINAPI AtlAxAttachControl(IUnknown* pControl, HWND hWnd, IUnknown** ppUnkContainer)
473 FIXME( "(%p %p %p) - stub\n", pControl, hWnd, ppUnkContainer );
474 return E_NOTIMPL;
477 /**********************************************************************
478 * Helper function for AX_ConvertDialogTemplate
480 static inline BOOL advance_array(WORD **pptr, DWORD *palloc, DWORD *pfilled, const WORD *data, DWORD size)
482 if ( (*pfilled + size) > *palloc )
484 *palloc = ((*pfilled+size) + 0xFF) & ~0xFF;
485 *pptr = HeapReAlloc( GetProcessHeap(), 0, *pptr, *palloc * sizeof(WORD) );
486 if (!*pptr)
487 return FALSE;
489 RtlMoveMemory( *pptr+*pfilled, data, size * sizeof(WORD) );
490 *pfilled += size;
491 return TRUE;
494 /**********************************************************************
495 * Convert ActiveX control templates to AtlAxWin class instances
497 static LPDLGTEMPLATEW AX_ConvertDialogTemplate(LPCDLGTEMPLATEW src_tmpl)
499 #define GET_WORD(x) (*(const WORD *)(x))
500 #define GET_DWORD(x) (*(const DWORD *)(x))
501 #define PUT_BLOCK(x,y) do {if (!advance_array(&output, &allocated, &filled, (x), (y))) return NULL;} while (0)
502 #define PUT_WORD(x) do {WORD w = (x);PUT_BLOCK(&w, 1);} while(0)
503 #define PUT_DWORD(x) do {DWORD w = (x);PUT_BLOCK(&w, 2);} while(0)
504 const WORD *tmp, *src = (const WORD *)src_tmpl;
505 WORD *output;
506 DWORD allocated, filled; /* in WORDs */
507 BOOL ext;
508 WORD signature, dlgver, rescount;
509 DWORD style;
511 filled = 0; allocated = 256;
512 output = HeapAlloc( GetProcessHeap(), 0, allocated * sizeof(WORD) );
513 if (!output)
514 return NULL;
516 /* header */
517 tmp = src;
518 signature = GET_WORD(src);
519 dlgver = GET_WORD(src + 1);
520 if (signature == 1 && dlgver == 0xFFFF)
522 ext = TRUE;
523 src += 6;
524 style = GET_DWORD(src);
525 src += 2;
526 rescount = GET_WORD(src++);
527 src += 4;
528 if ( GET_WORD(src) == 0xFFFF ) /* menu */
529 src += 2;
530 else
531 src += strlenW(src) + 1;
532 if ( GET_WORD(src) == 0xFFFF ) /* class */
533 src += 2;
534 else
535 src += strlenW(src) + 1;
536 src += strlenW(src) + 1; /* title */
537 if ( style & (DS_SETFONT | DS_SHELLFONT) )
539 src += 3;
540 src += strlenW(src) + 1;
542 } else {
543 ext = FALSE;
544 style = GET_DWORD(src);
545 src += 4;
546 rescount = GET_WORD(src++);
547 src += 4;
548 if ( GET_WORD(src) == 0xFFFF ) /* menu */
549 src += 2;
550 else
551 src += strlenW(src) + 1;
552 if ( GET_WORD(src) == 0xFFFF ) /* class */
553 src += 2;
554 else
555 src += strlenW(src) + 1;
556 src += strlenW(src) + 1; /* title */
557 if ( style & DS_SETFONT )
559 src++;
560 src += strlenW(src) + 1;
563 PUT_BLOCK(tmp, src-tmp);
565 while(rescount--)
567 src = (const WORD *)( ( ((ULONG)src) + 3) & ~3); /* align on DWORD boundary */
568 filled = (filled + 1) & ~1; /* depends on DWORD-aligned allocation unit */
570 tmp = src;
571 if (ext)
572 src += 11;
573 else
574 src += 9;
575 PUT_BLOCK(tmp, src-tmp);
577 tmp = src;
578 if ( GET_WORD(src) == 0xFFFF ) /* class */
580 src += 2;
581 } else
583 src += strlenW(src) + 1;
585 src += strlenW(src) + 1; /* title */
586 if ( GET_WORD(tmp) == '{' ) /* all this mess created because of this line */
588 const WCHAR AtlAxWin[9]={'A','t','l','A','x','W','i','n',0};
589 PUT_BLOCK(AtlAxWin, sizeof(AtlAxWin)/sizeof(WORD));
590 PUT_BLOCK(tmp, strlenW(tmp)+1);
591 } else
592 PUT_BLOCK(tmp, src-tmp);
594 if ( GET_WORD(src) )
596 WORD size = (GET_WORD(src)+sizeof(WORD)-1) / sizeof(WORD); /* quite ugly :( Maybe use BYTE* instead of WORD* everywhere ? */
597 PUT_BLOCK(src, size);
598 src+=size;
600 else
602 PUT_WORD(0);
603 src++;
606 return (LPDLGTEMPLATEW) output;
609 /***********************************************************************
610 * AtlAxCreateDialogA [ATL.@]
612 * Creates a dialog window
614 * PARAMS
615 * hInst [I] Application instance
616 * name [I] Dialog box template name
617 * owner [I] Dialog box parent HWND
618 * dlgProc [I] Dialog box procedure
619 * param [I] This value will be passed to dlgProc as WM_INITDIALOG's message lParam
621 * RETURNS
622 * Window handle of dialog window.
624 HWND WINAPI AtlAxCreateDialogA(HINSTANCE hInst, LPCSTR name, HWND owner, DLGPROC dlgProc ,LPARAM param)
626 HWND res = NULL;
627 int length;
628 WCHAR *nameW;
630 if ( HIWORD(name) == 0 )
631 return AtlAxCreateDialogW( hInst, (LPCWSTR) name, owner, dlgProc, param );
633 length = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
634 nameW = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) );
635 if (nameW)
637 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, length );
638 res = AtlAxCreateDialogW( hInst, nameW, owner, dlgProc, param );
639 HeapFree( GetProcessHeap(), 0, nameW );
641 return res;
644 /***********************************************************************
645 * AtlAxCreateDialogW [ATL.@]
647 * See AtlAxCreateDialogA
650 HWND WINAPI AtlAxCreateDialogW(HINSTANCE hInst, LPCWSTR name, HWND owner, DLGPROC dlgProc ,LPARAM param)
652 HRSRC hrsrc;
653 HGLOBAL hgl;
654 LPCDLGTEMPLATEW ptr;
655 LPDLGTEMPLATEW newptr;
656 HWND res;
658 FIXME("(%p %s %p %p %lx) - not tested\n", hInst, debugstr_w(name), owner, dlgProc, param);
660 hrsrc = FindResourceW( hInst, name, (LPWSTR)RT_DIALOG );
661 if ( !hrsrc )
662 return NULL;
663 hgl = LoadResource (hInst, hrsrc);
664 if ( !hgl )
665 return NULL;
666 ptr = (LPCDLGTEMPLATEW)LockResource ( hgl );
667 if (!ptr)
669 FreeResource( hgl );
670 return NULL;
672 newptr = AX_ConvertDialogTemplate( ptr );
673 if ( newptr )
675 res = CreateDialogIndirectParamW( hInst, newptr, owner, dlgProc, param );
676 HeapFree( GetProcessHeap(), 0, newptr );
677 } else
678 res = NULL;
679 FreeResource ( hrsrc );
680 return res;