561 lines
11 KiB
C++
561 lines
11 KiB
C++
#include "stdinc.h"
|
|
#include "local-stdinc.h"
|
|
#include "cduser.h"
|
|
#include "duser.h"
|
|
#include <stdio.h>
|
|
|
|
|
|
#define SAPW_DU_SET_PARENT_WINDOW ( WM_USER + 1 )
|
|
#define SAPW_DU_TEARDOWN_INSTANCE ( WM_USER + 2 )
|
|
#define SAPW_DU_NEXT_ROW ( WM_USER + 3 )
|
|
#define SAPW_DU_DRAW_REQUEST ( WM_USER + 4 )
|
|
|
|
|
|
class CRowObjectRowElement : public DirectUI::Element
|
|
{
|
|
IViewRow *m_pContainedColumns;
|
|
|
|
HRESULT ReCreateUI();
|
|
|
|
public:
|
|
CRowObjectRowElement();
|
|
~CRowObjectRowElement();
|
|
|
|
virtual HRESULT SetDatasource( IViewRow* );
|
|
virtual HRESULT Initialize();
|
|
};
|
|
|
|
CRowObjectRowElement::CRowObjectRowElement()
|
|
: m_pContainedColumns( NULL )
|
|
{
|
|
}
|
|
|
|
CRowObjectRowElement::~CRowObjectRowElement()
|
|
{
|
|
SetDatasource( NULL );
|
|
this->DestroyAll();
|
|
}
|
|
|
|
HRESULT
|
|
CRowObjectRowElement::SetDatasource( IViewRow* pRowSource )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if ( m_pContainedColumns != NULL )
|
|
{
|
|
m_pContainedColumns->Release();
|
|
m_pContainedColumns = NULL;
|
|
}
|
|
|
|
m_pContainedColumns = pRowSource;
|
|
|
|
if ( m_pContainedColumns != NULL )
|
|
{
|
|
hr = ReCreateUI();
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRowObjectRowElement::ReCreateUI()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DirectUI::Layout *OurLayout = NULL;
|
|
int iColumns = 0;
|
|
|
|
//
|
|
// Clear all stored UI first
|
|
//
|
|
this->DestroyAll();
|
|
|
|
//
|
|
// Construct the gridded layout of this object first
|
|
//
|
|
if ( FAILED( hr = m_pContainedColumns->get_Count( &iColumns ) ) )
|
|
goto Exit;
|
|
|
|
hr = DirectUI::GridLayout::Create( 1, iColumns, &OurLayout );
|
|
if ( FAILED( hr ) )
|
|
goto Exit;
|
|
|
|
//
|
|
// Then toss in a text label for each
|
|
//
|
|
for ( int i = 1; i <= iColumns; i++ )
|
|
{
|
|
DirectUI::Element *pElement = NULL;
|
|
BSTR bstTemp;
|
|
|
|
if ( FAILED( hr = DirectUI::Element::Create( 0, &pElement ) ) )
|
|
{
|
|
this->DestroyAll();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Get, copy, send, etc.
|
|
//
|
|
hr = this->m_pContainedColumns->get_Value( i, &bstTemp );
|
|
if ( SUCCEEDED( hr ) && ( bstTemp != NULL ) )
|
|
{
|
|
hr = pElement->SetContentString( bstTemp );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = this->Add( pElement );
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
}
|
|
|
|
SysFreeString( bstTemp );
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
if ( FAILED( hr ) )
|
|
{
|
|
this->DestroyAll();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRowObjectRowElement::Initialize()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if ( FAILED(hr = DirectUI::Element::Initialize(0)) )
|
|
return hr;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
CSxApwDUserView::CSxApwDUserView()
|
|
: m_hOurParentWnd( NULL ), m_hMasterElement( NULL ),
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
m_hThreadHandle( INVALID_HANDLE_VALUE ), m_dwThreadId( 0 ),
|
|
#endif
|
|
m_ulRefCount( 1 )
|
|
{
|
|
|
|
//
|
|
// Spin a thread for this object
|
|
//
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
m_hThreadGoing = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
|
|
m_hThreadHandle = CreateThread(
|
|
NULL,
|
|
0,
|
|
CSxApwDUserView::ThisViewThreadCallback,
|
|
this,
|
|
0,
|
|
&m_dwThreadId
|
|
);
|
|
|
|
ASSERT( m_hThreadHandle != INVALID_HANDLE_VALUE );
|
|
|
|
//
|
|
// We really do have to wait for the thread to get going
|
|
//
|
|
WaitForSingleObject( m_hThreadGoing, INFINITE );
|
|
CloseHandle( m_hThreadGoing );
|
|
#else
|
|
ASSERT( ConstructGadgets() );
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
CSxApwDUserView::~CSxApwDUserView()
|
|
{
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
ASSERT( m_hThreadHandle == INVALID_HANDLE_VALUE );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CSxApwDUserView::InternalCreateUI()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DirectUI::Value* pvLayout = NULL;
|
|
|
|
//
|
|
// No current UI, must have master window to start with.
|
|
//
|
|
ASSERT( m_hMasterElement == NULL );
|
|
ASSERT( m_hOurParentWnd != NULL );
|
|
|
|
//
|
|
// Create the directUI top-level Element object
|
|
//
|
|
hr = DirectUI::HWNDElement::Create( m_hOurParentWnd, true, 0, &this->m_hMasterElement );
|
|
if ( FAILED( hr ) )
|
|
goto Exit;
|
|
|
|
//
|
|
// Create this row-layout object so we can just toss things into it, then set the container
|
|
// as the host.
|
|
//
|
|
int __params[] = { -1, 0, 3 };
|
|
|
|
if ( FAILED( hr = DirectUI::RowLayout::Create( 3, __params, &pvLayout ) ) )
|
|
goto Exit;
|
|
|
|
hr = this->m_hMasterElement->SetValue(
|
|
DirectUI::Element::LayoutProp,
|
|
PI_Local,
|
|
pvLayout
|
|
);
|
|
|
|
if ( FAILED( hr ) )
|
|
goto Exit;
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
if ( FAILED(hr) )
|
|
{
|
|
InternalDestroyUI();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CSxApwDUserView::InternalDestroyUI()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if ( m_hMasterElement == NULL )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = m_hMasterElement->DestroyAll();
|
|
m_hMasterElement = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CSxApwDUserView::SetParentWindow(
|
|
HWND hWnd/*hWnd*/
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
BOOL bOk;
|
|
ASSERT( m_dwThreadId != 0 );
|
|
bOk = PostThreadMessageW( m_dwThreadId, SAPW_DU_SET_PARENT_WINDOW, (WPARAM)hWnd, NULL );
|
|
ASSERT( bOk );
|
|
#else
|
|
|
|
if ( SUCCEEDED( hr = InternalDestroyUI() ) )
|
|
{
|
|
m_hOurParentWnd = hWnd;
|
|
hr = InternalCreateUI();
|
|
}
|
|
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
class CRowObject;
|
|
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
|
|
DWORD
|
|
CSxApwDUserView::ThisViewThreadCallback()
|
|
{
|
|
MSG msg;
|
|
BOOL bConstructed = ConstructGadgets();
|
|
BOOL bOk;
|
|
|
|
ASSERT( bConstructed );
|
|
|
|
//
|
|
// Cheeseball method of making sure that this thread has started before we let the
|
|
// constructor continue.
|
|
//
|
|
PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
|
|
SetEvent( this->m_hThreadGoing );
|
|
|
|
while ( ( bOk = GetMessage( &msg, NULL, 0, 0 ) ) != 0 )
|
|
{
|
|
TranslateMessage( &msg );
|
|
|
|
//
|
|
// If this is a "set parent window" message, then we have to disconnect from our
|
|
// current UI, reconstruct the new UI, and go about our business.
|
|
//
|
|
if ( msg.message == SAPW_DU_SET_PARENT_WINDOW )
|
|
{
|
|
//
|
|
// Detsroy our current UI
|
|
//
|
|
if ( SUCCEEDED( InternalDestroyUI() ) )
|
|
{
|
|
//
|
|
// And if we're setting to a new HWND, reconstruct the UI around
|
|
// it.
|
|
//
|
|
if ( m_hOurParentWnd != (HWND)msg.wParam )
|
|
{
|
|
m_hOurParentWnd = (HWND)msg.wParam;
|
|
InternalCreateUI();
|
|
}
|
|
}
|
|
}
|
|
else if ( msg.message == SAPW_DU_TEARDOWN_INSTANCE )
|
|
{
|
|
this->InternalDestroyUI();
|
|
break;
|
|
}
|
|
else if ( msg.message == SAPW_DU_NEXT_ROW )
|
|
{
|
|
CRowObject* pRowObject = (CRowObject*)msg.wParam;
|
|
this->InternalSetNextRow( pRowObject );
|
|
}
|
|
else
|
|
{
|
|
DispatchMessage( &msg );
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI CALLBACK
|
|
CSxApwDUserView::ThisViewThreadCallback( LPVOID pvContext )
|
|
{
|
|
DWORD dwRetValue = 0;
|
|
|
|
__try
|
|
{
|
|
dwRetValue = ((CSxApwDUserView*)pvContext)->ThisViewThreadCallback();
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DebugBreak();
|
|
}
|
|
|
|
return dwRetValue;
|
|
}
|
|
|
|
#endif
|
|
|
|
HRESULT
|
|
CSxApwDUserView::InternalSetNextRow( IViewRow* pRow )
|
|
{
|
|
CRowObjectRowElement *pElement = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Add this next row to the table-view gadget
|
|
//
|
|
if ( pRow == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
pElement = new CRowObjectRowElement();
|
|
hr = pElement->Initialize();
|
|
|
|
if ( FAILED( hr = pElement->Initialize() ) )
|
|
goto Exit;
|
|
|
|
pRow->AddRef();
|
|
if ( FAILED( hr = pElement->SetDatasource( pRow ) ) )
|
|
goto Exit;
|
|
|
|
hr = m_hMasterElement->Add( pElement );
|
|
if ( SUCCEEDED( hr ) )
|
|
pElement = NULL;
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
if ( pElement != NULL )
|
|
{
|
|
delete pElement;
|
|
pElement = NULL;
|
|
}
|
|
|
|
if ( pRow != NULL )
|
|
pRow->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSxApwDUserView::Draw(
|
|
)
|
|
{
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
BOOL b = PostThreadMessageW( m_dwThreadId, SAPW_DU_DRAW_REQUEST, NULL, NULL );
|
|
ASSERT( b );
|
|
return b ? S_OK : E_FAIL;
|
|
#else
|
|
return S_OK;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CSxApwDUserView::NextRow(
|
|
int nColumns,
|
|
const LPCWSTR* columns
|
|
)
|
|
{
|
|
CRowObject *Row = new CRowObject();
|
|
HRESULT hr = S_OK;
|
|
|
|
Row->set_Count( nColumns, TRUE );
|
|
|
|
for ( int i = 0; i < nColumns; i++ )
|
|
{
|
|
if ( FAILED( hr = Row->set_Value( i + 1, _bstr_t(columns[i]) ) ) )
|
|
{
|
|
ASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if ( hr == S_OK )
|
|
{
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
if ( !PostThreadMessageW( m_dwThreadId, SAPW_DU_NEXT_ROW, (WPARAM)Row, NULL ) )
|
|
{
|
|
ASSERT( FALSE );
|
|
hr = E_FAIL;
|
|
}
|
|
#else
|
|
hr = this->InternalSetNextRow( Row );
|
|
#endif
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE
|
|
CSxApwDUserView::AddRef()
|
|
{
|
|
return ::InterlockedIncrement( &m_ulRefCount );
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE
|
|
CSxApwDUserView::Release()
|
|
{
|
|
ULONG ulRefCount = ::InterlockedDecrement( &m_ulRefCount );
|
|
if ( ulRefCount == 0 )
|
|
{
|
|
#if DUI_NEEDS_OWN_THREAD
|
|
if ( !PostThreadMessageW( m_dwThreadId, SAPW_DU_TEARDOWN_INSTANCE, NULL, NULL ) )
|
|
{
|
|
ASSERT( FALSE );
|
|
}
|
|
WaitForSingleObject( m_hThreadHandle, INFINITE );
|
|
m_hThreadHandle = INVALID_HANDLE_VALUE;
|
|
#endif
|
|
delete this;
|
|
}
|
|
return ulRefCount;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CSxApwDUserView::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID* ppvObject
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( ppvObject )
|
|
*ppvObject = NULL;
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
if ( riid == IID_IUnknown )
|
|
{
|
|
AddRef();
|
|
*ppvObject = (IUnknown*)this;
|
|
}
|
|
else if ( riid == __uuidof(ISxApwUiView) )
|
|
{
|
|
AddRef();
|
|
*ppvObject = (ISxApwUiView*)this;
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
}
|
|
|
|
static CHAR chVeryVeryLargeAssertionBuffer[4096];
|
|
|
|
VOID
|
|
FailAssertion(
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
int iLine,
|
|
PCSTR pszExpr
|
|
)
|
|
{
|
|
static const CHAR szAssertionFormatter[] = "\n*** Assertion failed: %s\n*** At %s(%d) in %s\n";
|
|
|
|
_snprintf(
|
|
chVeryVeryLargeAssertionBuffer,
|
|
NUMBER_OF(chVeryVeryLargeAssertionBuffer),
|
|
szAssertionFormatter,
|
|
pszExpr,
|
|
pszFile,
|
|
iLine,
|
|
pszFunction
|
|
);
|
|
|
|
OutputDebugStringA( chVeryVeryLargeAssertionBuffer );
|
|
}
|
|
|
|
|