// D3D.h : Declaration of the CDirect3D // // This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #include #include "resource.h" // main symbols #include "D3DWnd.h" ////////////////////////////////////////////////////////////////////////////////////////////////// // CTimer template class CTimer { public: CTimer() { m_bTimerOn = FALSE; } HRESULT TimerOn(DWORD dwTimerInterval) { Derived* pDerived = ((Derived*)this); m_dwTimerInterval = dwTimerInterval; if (m_bTimerOn) // already on, just change interval return S_OK; m_bTimerOn = TRUE; m_dwTimerInterval = dwTimerInterval; m_pStream = NULL; HRESULT hRes; hRes = CoMarshalInterThreadInterfaceInStream(*piid, (T*)pDerived, &m_pStream); // Create thread and pass the thread proc the this ptr m_hThread = CreateThread(NULL, 0, &_Apartment, (void*)this, 0, &m_dwThreadID); return S_OK; } void TimerOff() { if (m_bTimerOn) { m_bTimerOn = FALSE; AtlWaitWithMessageLoop(m_hThread); } } // Implementation private: static DWORD WINAPI _Apartment(void* pv) { CTimer* pThis = (CTimer*) pv; pThis->Apartment(); return 0; } DWORD Apartment() { CoInitialize(NULL); HRESULT hRes; m_spT.Release(); if (m_pStream) hRes = CoGetInterfaceAndReleaseStream(m_pStream, *piid, (void**)&m_spT); while(m_bTimerOn) { Sleep(m_dwTimerInterval); if (!m_bTimerOn) break; m_spT->DisplayScene(); } m_spT.Release(); CoUninitialize(); return 0; } // Attributes public: DWORD m_dwTimerInterval; // Implementation private: HANDLE m_hThread; DWORD m_dwThreadID; LPSTREAM m_pStream; CComPtr m_spT; BOOL m_bTimerOn; }; ///////////////////////////////////////////////////////////////////////////// // CDirect3D class CDirect3D : public CComObjectRoot, public CComCoClass, public CComControl, public CTimer, public IDispatchImpl, public IPersistStreamInitImpl, public IPersistStorageImpl, public IQuickActivateImpl, public IProvideClassInfo2Impl<&CLSID_CDirect3DCtl, NULL, &LIBID_DIRECT3DLib>, public IOleControlImpl, public IOleObjectImpl, public IOleInPlaceActiveObjectImpl, public IViewObjectExImpl, public IOleInPlaceObjectWindowlessImpl, public IDataObjectImpl, public IObjectSafetyImpl, public ISupportErrorInfo { public: CDirect3D() { m_hOurWnd = NULL; m_p3DWindow = NULL; m_dwSafety = 0; } ~CDirect3D() { // Stop, if we haven't stopped already if (m_p3DWindow) Stop3D(); } DECLARE_REGISTRY_RESOURCEID(IDR_Direct3D) DECLARE_GET_CONTROLLING_UNKNOWN() BEGIN_COM_MAP(CDirect3D) COM_INTERFACE_ENTRY(IDirect3DCtl) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY_IMPL(IViewObjectEx) COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject2, IViewObjectEx) COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject, IViewObjectEx) COM_INTERFACE_ENTRY_IMPL(IOleInPlaceObjectWindowless) COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleInPlaceObject, IOleInPlaceObjectWindowless) COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleWindow, IOleInPlaceObjectWindowless) COM_INTERFACE_ENTRY_IMPL(IOleInPlaceActiveObject) COM_INTERFACE_ENTRY_IMPL(IOleControl) COM_INTERFACE_ENTRY_IMPL(IOleObject) COM_INTERFACE_ENTRY_IMPL(IQuickActivate) COM_INTERFACE_ENTRY_IMPL(IPersistStorage) COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit) COM_INTERFACE_ENTRY_IMPL(IDataObject) COM_INTERFACE_ENTRY(IObjectSafety) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2) COM_INTERFACE_ENTRY(ISupportErrorInfo) END_COM_MAP() BEGIN_MSG_MAP(CDirect3D) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) END_MSG_MAP() BEGIN_PROPERTY_MAP(CDirect3D) END_PROPERTY_MAP() // ISupportsErrorInfo STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); STDMETHOD(OnFrameWindowActivate)(BOOL fActivate) { ATLTRACE(_T("OnFrameWindowActivate\n")); if (fActivate && m_p3DWindow) m_p3DWindow->SetPalette(); return S_OK; } // IDirect3DCtl public: // Implementation public: // The drawing is done through CDirect3DWindow, so we need // to do nothing here. LRESULT OnEraseBackground(UINT, WPARAM, LPARAM, BOOL& bHandled) { return 0; } LRESULT OnLButtonDown(UINT, WPARAM, LPARAM, BOOL& bHandled) { m_p3DWindow->SetPalette(); return 0; } HRESULT OnDraw(ATL_DRAWINFO&) { // We're not doing any drawing using GDI, so there is nothing to do here. // We still need to have this function so we don't bring in the default ATL // drawing code. return TRUE; } HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL) { HRESULT hr; hr = CComControlBase::InPlaceActivate(iVerb, prcPosRect); if (!m_p3DWindow) // Start if we haven't started yet Start3D(); return hr; } STDMETHOD(InPlaceDeactivate)(void) { if (m_p3DWindow) Stop3D(); return IOleInPlaceObjectWindowlessImpl::InPlaceDeactivate(); } STDMETHOD(Start3D)() { // Find out what window we need to use GetOurWindow(); // If we haven't got a window yet, then there's nothing we can do if (m_hOurWnd == NULL) return E_FAIL; m_p3DWindow = new CDirect3DWindow; if (!m_p3DWindow) { return E_OUTOFMEMORY; } RECT rcInitialPos = m_rcPos; RectToDesktop(&rcInitialPos); HRESULT hr = m_p3DWindow->OnCreate(m_hOurWnd, rcInitialPos); // The OnSize method creates the initial scene if (SUCCEEDED(hr)) m_p3DWindow->OnSize(m_hOurWnd, m_rcPos.right-m_rcPos.left, m_rcPos.bottom-m_rcPos.top); TimerOn(5); return hr; } STDMETHOD(Stop3D)() { TimerOff(); delete m_p3DWindow; m_p3DWindow = NULL; return S_OK; } STDMETHOD(SetObjectRects)(LPCRECT prcPos,LPCRECT prcClip) { if (prcPos == NULL) { // I've seen VB5 send this ATLTRACE(_T("WARNING: SetObjects called with NULL prcPos\n")); return S_OK; } HRESULT hr = IOleInPlaceObjectWindowlessImpl::SetObjectRects(prcPos, prcClip); return hr; } STDMETHOD(DisplayScene)() { if (m_p3DWindow) { // m_p3DWindow->SetPalette(); m_p3DWindow->TickScene(); Draw3DWindow(); } return S_OK; } private: void Draw3DWindow() { static RECT rcOldPos; if (m_p3DWindow) { RECT rcPos = m_rcPos; RectToDesktop(&rcPos); // Has the size changed if ((rcPos.right-rcPos.left != rcOldPos.right-rcOldPos.left) || (rcPos.bottom-rcPos.top != rcOldPos.bottom-rcOldPos.top)) { ATLTRACE(_T("Draw(%d,%d,%d,%d)\n"),rcPos.left,rcPos.top,rcPos.right,rcPos.bottom); m_p3DWindow->OnSize(m_hOurWnd, m_rcPos.right-m_rcPos.left, m_rcPos.bottom-m_rcPos.top); ATLTRACE(_T("EndDraw\n")); } // Has it moved if (rcPos.left!=rcOldPos.left || rcPos.top!=rcOldPos.top) m_p3DWindow->OnMove(m_hOurWnd, rcPos.left, rcPos.top); rcOldPos = rcPos; m_p3DWindow->DoFrame(); } } // Get the window we need to use. This will either be the window that has already // been created if we are window. If we are windowless the HWND of the client // will be retrieved from the HDC. void GetOurWindow() { // If we're windowless we still need an HWND for Direct3d if (m_bWndLess) { HDC hDC; // Get the HDC from the client m_spInPlaceSite->GetDC(NULL, OLEDC_NODRAW, &hDC); m_hOurWnd = WindowFromDC(hDC); #if 1 // Code to make VB5 paint properly now it has clipped it's own hDC RECT rect; ::GetClientRect(m_hOurWnd,&rect); HRGN hRegion = CreateRectRgn(rect.left,rect.top,rect.right,rect.bottom); SelectClipRgn(hDC,hRegion); #endif m_spInPlaceSite->ReleaseDC(hDC); } else m_hOurWnd = m_hWnd; } // Convert RECT so that it is relative to the desktop. void RectToDesktop(RECT* pRect) { POINT pt; pt.x = 0; pt.y = 0; ::ClientToScreen(m_hOurWnd, &pt); if (m_bWndLess) ::OffsetRect(pRect, pt.x, pt.y); else // If we're not windowless, cater for the fact that pRect will not necessarily be at (0,0) ::OffsetRect(pRect, pt.x-pRect->left, pt.y-pRect->top); } HWND m_hOurWnd; CDirect3DWindow* m_p3DWindow; // Pointer to Direct3D window if we have one DWORD m_dwSafety; // Current safety settings };