// ResFile.cpp: implementation of the CResFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ResFile.h"
#include "debug.h"
extern void	GetRCMLVersionNumber( HINSTANCE h,  LPTSTR * ppszVersion);

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CResFile::CResFile(BOOL bEnhanced, BOOL bRelative, BOOL bWin32, BOOL bCicero)
{
	m_pszMenu=NULL;
	m_pszClass=NULL;
	m_pszTitle=NULL;
	m_pszFont=NULL;
	m_pControls=NULL;
	SetItemCount(0);

    SetEnhanced( bEnhanced );
    SetRelative( bRelative );
    SetWin32( bWin32 );
    SetCicero( bCicero );

    m_pWin32=NULL;
    m_hwnd=NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
CResFile::~CResFile()
{
    if( HIWORD(m_pszMenu) )
	    delete m_pszMenu;

    if( HIWORD(m_pszClass) )
	    delete m_pszClass;

	delete m_pszTitle;
	delete m_pszFont;
    delete m_pWin32;

	int k=GetItemCount();
	for(int i=0;i<k;i++)
		delete m_pControls[i];
	delete m_pControls;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
BOOL CResFile::LoadDialog(LPTSTR ID, HMODULE hMod)
{
	HRSRC hDialog = FindResource( hMod, ID , RT_DIALOG );
	if( hDialog!=NULL )
	{
		HGLOBAL hMemDialog = LoadResource( hMod, hDialog );
		if( hMemDialog != NULL )
		{
			LPVOID pMemDialog = LockResource( hMemDialog );
			//
			//
			//
			DLGTEMPLATE * pDlgTemplate=(DLGTEMPLATE*)pMemDialog;
			DLGITEMTEMPLATE * pControls = ExtractDlgHeaderInformation( pDlgTemplate );
			if(pControls==NULL)
				return FALSE;

			BOOL	bIsExtended=IsExtended( pDlgTemplate );
			int k=GetItemCount();
			m_pControls=new CResControl*[k];
			for(int i=0;i<k;i++)
			{
				m_pControls[i]=new CResControl( pControls, bIsExtended, GetWin32(), *this );
				pControls=m_pControls[i]->GetNextControl();		// this is odd.
			}
			UnlockResource( hMemDialog );
			return TRUE;
		}
	}
	return FALSE;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
//
// Temporary hack - but seems to be working quite well
//
//////////////////////////////////////////////////////////////////////
BOOL CResFile::LoadWindow(HWND hWnd)
{
    m_hwnd= hWnd;
    ExtractDlgHeaderInformation(hWnd);

    HWND hFirstChild=::GetWindow(hWnd, GW_CHILD);
    // count the number of children.
    int i=0;
    while( hFirstChild )
    {
        hFirstChild=::GetWindow( hFirstChild, GW_HWNDNEXT );
        i++;
    }

    // 
    SetItemCount(i);
    m_pControls=new CResControl*[i];
    hFirstChild=::GetWindow(hWnd, GW_CHILD);
    i=0;
    while( hFirstChild )
    {
    	m_pControls[i]=new CResControl( hFirstChild, TRUE, GetWin32(), *this );
        hFirstChild=::GetWindow( hFirstChild, GW_HWNDNEXT );
        i++;
    }
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CResFile::ExtractDlgHeaderInformation(HWND hwnd)
{
    HFONT hFont = (HFONT)SendMessage( hwnd , WM_GETFONT, NULL, NULL);
    if(hFont==NULL)
        hFont = (HFONT)GetStockObject(SYSTEM_FONT);
    LOGFONT lf;
    ::GetObject( hFont, sizeof(lf), &lf );
    m_Font.Init(NULL,0,0,0,&lf);

    WORD wSize= (WORD)(lf.lfHeight<0?-MulDiv(lf.lfHeight, 72, GetDeviceCaps(GetDC(hwnd), LOGPIXELSY) ):lf.lfHeight);

    SetFontSize( wSize );     // probably need to back map?
    SetFontWeight( (WORD)lf.lfWeight );
    SetFontItalic( lf.lfItalic );
    SetFont( lf.lfFaceName );

    //
    // Now we have the font, we can size the dialog correctly.
    //
    WINDOWPLACEMENT wp;
    wp.length = sizeof(wp);
    GetWindowPlacement( hwnd, &wp );

    RECT r;
    GetClientRect( hwnd, &r);

    SIZE size;
    size.cx = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
    size.cy = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
    size.cx = r.right - r.left;
    size.cy = r.bottom - r.top;
    size = m_Font.GetDlgUnitsFromPixels( size );

	SetWidth( size.cx );
	SetHeight( size.cy );

	SetStyle( GetWindowLong( hwnd, GWL_STYLE) );
	SetStyleEx( GetWindowLong( hwnd, GWL_EXSTYLE) );

    SetMenu(NULL);      // review
    SetClass(NULL);     // can't get that I don't think, hidden?
    int cbText = GetWindowTextLength( hwnd )+1;
    LPTSTR pszTitle=new TCHAR[cbText+1];
    GetWindowText( hwnd, pszTitle, cbText );
    SetTitle(pszTitle);
    delete pszTitle;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
DLGITEMTEMPLATE * CResFile::ExtractDlgHeaderInformation(DLGTEMPLATE *pDlgTemplate)
{
	DLGTEMPLATEEX * pDlgEx=(DLGTEMPLATEEX*)pDlgTemplate;

	//
	// New or old style dialog template.
	//
	if ( pDlgEx->signature == (WORD)-1 )
	{
		//
		// New dialog format used here.
		//
		SetWidth( pDlgEx->cx );
		SetHeight( pDlgEx->cy );
		SetItemCount( pDlgEx->cDlgItems );
		SetStyle( pDlgEx->style );
		SetStyleEx( pDlgEx->exStyle );

		LPWSTR pszString=(LPWSTR)(&pDlgEx->menu);

		//
		// Menu goo.
		//
		WORD * pW=(WORD*)pszString;
		if( *pW == 0 )
		{
			// No menu.
			pszString++;
		}
		else if (*pW==(WORD)-1)
		{
			// Menu is a resource - yuck.
			SetMenu( (LPTSTR)*(pW+1) );
			pszString+=2;
		}
		else
		{
			pszString = SetMenu( pszString );
		}

		//
		// Class goo.
		//
		pW=(WORD*)pszString;
		if( *pW == 0 )
		{
			// No class.
			pszString++;
		}
		else if (*pW==(WORD)-1)
		{
			// Menu is a resource - what does that mean!
			pszString+=2;
		}
		else
		{
			pszString = SetClass( pszString );
		}

		//
		//
		pszString = SetTitle( pszString );

		//
		// pszString now points at 
		//
	    // short  pointsize;       // if DS_SETFONT or DS_SHELLFONT is set
		// short  weight;          // if DS_SETFONT or DS_SHELLFONT is set
		// short  bItalic;         // if DS_SETFONT or DS_SHELLFONT is set
		// WCHAR  font[fontLen];   // if DS_SETFONT or DS_SHELLFONT is set

		DWORD dwStyle = GetStyle();
		if( dwStyle & DS_SETFONT )
		{
			short * pShort=(short *)pszString;
			// Font Size
			SetFontSize( *pShort++ );
			SetFontWeight( *pShort++ );
			SetFontItalic( *pShort++ );
			pszString=SetFont( (LPWSTR)pShort );
		}
		DWORD pData=(DWORD)pszString;
		pData+=3;
		pData &= ~3;
		return (DLGITEMTEMPLATE * )pData;

	}
	else
	{
		SetWidth( pDlgTemplate->cx );
		SetHeight( pDlgTemplate->cy );
		SetItemCount( pDlgTemplate->cdit );
		SetStyle( pDlgTemplate->style );
		SetStyleEx( pDlgTemplate->dwExtendedStyle );

		LPWSTR pszString=(LPWSTR)(&pDlgTemplate->cy+1);
		// pszString++;		// for some reason, we do this>?

		//
		// Followed by 3 variable length arrays (strings)
		// menu, class, title and then a font name if DS_SETFONT is used.
		//
		pszString = SetMenu( pszString );
		pszString = SetClass( pszString );
		pszString = SetTitle( pszString );

		//
		// Now we go for the FONT.
		// 
		DWORD dwStyle = GetStyle();
		if( dwStyle & DS_SETFONT )
		{
			// Font Size
			SetFontSize( *((LPWORD)pszString) );
			pszString++;
			pszString=SetFont( pszString );
		}
		DWORD pData=(DWORD)pszString;
		pData+=3;
		pData &= ~3;
		return (DLGITEMTEMPLATE * )pData;
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
LPWSTR CResFile::SetMenu	( LPWSTR pszMenu )
{
	return SetString( &m_pszMenu, pszMenu );
}

LPWSTR CResFile::SetClass	( LPWSTR pszClass )
{
	return SetString( &m_pszClass, pszClass );
}

LPWSTR CResFile::SetTitle	( LPWSTR pszTitle )
{
	UINT   cbLen=lstrlenW(pszTitle)+1;
    LPWSTR newString = FixEntity( pszTitle );
	LPWSTR pRes=SetString( &m_pszTitle, newString);
	delete newString;
	return pszTitle+cbLen;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Takes an input string, and returns a string fixed up with entities.
//
LPWSTR CResFile::FixEntity( LPWSTR pszTitle )
{
	UINT	cbLen=lstrlenW(pszTitle)+1;
	LPWSTR newString=new WCHAR[cbLen*4];
	LPWSTR pSource=pszTitle;
	LPWSTR pDest=newString;
	while( *pSource!=0)
	{
    /*    
    &lt; - (<) 
    &gt; - (>) 
    &amp; - (&) 
    &quot; - (") 
    &apos; - (') 
    */
        int i=0;
        BOOL bFound=FALSE;
        while( g_Entity[i].szEntity )
        {
            if( *pSource == g_Entity[i].szChar )
            {
                lstrcpy(pDest, g_Entity[i].szEntity );
                pDest += lstrlen( g_Entity[i].szEntity );
                bFound=TRUE;
                break;
            }
            i++;
        }

        if( !bFound )
			*pDest++=*pSource;
	    pSource++;
	}
	*pDest=0;

	return newString;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
LPWSTR CResFile::SetFont	( LPWSTR pszFont )
{
	return SetString( &m_pszFont, pszFont );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
LPWSTR CResFile::SetString( LPWSTR * ppszString , LPWSTR pszSource )
{
	if( HIWORD(*ppszString) != NULL )
	{
		delete *ppszString;
		*ppszString=NULL;
	}
    if(HIWORD(pszSource))
    {
	    int len=lstrlenW( pszSource )+1;
	    *ppszString=new WCHAR[len];
	    lstrcpyW( *ppszString, pszSource );
	    return pszSource+len;
    }
    else
    {
        *ppszString=pszSource;
        return NULL;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CResFile::DumpDialog(LPTSTR pszFilename)
{
    if( m_hFile.CreateFile(pszFilename) )
    {
        DumpProlog();

        DumpFormAndCaption();

        DumpPage();
        //<PAGE>
        DumpDialogStyles();
        DumpTestInfo(pszFilename);
        DumpLayoutElement();
        DumpMenu();
	    int k=GetItemCount();
	    CResControl * pLast=NULL;
	    CResControl * pCurrent=NULL;
	    for(int i=0;i<k;i++)
	    {
		    pCurrent=m_pControls[i];
		    
		    BOOL bRelative=FALSE;
		    if( GetRelative() )
		    {
			    //
			    // Work out if we can do a relative position.
			    // same X or same Y, with same height is OK.
			    //
			    if( pLast )
			    {
				    if( pCurrent->GetY() == pLast->GetY() )
				    {
					    if( pCurrent->GetHeight() == pCurrent->GetHeight() )
					    {
						    bRelative=TRUE;
					    }
				    }

				    if( pCurrent->GetX() == pLast->GetX( ) )
				    {
					    if( pCurrent->GetHeight() == pCurrent->GetHeight() )
					    {
						    bRelative=TRUE;
					    }
				    }
			    }
		    }
            pCurrent->Dump(bRelative?pLast:NULL);
		    pLast=pCurrent;
            Write( TEXT("\r\n"), FALSE );
	    }
        //</PAGE>
        DumpEpilog();
        m_hFile.CloseFile();
    }	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
BOOL CResFile::IsExtended(DLGTEMPLATE *pDlgTemplate)
{
	DLGTEMPLATEEX * pDlgEx=(DLGTEMPLATEEX*)pDlgTemplate;

	//
	// New or old style dialog template.
	//
	return pDlgEx->signature == (WORD)-1 ;
}

void CResFile::DumpLayoutElement()
{
	TCHAR szBuffer[1024];
	Write(TEXT("\t\t\t<LAYOUT>"));
	Write(TEXT("\t\t\t\t<XYLAYOUT ANNOTATE=\"NO\">"));
	    //
	    // Now we dump the style object too.
	    //
	    wsprintf(szBuffer,TEXT("\t\t\t\t<STYLE FONT-FAMILY=\"%s\" FONT-SIZE=\"%d\" /> \r\n"),
		    GetFont(), GetFontSize() );
	    Write(szBuffer);
	Write(TEXT("\t\t\t\t</XYLAYOUT>\r\n"));

	Write(TEXT("\t\t\t</LAYOUT>\r\n"));
}

#undef PROPERTY
#define PROPERTY(p,id, def) if( ((dwRemainingStyles & p)==p) != def ) { wsprintf(szBuffer, TEXT("%s=\"%s\" "), id, (dwRemainingStyles & p)?TEXT("YES"):TEXT("NO") ); m_pWin32->AllocAddAttribute(szBuffer, 0); }
#define DLGSTYLE(p,id, member, def) if( ((dwRemainingStyles & p)==p) != def ) { wsprintf(szBuffer, TEXT("%s=\"%s\" "), id, (dwRemainingStyles & p)?TEXT("YES"):TEXT("NO") ); m_pWin32->AllocAddAttribute(szBuffer, 0); }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// These are very WIN32 specific styles.
//
void CResFile::DumpDialogStyles()
{
    if( GetWin32() == FALSE )
        return;

    if(m_pWin32==NULL)
        m_pWin32=new CDumpCache(m_hFile);

	TCHAR szBuffer[1024];
	DWORD dwRemainingStyles;

    dwRemainingStyles = GetStyle();

    PROPERTY( WS_POPUP           , TEXT("POPUP") ,             TRUE );     // POPUP
    PROPERTY( WS_CHILD           , TEXT("CHILD") ,             FALSE );
    PROPERTY( WS_MINIMIZE        , TEXT("MAXIMIZEBUTTON") ,    FALSE );
//    PROPERTY( WS_VISIBLE         , TEXT("VISIBLE") ,           TRUE );     // VISIBLE - CARE?

//    PROPERTY( WS_DISABLED        , TEXT("DISABLED") ,          FALSE );
    PROPERTY( WS_CLIPSIBLINGS    , TEXT("CLIPSIBLINGS") ,      FALSE );
    PROPERTY( WS_CLIPCHILDREN    , TEXT("CLIPCHILDREN") ,      FALSE );

    // WS_CAPTION is annoying, and in FormAndCaption stuff.
    // PROPERTY( WS_BORDER          , TEXT("BORDER") ,            TRUE );     // BORDER
    // PROPERTY( WS_DLGFRAME        , TEXT("DLGFRAME") ,          TRUE );     // DLGFRAME - close button.
    PROPERTY( WS_VSCROLL         , TEXT("VSCROLL") ,           FALSE );
    PROPERTY( WS_HSCROLL         , TEXT("HSCROLL") ,           FALSE );

    PROPERTY( WS_SYSMENU         , TEXT("SYSMENU"),            TRUE );     // most dialogs have this.
    PROPERTY( WS_THICKFRAME      , TEXT("THICKFRAME") ,        FALSE );
    // PROPERTY( WS_GROUP           , TEXT("GROUP") ,             FALSE );
    // PROPERTY( WS_TABSTOP         , TEXT("TABSTOP") ,           FALSE );

    // Dumped in FormAndCaption
    // PROPERTY( WS_MINIMIZEBOX     , TEXT("MINIMIZEBOX") ,       FALSE );
    // PROPERTY( WS_MAXIMIZEBOX     , TEXT("MAXIMIZEBOX") ,       FALSE );


    //
    // Extended styles
    //
    dwRemainingStyles = GetStyleEx();

    PROPERTY( WS_EX_DLGMODALFRAME     , TEXT("MODALFRAME"),    FALSE );      // Default.
    PROPERTY( WS_EX_NOPARENTNOTIFY    , TEXT("NOPARENTNOTIFY"),FALSE );
    PROPERTY( WS_EX_TOPMOST           , TEXT("TOPMOST"),       FALSE );

    PROPERTY( WS_EX_ACCEPTFILES       , TEXT("DROPTARGET"),    FALSE );
    PROPERTY( WS_EX_TRANSPARENT       , TEXT("TRANSPARENT"),   FALSE );
    PROPERTY( WS_EX_MDICHILD          , TEXT("MDI"),           FALSE );
    PROPERTY( WS_EX_TOOLWINDOW        , TEXT("TOOLWINDOW"),    FALSE );

    PROPERTY( WS_EX_WINDOWEDGE        , TEXT("WINDOWEDGE"),    FALSE );
    PROPERTY( WS_EX_CLIENTEDGE        , TEXT("CLIENTEDGE"),    FALSE );
    PROPERTY( WS_EX_CONTEXTHELP       , TEXT("CONTEXTHELP"),   FALSE );
    PROPERTY( WS_EX_RIGHT             , TEXT("RIGHT"),         FALSE );
    PROPERTY( WS_EX_RTLREADING        , TEXT("RTLREADING"),    FALSE );
    PROPERTY( WS_EX_LEFTSCROLLBAR     , TEXT("LEFTSCROLLBAR"), FALSE );

    PROPERTY( WS_EX_CONTROLPARENT     , TEXT("CONTROLPARENT"), FALSE );
    PROPERTY( WS_EX_STATICEDGE        , TEXT("STATICEDGE"),    FALSE );
    PROPERTY( WS_EX_APPWINDOW         , TEXT("APPWINDOW"),     FALSE );

    m_pWin32->WriteElement(TEXT("WIN32:STYLE") );

    delete m_pWin32;
    m_pWin32= new CDumpCache(m_hFile);

    //
    // Specific Dialog styles.
    //
    dwRemainingStyles = GetStyle();
    DLGSTYLE(  DS_ABSALIGN         , TEXT("ABSALIGN"),      m_AbsAlign,         FALSE );
    DLGSTYLE(  DS_SYSMODAL         , TEXT("SYSMODAL"),      m_SysModal,         FALSE );
    DLGSTYLE(  DS_LOCALEDIT        , TEXT("LOCALEDIT"),     m_LocalEdit,        FALSE );  // Local storage.

    DLGSTYLE(  DS_SETFONT          , TEXT("SETFONT"),       m_SetFont,          TRUE );  // User specified font for Dlg controls */
    DLGSTYLE(  DS_MODALFRAME       , TEXT("MODALFRAME"),    m_ModalFrame,       TRUE );  // Can be combined with WS_CAPTION  */
    DLGSTYLE(  DS_NOIDLEMSG        , TEXT("NOIDLEMSG"),     m_NoIdleMessgae,    FALSE );  // IDLE message will not be sent */
    DLGSTYLE(  DS_SETFOREGROUND    , TEXT("SETFOREGROUND"), m_SetForeground,    FALSE );  // not in win3.1 */

    DLGSTYLE(  DS_3DLOOK           , TEXT("DDDLOOK"),       m_3DLook,           FALSE );
    DLGSTYLE(  DS_FIXEDSYS         , TEXT("FIXEDSYS"),      m_FixedSys,         FALSE );
    DLGSTYLE(  DS_NOFAILCREATE     , TEXT("NOFAILCREATE"),  m_NoFailCreate,     FALSE );
    DLGSTYLE(  DS_CONTROL          , TEXT("CONTROL"),       m_Control,          FALSE );
    DLGSTYLE(  DS_CENTER           , TEXT("CENTER"),        m_Center,           FALSE );
    DLGSTYLE(  DS_CENTERMOUSE      , TEXT("CENTERMOUSE"),   m_CenterMouse,      FALSE );
    DLGSTYLE(  DS_CONTEXTHELP      , TEXT("CONTEXTHELP"),   m_ContextHelp,      FALSE );

    if( GetClass() )
    {
        if( HIWORD(GetClass()) )
        {
            if( lstrlen(GetClass()) )
            {
                wsprintf( szBuffer, TEXT("CLASS=\"%s\" "), GetClass() );
                m_pWin32->AllocAddAttribute(szBuffer);
            }
        }
        else
        {
            wsprintf( szBuffer, TEXT("CLASS=\"%d\" "), GetClass() );
            m_pWin32->AllocAddAttribute(szBuffer);
        }

    }

    if( GetMenu() )
    {
        if( HIWORD(GetMenu())  )
        {
            if( lstrlen(GetMenu()) )
            {
                wsprintf( szBuffer, TEXT("MENUID=\"%s\" "), GetMenu() );
                m_pWin32->AllocAddAttribute(szBuffer);
            }
        }
        else
        {
            wsprintf( szBuffer, TEXT("MENUID=\"%d\" "), GetMenu() );
            m_pWin32->AllocAddAttribute(szBuffer);
        }
    }

    m_pWin32->WriteElement(TEXT("WIN32:DIALOGSTYLE"));
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The header for the XML files.
//
void CResFile::DumpProlog()
{
    switch( m_hFile.GetEncoding() )
    {
    case CFileEncoder::RF_UNICODE:
   	    Write(TEXT("<?xml version='1.0' encoding=\"UTF-16\" ?>") );
        break;

    case CFileEncoder::RF_UTF8:
   	    Write(TEXT("<?xml version='1.0' encoding=\"UTF-8\" ?>") );
        break;

    default:
   	    Write(TEXT("<?xml version='1.0' ?>") );
        break;
    }

   	Write(TEXT("<!-- XML Generated by RCMLGen (C) Microsoft Corp. 1999, 2000 -->") );
   	Write(TEXT("<RCML\txmlns=\"urn:schemas-microsoft-com:rcml\" "));
    if( GetEnhanced() )
       Write(TEXT("\txmlns:WIN32=\"urn:schemas-microsoft-com:rcml:win32\""));
    if( GetCicero() )
       Write(TEXT("\txmlns:CICERO=\"urn:schemas-microsoft-com:rcml:CICERO\""));
    Write(TEXT(">") );
   	Write(TEXT("\t<PLATFORM OS=\"WINDOWS\" />") );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CResFile::DumpFormAndCaption()
{
	TCHAR szBuffer[1024];
   	Write(TEXT("\t<FORM "), FALSE );
	if( GetEnhanced() )
		Write(TEXT("RESIZE=\"Automatic\" "),FALSE);
   	Write(TEXT(">") );

	wsprintf(szBuffer,TEXT("\t\t<CAPTION TEXT=\"%s\" "), GetTitle() );
	Write(szBuffer, FALSE);
 	DWORD dwRemainingStyles;

    dwRemainingStyles = GetStyle();

    if( dwRemainingStyles & WS_MINIMIZEBOX )        // default FALSE
        Write( TEXT("MINIMIZEBOX=\"YES\" "), FALSE );

    if( dwRemainingStyles & WS_MAXIMIZEBOX )        // default FALSE
        Write( TEXT("MAXIMIZEBOX=\"YES\" "), FALSE );

    if( (dwRemainingStyles & WS_SYSMENU) == FALSE)  // default TRUE
        Write( TEXT("CLOSE=\"NO\" "), FALSE );

  	Write(TEXT("/>") );
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CResFile::DumpEpilog()
{
    if( GetEnhanced() )
   	    Write(TEXT("\t\t\t<STRINGTABLE />"));

	Write(TEXT("\t\t</PAGE>"));
	Write(TEXT("\t</FORM>"));
	Write(TEXT("</RCML>"));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CResFile::DumpTestInfo(LPTSTR pszFileName)
{
	//
	// Write out useful testing information.
	//
	TCHAR szBuffer[1024];
	LPTSTR pVersion;
	GetRCMLVersionNumber( GetModuleHandle( TEXT("RCML.dll")), &pVersion );
	wsprintf(szBuffer,TEXT("\t\t\t<TESTINFO FILE=\"%s\" GENERATORDATE=\"%s\" ENHANCED=\"%s\" RCMLVER=\"%s\" />"),
		pszFileName?pszFileName:TEXT("No File"), TEXT(__DATE__), GetEnhanced()?TEXT("YES"):TEXT("NO"), pVersion); 
	Write(szBuffer);
    delete pVersion;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CResFile::DumpPage()
{
	TCHAR szBuffer[1024];
  	Write(TEXT("\t\t<PAGE "), FALSE);
	wsprintf(szBuffer,TEXT(" WIDTH=\"%d\" HEIGHT=\"%d\" "), GetWidth(), GetHeight());
	Write(szBuffer, FALSE);

	Write(TEXT(">"));

}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
void CResFile::DumpMenu()
{
    if( GetWindow() == NULL )
        return;

    if( GetCicero() == FALSE )
        return;

   	Write(TEXT("\t\t<CICERO:COMMANDING xmlns=\"urn:schemas-microsoft-com:rcml:CICERO\">") );

    //
    // The accessible guys supposedly do this for HMENUs to, HOWEVER
    // they cannot provide me with the command ID that I should use to fake up the command
    //
    HMENU hMenu = ::GetMenu(GetWindow());
    if( hMenu != NULL )
        FindMenuItem(hMenu, NULL);

    //
    // This was for MSAA support. MSAA cannot enumerate the 
    // menus on an Explorer window - so PM's will just have to do those by hand?
    // This should work on the office applications though.
    //
    IAccessible * pA;
    HRESULT hr;
    CoInitialize(NULL);
    if( SUCCEEDED(hr=AccessibleObjectFromWindow( GetWindow(), 
        OBJID_WINDOW,   // works for office, information about the window itself, how many children it has.
        // OBJID_MENU , // the menu for the window, doesn't work for office.
        IID_IAccessible, (LPVOID*)&pA ) ))
    {
        FindMenuItem(pA, ROLE_SYSTEM_MENUITEM);
        // FindMenuItem(pA, ROLE_SYSTEM_PUSHBUTTON);   // for Coolbar menu items ... hmm...
        pA->Release();
    }
    CoUninitialize();

   	Write(TEXT("\t\t</CICERO:COMMANDING>") );
}

//
// 
//
void CResFile::FindMenuItem(IAccessible *pA, LONG role_code)
{
    long childCount;
    HRESULT hr;
    if( SUCCEEDED( hr= pA->get_accChildCount( &childCount )))
    {
        if( childCount>0 )
        {
            int i;
            VARIANT * childArray=new VARIANT[childCount];
            for(i=0;i<childCount;i++)
                VariantInit( &childArray[i]);

            //
            // Get the children
            //
            LONG obtained;
            hr=AccessibleChildren( pA, 0, childCount, childArray, &obtained );
            TRACE(TEXT("Got %d children our of %d from this control\n"),obtained, childCount);

            // Dump them out
            for(i=0;i<obtained;i++)
            {
                //
                // Get an Idispatch interface.
                //
                if( childArray[i].vt == VT_I4 )
                {
                    // hr=pA->get_accChild( childArray[i], &pDisp );
                    DumpAccessibleItem( pA, &childArray[i], role_code);
                }
                else
                if( childArray[i].vt == VT_DISPATCH )
                {
                    IDispatch * pDisp = childArray[i].pdispVal;
                    IAccessible * pDumpThis = NULL;
                    if( SUCCEEDED( pDisp->QueryInterface( IID_IAccessible, (LPVOID*)&pDumpThis) ))
                    {
                        if( pDumpThis )
                        {
                            VARIANT varDumpThis;
                            VariantInit(&varDumpThis);
                            varDumpThis.vt=VT_I4;
                            varDumpThis.lVal = CHILDID_SELF;

                            DumpAccessibleItem( pDumpThis, &varDumpThis, role_code );

                            VariantClear( &varDumpThis );

                            FindMenuItem(pDumpThis, role_code);      // recurse.

                            pDumpThis->Release();
                        }
                    }
                    // pDisp->Release();    // done in the VariantClear (I suspect).
                }
            }

            //
            // Cleanup - lets not bother. we released from the variant already.
            //
            for(int iDel=0;iDel<childCount;iDel++)
                hr = VariantClear( &childArray[iDel]);
            delete [] childArray;
        }
    }
}

void CResFile::FindMenuItem(HMENU hMenu, LONG nothing)
{
    int iMenuCount = GetMenuItemCount( hMenu );
    for(int i=0; i<iMenuCount;i++)
    {
        MENUITEMINFO mInfo;
        mInfo.cbSize = sizeof(MENUITEMINFO);
        mInfo.fMask = MIIM_SUBMENU | MIIM_ID;
        if( GetMenuItemInfo( hMenu, i, TRUE, &mInfo ) )
        {
            if( mInfo.hSubMenu )
            {
                TRACE(TEXT("Menu has a child menu of 0x%08x\n"), mInfo.hSubMenu);
                FindMenuItem(mInfo.hSubMenu, nothing);
            }
            else
            {
                // Parent menus can't be actioned upon, so don't dump them out.
                TCHAR menuText[MAX_PATH];
                if( GetMenuString( hMenu, i, menuText, sizeof(menuText), MF_BYPOSITION ) )
                {
                    if( GetCicero() )
                    {
                        LPWSTR text=CResControl::FindNiceText( menuText );
                        TRACE(TEXT("Menu item %s (was '%s') command %d\n"), 
                            text, menuText, mInfo.wID);
                        TCHAR szBuffer[1024];
                        wsprintf(szBuffer,
                            TEXT("\t\t\t<COMMAND TEXT=\"+%s\" ID=\"%u\"/>"), 
                            text, mInfo.wID );
                       	Write(szBuffer);
                        delete text;
                    }
                }
            }
        }
    }
}

//
//
//
void CResFile::DumpAccessibleItem( IAccessible * pDumpThis, VARIANT * pvarDumpThis, LONG role_code )
{

    VARIANT varRole;
    VariantInit(&varRole);

    HRESULT hr; 
    if( SUCCEEDED( hr = pDumpThis->get_accRole( *pvarDumpThis , &varRole ) ))
    {
        VARIANT varState;
        VariantInit(&varState);
        if( SUCCEEDED( hr = pDumpThis->get_accState( *pvarDumpThis , &varState ) ))
        {
#ifdef _DEBUG
            {
            BSTR bstrDesc=NULL;
            if( SUCCEEDED( hr=pDumpThis->get_accDescription( *pvarDumpThis, &bstrDesc)))
            {
                TRACE(TEXT("Debug : it's a '%s' "),bstrDesc);
            }
            BSTR bstrName;
            if( SUCCEEDED( hr=pDumpThis->get_accName( *pvarDumpThis, &bstrName)))
            {
                TRACE(TEXT("Debug called : %s "),bstrName);
            }
            TRACE(TEXT("its state is 0x%08x\n"), varState.lVal );
            SysFreeString( bstrDesc );
            SysFreeString( bstrName );
            }
#endif
            if( ( varState.lVal && ((varState.lVal & STATE_SYSTEM_INVISIBLE) == 0 )))
            {
                // TRACE(TEXT("varRole code 0x%08x, "), varRole.lVal);
                if( varRole.lVal == role_code  )
                {
                    BSTR bstrDesc=NULL;
                    if( SUCCEEDED( hr=pDumpThis->get_accDescription( *pvarDumpThis, &bstrDesc)))
                    {
                        TRACE(TEXT("it's a '%s' \n"),bstrDesc);
                    }
                    SysFreeString( bstrDesc );

                    BSTR bstrName=NULL;
        #if 0
                    if( SUCCEEDED( hr=pDumpThis->get_accName( *pvarDumpThis, &bstrName)))
                    {
                        TRACE(TEXT("*-*-* We have a menu item %s\n"),bstrName);
                        SysFreeString( bstrName );
                    }
        #endif
                    if( bstrDesc )
                    {
                        LPWSTR text=CResControl::FindNiceText( bstrDesc );
                        TRACE(TEXT("Accessible item %s (was '%s') command\n"), 
                            text, bstrName);
                        TCHAR szBuffer[1024];
                        wsprintf(szBuffer,
                            TEXT("\t\t\t<COMMAND TEXT=\"%s\"/>"), 
                            text);
                        Write(szBuffer);
                        delete text;
                    }
                }
            }
        }
    }
    VariantClear( &varRole );
}