// Tranform.cpp : implementation file
//
#include "stdafx.h"
#include "XTrans.h"
#include "Tranform.h"
#include "XTransDoc.h"
#include "OTNSink.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern CXTransApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CTranform dialog
CTranform::CTranform(CMDIFrameWnd *pMDIFrame)
: CDialog(CTranform::IDD, pMDIFrame), MDIFrame_ptr(pMDIFrame)
{
//{{AFX_DATA_INIT(CTranform)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
hwnd_active = NULL;
}
void CTranform::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTranform)
DDX_Control(pDX, IDS_TRANSFORMWITH, transform_with_static);
DDX_Control(pDX, IDL_XSLSELECT, x_select_list);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTranform, CDialog)
//{{AFX_MSG_MAP(CTranform)
ON_BN_CLICKED(IDOK, OnTransform)
ON_LBN_ERRSPACE(IDL_XSLSELECT, OnErrspaceXslselect)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTranform message handlers
BOOL CTranform::OnInitDialog()
{
CDialog::OnInitDialog();
if( MDIFrame_ptr ) {
x_select_list.SetRedraw(FALSE);
x_select_list.ResetContent();
HWND hwnd_client = ::GetWindow( MDIFrame_ptr->m_hWndMDIClient, GW_CHILD);
CWnd *wndT;
wndT = CWnd::FromHandle( hwnd_client );
hwnd_active = (HWND)::SendMessage( MDIFrame_ptr->m_hWndMDIClient, WM_MDIGETACTIVE, 0, 0 );
if( !wndT || !hwnd_active ) {
AfxMessageBox( "You should open an XML and XSL documents first to produce transformation", MB_OK | MB_ICONHAND );
EndDialog( 0 );
return TRUE;
}
xsl_active = IsDocTemplate( hwnd_active );
char szWndTitle[256];
::GetWindowText( hwnd_active, szWndTitle, 255 );
transform_with_static.SetWindowText( xsl_active ? CString("Use the template '") + szWndTitle + "' to transform: " :
CString("Transform the document '") + szWndTitle + "' by: " );
int count = 0;
while( wndT != NULL) {
if( xsl_active != IsDocTemplate( wndT->m_hWnd ) ) {
CString sWndTitle;
wndT->GetWindowText( sWndTitle );
int index = x_select_list.AddString( sWndTitle );
x_select_list.SetItemData( index, (DWORD)wndT->m_hWnd );
count++;
}
wndT = wndT->GetWindow( GW_HWNDNEXT );
}
x_select_list.SetRedraw(TRUE);
if( !count ) {
AfxMessageBox( "Open another document or template", MB_OK | MB_ICONHAND );
EndDialog( 0 );
return TRUE;
}
if( count == 1 ) {
x_select_list.SetCurSel( 0 );
OnTransform();
}
}
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
bool CTranform::IsDocTemplate( HWND child_wnd )
{
CXTransDoc *pXTransDoc = GetDocument( child_wnd );
if( pXTransDoc ) return pXTransDoc->IsKindOf( RUNTIME_CLASS( CXTransXSLDoc ) ) != NULL;
return false;
}
void CTranform::OnTransform()
{
BeginWaitCursor();
int nItems = x_select_list.GetCount();
if( nItems != LB_ERR && nItems>0 ) {
HWND hMDIClient = MDIFrame_ptr->m_hWndMDIClient;
for( int i=0; i < nItems; i++ ) {
if( x_select_list.GetSel( i ) <= 0 ) continue;
HWND hwnd_sel = (HWND)x_select_list.GetItemData(i);
CComPtr<IXMLDOMDocument2> xml;
if( GetDOMDocument( xsl_active ? hwnd_sel : hwnd_active, &xml ) ) {
CComPtr<IXMLDOMDocument2> xsl;
CStringArray parameters;
bool use_processor = theApp.GetUseProcessor( parameters );
// the document object must be free-threaded, to use the transform procesor!
if( GetDOMDocument( xsl_active ? hwnd_active : hwnd_sel, &xsl, use_processor ) ) {
bool ok = false;
CStreamMem mem;
if( use_processor )
ok = XSLProcess( xml, xsl, parameters, mem );
else
ok = XSLTransform( xml, xsl, mem );
const byte *src = mem.GetMem();
if( !ok )
SetStatusMessage( "The transformation was failed" );
else {
if( !src ) src = (const unsigned char *)"";
CXTransDoc *doc = theApp.CreateNewDocument();
if( doc ) {
bool u = *src == 0xFF && *(src+1) == 0xFE;
int sz = mem.GetSize();
char *buf = new char[ sz + ( u ? 2 : 1) ];
memcpy( buf, src, sz );
buf[sz] = 0;
if( u ) buf[sz+1] = 0;
USES_CONVERSION;
doc->InitFrom( u ? OLE2T((LPCWSTR)(buf+2)) : buf );
doc->SetModifiedFlag( FALSE );
delete [] buf;
}
EndDialog( IDOK );
EndWaitCursor();
SetStatusMessage( "The transformation has completed" );
return;
}
}
}
EndWaitCursor();
EndDialog( 0 );
return;
}
AfxMessageBox( "Please, select an XSLT file to using as a transform template.", MB_OK | MB_ICONHAND );
}
EndDialog( 0 );
EndWaitCursor();
}
bool CTranform::XSLTransform( IXMLDOMDocument2 *xml, IXMLDOMDocument2 *xsl, CStreamMem &mem )
{
// Alternate way
HRESULT hr;
try {
COTNSink ontransform_sink( xml );
COM_CHECK( xml->transformNodeToObject( xsl, CComVariant( mem.stream ) ) );
return true;
}
catch( HRESULT hr ) {
DisplayCOMError( "Unable to transform the documents", hr );
}
catch( ... ) {
AfxMessageBox( "Fatal error", MB_OK | MB_ICONERROR );
}
return false;
}
bool CTranform::CreateXSLTemplate( const CLSID &clsid, IXSLTemplate **xsl )
{
HRESULT hr;
if( SUCCEEDED( hr = CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IXSLTemplate, (void**)xsl ) ) ) return true;
DisplayCOMError( "Unable to create the XSL Template object", hr );
return false;
}
bool CTranform::CreateXSLTemplate( IXSLTemplate **xsl, int idx )
{
try {
const CLSID clsid_XSLTemplate_probes[DOMverNum] = {
CLSID_XSLTemplate60,
CLSID_XSLTemplate40,
CLSID_XSLTemplate30,
CLSID_XSLTemplate26,
CLSID_XSLTemplate
};
if( idx >= 0 && idx < DOMverNum )
return CreateXSLTemplate( clsid_XSLTemplate_probes[idx], xsl );
for( int i = 0; i < DOMverNum; i++ ) {
if( CreateXSLTemplate( clsid_XSLTemplate_probes[i], xsl ) ) return true;
}
}
catch( ... ) {
TRACE0( "XSL Template creation error" );
}
return false;
}
bool CTranform::XSLProcess( IXMLDOMDocument2 *pIXMLDOMDocument, IXMLDOMDocument2 *pStyleSheet, CStringArray ¶meters, CStreamMem &mem )
{
if( !pIXMLDOMDocument || !pStyleSheet ) return false;
BOOL bResult = FALSE;
short sResult = FALSE;
HRESULT hr;
CComPtr<IXSLTemplate> pIXSLTemplate;
CComPtr<IXSLProcessor> pIXSLProcessor;
try {
if( CreateXSLTemplate( &pIXSLTemplate, theApp.GetMSXMLVersion() ) && pIXSLTemplate )
{
COM_CHECK( pStyleSheet->put_async(VARIANT_FALSE) );
COM_CHECK( pIXSLTemplate->putref_stylesheet( pStyleSheet ) );
COM_CHECK( pIXSLTemplate->createProcessor( &pIXSLProcessor ) );
if( pIXSLProcessor )
{
COM_CHECK( pIXSLProcessor->put_input( _variant_t(pIXMLDOMDocument) ) );
for( int i = 0; i < parameters.GetSize(); i++ )
{
CString &cur_par = parameters[i];
int div = cur_par.Find( '=' );
if( div > 0 )
COM_CHECK( pIXSLProcessor->addParameter( CComBSTR( cur_par.Left( div ) ),
CComVariant( cur_par.Mid( div+1 ) ) ) );
}
CComVariant var( mem.stream );
COM_CHECK( pIXSLProcessor->put_output( var ) );
COM_CHECK( pIXSLProcessor->transform( &sResult ) );
if( sResult == VARIANT_TRUE ) {
return true;
}
}
}
}
catch( HRESULT hr )
{
DisplayCOMError( "Unable to transform the documents", hr );
}
return false;
}
void CTranform::OnErrspaceXslselect()
{
AfxMessageBox( "Out of memory. Possible too many documents are opened.", MB_OK | MB_ICONERROR );
}
// --- CStreamMem ---
CStreamMem::CStreamMem() : hGlobal( 0 )
{
CreateStreamOnHGlobal( NULL, TRUE, &stream );
}
CStreamMem::~CStreamMem()
{
if( hGlobal ) GlobalUnlock( hGlobal );
}
bool CStreamMem::operator !()
{
if( stream == NULL ) return true;
if( !hGlobal ) GetHGlobalFromStream( stream, &hGlobal );
return !hGlobal;
}
const byte *CStreamMem::GetMem()
{
if( !hGlobal ) GetHGlobalFromStream( stream, &hGlobal );
return hGlobal ? (const byte *)GlobalLock( hGlobal ) : NULL;
}
int CStreamMem::GetSize()
{
if( !hGlobal ) GetHGlobalFromStream( stream, &hGlobal );
return hGlobal ? GlobalSize( hGlobal ) : 0;
}