2025-04-27 07:49:33 -04:00

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 );
}