1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include	"StdAfx.h"
19
20#include	"comutil.h"
21#include	"ShObjIdl.h"
22
23#include	"DebugServices.h"
24
25#include	"Resource.h"
26
27#include	"ExplorerBar.h"
28
29#include	"About.h"
30// MFC Debugging
31
32#ifdef _DEBUG
33#define new DEBUG_NEW
34#undef THIS_FILE
35static char THIS_FILE[] = __FILE__;
36#endif
37
38//===========================================================================================================================
39//	Constants
40//===========================================================================================================================
41#define LENGTHOF(a) (sizeof(a) == sizeof(&*a)) ? 0 : (sizeof(a) / sizeof(*a))
42#define MIN_SIZE_X		10
43#define MIN_SIZE_Y		10
44
45//===========================================================================================================================
46//	ExplorerBar
47//===========================================================================================================================
48
49ExplorerBar::ExplorerBar( void )
50{
51	++gDLLRefCount;
52
53	mRefCount		= 1;
54	mSite 			= NULL;
55	mWebBrowser		= NULL;
56	mParentWindow	= NULL;
57	mFocus			= FALSE;
58	mViewMode		= 0;
59	mBandID			= 0;
60}
61
62//===========================================================================================================================
63//	~ExplorerBar
64//===========================================================================================================================
65
66ExplorerBar::~ExplorerBar( void )
67{
68	if( mWebBrowser )
69	{
70		mWebBrowser->Release();
71		mWebBrowser = NULL;
72	}
73	if( mSite )
74	{
75		mSite->Release();
76		mSite = NULL;
77	}
78
79	--gDLLRefCount;
80}
81
82#if 0
83#pragma mark -
84#pragma mark == IUnknown implementation ==
85#endif
86
87//===========================================================================================================================
88//	QueryInterface
89//===========================================================================================================================
90
91STDMETHODIMP	ExplorerBar::QueryInterface( REFIID inID, LPVOID *outResult )
92{
93	HRESULT		err;
94
95	if( IsEqualIID( inID, IID_IUnknown ) )				// IUnknown
96	{
97		*outResult = this;
98	}
99	else if( IsEqualIID( inID, IID_IOleWindow ) )		// IOleWindow
100	{
101		*outResult = (IOleWindow *) this;
102	}
103	else if( IsEqualIID( inID, IID_IDockingWindow ) )	// IDockingWindow
104	{
105		*outResult = (IDockingWindow *) this;
106	}
107	else if( IsEqualIID( inID, IID_IDeskBand ) )		// IDeskBand
108	{
109		*outResult = (IDeskBand *) this;
110	}
111	else if( IsEqualIID( inID, IID_IInputObject ) )		// IInputObject
112	{
113		*outResult = (IInputObject *) this;
114	}
115	else if( IsEqualIID( inID, IID_IObjectWithSite ) )	// IObjectWithSite
116	{
117		*outResult = (IObjectWithSite *) this;
118	}
119	else if( IsEqualIID( inID, IID_IPersistStream ) )	// IPersistStream
120	{
121		*outResult = (IPersistStream *) this;
122	}
123	else if( IsEqualIID( inID, IID_IContextMenu ) )     // IContextMenu
124	{
125		*outResult = (IContextMenu *) this;
126	}
127	else
128	{
129		*outResult = NULL;
130		err = E_NOINTERFACE;
131		goto exit;
132	}
133
134	( *( (LPUNKNOWN *) outResult ) )->AddRef();
135	err = S_OK;
136
137exit:
138	return( err );
139}
140
141//===========================================================================================================================
142//	AddRef
143//===========================================================================================================================
144
145STDMETHODIMP_( DWORD )	ExplorerBar::AddRef( void )
146{
147	return( ++mRefCount );
148}
149
150//===========================================================================================================================
151//	Release
152//===========================================================================================================================
153
154STDMETHODIMP_( DWORD )	ExplorerBar::Release( void )
155{
156	DWORD		count;
157
158	count = --mRefCount;
159	if( count == 0 )
160	{
161		delete this;
162	}
163	return( count );
164}
165
166#if 0
167#pragma mark -
168#pragma mark == IOleWindow implementation ==
169#endif
170
171//===========================================================================================================================
172//	GetWindow
173//===========================================================================================================================
174
175STDMETHODIMP	ExplorerBar::GetWindow( HWND *outWindow )
176{
177	*outWindow = mWindow.GetSafeHwnd();
178	return( S_OK );
179}
180
181//===========================================================================================================================
182//	ContextSensitiveHelp
183//===========================================================================================================================
184
185STDMETHODIMP	ExplorerBar::ContextSensitiveHelp( BOOL inEnterMode )
186{
187	DEBUG_UNUSED( inEnterMode );
188
189	return( E_NOTIMPL );
190}
191
192#if 0
193#pragma mark -
194#pragma mark == IDockingWindow implementation ==
195#endif
196
197//===========================================================================================================================
198//	ShowDW
199//===========================================================================================================================
200
201STDMETHODIMP	ExplorerBar::ShowDW( BOOL inShow )
202{
203	if( mWindow.GetSafeHwnd() )
204	{
205		mWindow.ShowWindow( inShow ? SW_SHOW : SW_HIDE );
206	}
207	return( S_OK );
208}
209
210//===========================================================================================================================
211//	CloseDW
212//===========================================================================================================================
213
214STDMETHODIMP	ExplorerBar::CloseDW( DWORD inReserved )
215{
216	DEBUG_UNUSED( inReserved );
217
218	ShowDW( FALSE );
219	if( mWindow.GetSafeHwnd() )
220	{
221		mWindow.SendMessage( WM_CLOSE );
222	}
223	return( S_OK );
224}
225
226//===========================================================================================================================
227//	ResizeBorderDW
228//===========================================================================================================================
229
230STDMETHODIMP	ExplorerBar::ResizeBorderDW( LPCRECT inBorder, IUnknown *inPunkSite, BOOL inReserved )
231{
232	DEBUG_UNUSED( inBorder );
233	DEBUG_UNUSED( inPunkSite );
234	DEBUG_UNUSED( inReserved );
235
236	return( E_NOTIMPL );
237}
238
239#if 0
240#pragma mark -
241#pragma mark == IDeskBand implementation ==
242#endif
243
244//===========================================================================================================================
245//	GetBandInfo
246//===========================================================================================================================
247
248STDMETHODIMP	ExplorerBar::GetBandInfo( DWORD inBandID, DWORD inViewMode, DESKBANDINFO *outInfo )
249{
250	HRESULT		err;
251
252	require_action( outInfo, exit, err = E_INVALIDARG );
253
254	mBandID   = inBandID;
255	mViewMode = inViewMode;
256
257	if( outInfo->dwMask & DBIM_MINSIZE )
258	{
259		outInfo->ptMinSize.x = 100;
260		outInfo->ptMinSize.y = 100;
261	}
262	if( outInfo->dwMask & DBIM_MAXSIZE )
263	{
264		// Unlimited max size.
265
266		outInfo->ptMaxSize.x = -1;
267		outInfo->ptMaxSize.y = -1;
268	}
269	if( outInfo->dwMask & DBIM_INTEGRAL )
270	{
271		outInfo->ptIntegral.x = 1;
272		outInfo->ptIntegral.y = 1;
273	}
274	if( outInfo->dwMask & DBIM_ACTUAL )
275	{
276		outInfo->ptActual.x = 0;
277		outInfo->ptActual.y = 0;
278	}
279	if( outInfo->dwMask & DBIM_TITLE )
280	{
281		CString		s;
282		BOOL		ok;
283
284		ok = s.LoadString( IDS_NAME );
285		require_action( ok, exit, err = kNoResourcesErr );
286
287		#ifdef UNICODE
288			lstrcpyn( outInfo->wszTitle, s, sizeof_array( outInfo->wszTitle ) );
289		#else
290			DWORD		nChars;
291
292			nChars = MultiByteToWideChar( CP_ACP, 0, s, -1, outInfo->wszTitle, sizeof_array( outInfo->wszTitle ) );
293			err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
294			require_noerr( err, exit );
295		#endif
296	}
297	if( outInfo->dwMask & DBIM_MODEFLAGS )
298	{
299		outInfo->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
300	}
301
302	// Force the default background color.
303
304	outInfo->dwMask &= ~DBIM_BKCOLOR;
305	err = S_OK;
306
307exit:
308	return( err );
309}
310
311#if 0
312#pragma mark -
313#pragma mark == IInputObject implementation ==
314#endif
315
316//===========================================================================================================================
317//	UIActivateIO
318//===========================================================================================================================
319
320STDMETHODIMP	ExplorerBar::UIActivateIO( BOOL inActivate, LPMSG inMsg )
321{
322	DEBUG_UNUSED( inMsg );
323
324	if( inActivate )
325	{
326		mWindow.SetFocus();
327	}
328	return( S_OK );
329}
330
331//===========================================================================================================================
332//	HasFocusIO
333//===========================================================================================================================
334
335STDMETHODIMP	ExplorerBar::HasFocusIO( void )
336{
337	if( mWindow.GetFocus()->GetSafeHwnd() == mWindow.GetSafeHwnd() )
338	{
339		return( S_OK );
340	}
341	return( S_FALSE );
342}
343
344//===========================================================================================================================
345//	TranslateAcceleratorIO
346//===========================================================================================================================
347
348STDMETHODIMP	ExplorerBar::TranslateAcceleratorIO( LPMSG inMsg )
349{
350	DEBUG_UNUSED( inMsg );
351
352	return( S_FALSE );
353}
354
355#if 0
356#pragma mark -
357#pragma mark == IObjectWithSite implementation ==
358#endif
359
360//===========================================================================================================================
361//	SetSite
362//===========================================================================================================================
363
364STDMETHODIMP	ExplorerBar::SetSite( IUnknown *inPunkSite )
365{
366	AFX_MANAGE_STATE( AfxGetStaticModuleState() );
367
368	HRESULT		err;
369
370	// Release the old interfaces.
371
372	if( mWebBrowser )
373	{
374		mWebBrowser->Release();
375		mWebBrowser = NULL;
376	}
377	if( mSite )
378	{
379		mSite->Release();
380		mSite = NULL;
381	}
382
383	// A non-NULL site means we're setting the site. Otherwise, the site is being released (done above).
384
385	if( !inPunkSite )
386	{
387		err = S_OK;
388		goto exit;
389	}
390
391	// Get the parent window.
392
393	IOleWindow *		oleWindow;
394
395	mParentWindow = NULL;
396	err = inPunkSite->QueryInterface( IID_IOleWindow, (LPVOID *) &oleWindow );
397	require( SUCCEEDED( err ), exit );
398
399	err = oleWindow->GetWindow( &mParentWindow );
400	oleWindow->Release();
401	require_noerr( err, exit );
402	require_action( mParentWindow, exit, err = E_FAIL );
403
404	// Get the IInputObject interface.
405
406	err = inPunkSite->QueryInterface( IID_IInputObjectSite, (LPVOID *) &mSite );
407	require( SUCCEEDED( err ), exit );
408	check( mSite );
409
410	// Get the IWebBrowser2 interface.
411
412	IOleCommandTarget *		oleCommandTarget;
413
414	err = inPunkSite->QueryInterface( IID_IOleCommandTarget, (LPVOID *) &oleCommandTarget );
415	require( SUCCEEDED( err ), exit );
416
417	IServiceProvider *		serviceProvider;
418
419	err = oleCommandTarget->QueryInterface( IID_IServiceProvider, (LPVOID *) &serviceProvider );
420	oleCommandTarget->Release();
421	require( SUCCEEDED( err ), exit );
422
423	err = serviceProvider->QueryService( SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID *) &mWebBrowser );
424	serviceProvider->Release();
425	require( SUCCEEDED( err ), exit );
426
427	// Create the main window.
428
429	err = SetupWindow();
430	require_noerr( err, exit );
431
432exit:
433	return( err );
434}
435
436//===========================================================================================================================
437//	GetSite
438//===========================================================================================================================
439
440STDMETHODIMP	ExplorerBar::GetSite( REFIID inID, LPVOID *outResult )
441{
442	HRESULT		err;
443
444	*outResult = NULL;
445	require_action( mSite, exit, err = E_FAIL );
446
447	err = mSite->QueryInterface( inID, outResult );
448
449exit:
450	return( err );
451}
452
453#if 0
454#pragma mark -
455#pragma mark == IPersistStream implementation ==
456#endif
457
458//
459// IPersistStream implementation
460//
461// This is only supported to allow the desk band to be dropped on the desktop and to prevent multiple instances of
462// the desk band from showing up in the context menu. This desk band doesn't actually persist any data.
463//
464
465//===========================================================================================================================
466//	GetClassID
467//===========================================================================================================================
468
469STDMETHODIMP	ExplorerBar::GetClassID( LPCLSID outClassID )
470{
471	*outClassID = CLSID_ExplorerBar;
472	return( S_OK );
473}
474
475//===========================================================================================================================
476//	IsDirty
477//===========================================================================================================================
478
479STDMETHODIMP	ExplorerBar::IsDirty( void )
480{
481	return( S_FALSE );
482}
483
484//===========================================================================================================================
485//	Load
486//===========================================================================================================================
487
488STDMETHODIMP	ExplorerBar::Load( LPSTREAM inStream )
489{
490	DEBUG_UNUSED( inStream );
491
492	return( S_OK );
493}
494
495//===========================================================================================================================
496//	Save
497//===========================================================================================================================
498
499STDMETHODIMP	ExplorerBar::Save( LPSTREAM inStream, BOOL inClearDirty )
500{
501	DEBUG_UNUSED( inStream );
502	DEBUG_UNUSED( inClearDirty );
503
504	return( S_OK );
505}
506
507//===========================================================================================================================
508//	GetSizeMax
509//===========================================================================================================================
510
511STDMETHODIMP	ExplorerBar::GetSizeMax( ULARGE_INTEGER *outSizeMax )
512{
513	DEBUG_UNUSED( outSizeMax );
514
515	return( E_NOTIMPL );
516}
517
518
519//===========================================================================================================================
520//	QueryContextMenu
521//===========================================================================================================================
522
523STDMETHODIMP  ExplorerBar::QueryContextMenu(HMENU hShellContextMenu, UINT iContextMenuFirstItem, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
524{
525	DEBUG_UNUSED( idCmdLast );
526	DEBUG_UNUSED( uFlags );
527
528	CMenu menubar;
529
530	menubar.LoadMenu(IDR_CONTEXT_MENU);
531	CMenu * menu = menubar.GetSubMenu(0);
532
533	CMenu shellmenu;
534
535	shellmenu.Attach(hShellContextMenu);
536
537	UINT iShellItem = iContextMenuFirstItem;	//! remove plus one
538	UINT idShellCmd = idCmdFirst;
539
540	int n = menu->GetMenuItemCount();
541
542	for (int i=0; i<n; ++i)
543	{
544		MENUITEMINFO	mii;
545		TCHAR				sz[128] = {0};
546
547		ZeroMemory(&mii, sizeof(mii));
548		mii.fMask		= MIIM_TYPE | MIIM_ID;
549		mii.fType		= MFT_STRING;
550		mii.cbSize		= sizeof(mii);
551		mii.cch			= LENGTHOF(sz);
552		mii.dwTypeData	= sz;
553
554		menu->GetMenuItemInfo(i, &mii, TRUE);
555
556		mii.wID = idShellCmd++;
557
558		shellmenu.InsertMenuItem(iShellItem++, &mii, TRUE);
559	}
560
561	shellmenu.Detach();
562
563	return n;
564}
565
566
567//===========================================================================================================================
568//	GetCommandString
569//===========================================================================================================================
570
571// Not called for explorer bars
572STDMETHODIMP ExplorerBar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
573{
574	DEBUG_UNUSED( idCmd );
575	DEBUG_UNUSED( uType );
576	DEBUG_UNUSED( pwReserved );
577	DEBUG_UNUSED( pszName );
578	DEBUG_UNUSED( cchMax );
579
580	return E_NOTIMPL;
581}
582
583//===========================================================================================================================
584//	InvokeCommand
585//===========================================================================================================================
586
587//	The shell sends either strings or indexes
588//	IE never sends strings
589//	The indexes are into an array of my commands
590//	So the verb for the first command I added to the menu is always 0x0000
591//	Here - because I don't have any submenus -
592//		I can treat the 'verb' as an menu item position
593STDMETHODIMP ExplorerBar::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
594{
595	// IE doesn't send string commands
596	if (HIWORD(lpici->lpVerb) != 0) return 0;
597
598	CAbout dlg;
599
600	dlg.DoModal();
601
602	return S_OK;
603}
604
605#if 0
606#pragma mark -
607#pragma mark == Other ==
608#endif
609
610//===========================================================================================================================
611//	SetupWindow
612//===========================================================================================================================
613
614OSStatus	ExplorerBar::SetupWindow( void )
615{
616	OSStatus		err;
617	CWnd *			window;
618	CRect			rect;
619	CString			s;
620	BOOL			ok;
621
622	window = CWnd::FromHandle( mParentWindow );
623	check( window );
624	window->GetClientRect( rect );
625
626	ok = s.LoadString( IDS_NAME );
627	require_action( ok, exit, err = kNoResourcesErr );
628
629	ok = mWindow.Create( NULL, s, WS_CHILD | WS_VISIBLE, rect, window, 100 ) != 0;
630	require_action( ok, exit, err = kNoResourcesErr );
631
632	mWindow.SetOwner( this );
633	err = kNoErr;
634
635exit:
636	return( err );
637}
638
639//===========================================================================================================================
640//	GoToURL
641//===========================================================================================================================
642
643OSStatus	ExplorerBar::GoToURL( const CString &inURL )
644{
645	OSStatus		err;
646	BSTR			s;
647	VARIANT			empty;
648
649	s = inURL.AllocSysString();
650	require_action( s, exit, err = kNoMemoryErr );
651
652	VariantInit( &empty );
653	err = mWebBrowser->Navigate( s, &empty, &empty, &empty, &empty );
654	SysFreeString( s );
655	require_noerr( err, exit );
656
657exit:
658	return( err );
659}
660