Click here to Skip to main content
15,893,668 members
Articles / Desktop Programming / ATL

XML Transform Shell Extension

Rate me:
Please Sign up or sign in to vote.
4.08/5 (12 votes)
11 Oct 20033 min read 85.4K   1.6K   27  
A shell extension to transform xml files against a stylesheet
// xmlTransformerShlExt.cpp : Implementation of CxmlTransformerShlExt

#include "stdafx.h"
#include <comdef.h>
#include <shlobj.h>
#include <atlstr.h>
#include <atlfile.h>
#include "xmlTransformerShlExt.h"


// CxmlTransformerShlExt



STDMETHODIMP CxmlTransformerShlExt::Initialize( LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID )
{
    if(!lpdobj)
        return E_POINTER;

    STGMEDIUM stgMedium;
    FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

    if( FAILED(lpdobj->GetData( &format, &stgMedium ) ) )
        return E_INVALIDARG;

    // get the file path for input
    TCHAR szFile[MAX_PATH];
    DragQueryFile( reinterpret_cast< HDROP >( stgMedium.hGlobal ), 0, szFile, MAX_PATH );
    
    bstrInputFile = szFile;
    ReleaseStgMedium( &stgMedium );

    return S_OK;
}

STDMETHODIMP CxmlTransformerShlExt::QueryContextMenu( HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
{
    HRESULT hr;

    MENUITEMINFO mii;
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask = MIIM_ID | MIIM_TYPE;
	mii.fType = MFT_STRING;
	mii.wID = idCmdFirst;
	mii.dwTypeData = _T("T&ransform with...");

	if( InsertMenuItem(hmenu, indexMenu, TRUE, &mii))
		hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, 1);

    return hr;
}

STDMETHODIMP CxmlTransformerShlExt::GetCommandString( UINT idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax )
{

    if( uFlags & GCS_HELPTEXT )
    {

        // verify size of characters
        OSVERSIONINFO ovi;
        ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        GetVersionEx( &ovi );

        if( ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
        {
            wchar_t* pszDesc = L"Transform this file with an xsl/xslt file";
            UINT cch = min( static_cast<UINT>(wcslen(pszDesc)) + 1, cchMax);
            wcsncpy( reinterpret_cast<wchar_t*>(pszName), pszDesc, cch );
        }
        else
        {
            char* pszDesc = "Transform this file with an xsl/xslt file";
            UINT cch = min( static_cast<UINT>(strlen(pszDesc)) + 1, cchMax);
            strncpy( pszName, pszDesc, cch );
        }
        
    }
    
    return S_OK;
}

STDMETHODIMP CxmlTransformerShlExt::InvokeCommand( LPCMINVOKECOMMANDINFO pici )
{

    // We need to get the xsl/xslt file to use in the transform
    TCHAR szStyleSheet[MAX_PATH];

    if(!GetStyleSheet( szStyleSheet, MAX_PATH ))
        return S_FALSE;

    try
    {
        // load the stylesheet into a DOM
        MSXML2::IXMLDOMDocument2Ptr spStyleSheet;
        spStyleSheet.CreateInstance(__uuidof(MSXML2::DOMDocument) );
        spStyleSheet->put_async( VARIANT_FALSE );

        if( spStyleSheet->load( _variant_t( szStyleSheet )) == VARIANT_FALSE )
        {
            ReportParseError( spStyleSheet->parseError, szStyleSheet );
            return S_FALSE;
        }


        // load the xml source
        MSXML2::IXMLDOMDocument2Ptr spSrcXML;
        spSrcXML.CreateInstance(__uuidof(MSXML2::DOMDocument) );
        spSrcXML->put_async( VARIANT_FALSE );

        if( spSrcXML->load( _variant_t( bstrInputFile )) == VARIANT_FALSE )
        {
            ReportParseError( spSrcXML->parseError,  bstrInputFile );
            return S_FALSE;
        }

        // transform the document and display the data
        WriteOutputAndDisplay(spSrcXML->transformNode( spStyleSheet ).GetBSTR() );

    }
    catch( _com_error e)
    {
        MessageBox(pici->hwnd, e.ErrorMessage(), _T("Error"), MB_OK | MB_ICONSTOP );
        return e.Error();
    }
    
    return S_OK;
}

BOOL CxmlTransformerShlExt::GetStyleSheet(TCHAR *filePath, UINT len)
{

    TCHAR szFileTitle[_MAX_FNAME];
    TCHAR* pszFilter = _T("XSL/XSLT Files (*.xsl;*.xslt)\0*.xsl;*.xslt\0\0");

    // clear the strings
    memset( szFileTitle, 0, _MAX_FNAME );
    memset( filePath, 0, len);

    OPENFILENAME ofn;
    memset( &ofn, 0, sizeof(ofn) );
    ofn.lStructSize = sizeof(ofn);
    ofn.lpstrTitle = szFileTitle;
    ofn.nMaxFileTitle = _MAX_FNAME;
    ofn.lpstrFile = filePath;
    ofn.nMaxFile = len;
    ofn.lpstrFilter = pszFilter;
    ofn.Flags =  OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY;
    ofn.hwndOwner = ::GetActiveWindow();

    if(! ::GetOpenFileName(&ofn))
        // user canceled: notify caller that the operation failed
        return FALSE;

    return TRUE;
}

void CxmlTransformerShlExt::ReportParseError(MSXML2::IXMLDOMParseErrorPtr pParseError, TCHAR *inputDoc)
{
    CString msg;
    CString src = pParseError->srcText.GetBSTR();
    

    int badChar = 0;
    int maxLen = 0;
    if(src.GetLength() < 120)
        maxLen = src.GetLength();
    else
    {
        // move to the bad character
        for(int x=0; x < pParseError->line - 1; x++)
            badChar = src.Find(_T("\n"), badChar);

        // get 120 characters starting at 60 before error
        badChar -= (60 - pParseError->linepos);  
        maxLen = 120;
    }


    msg.Format( _T("Error in %s\r\nErrorCode: 0x%x\r\nLine: %d Position: %d\r\nReason: %s\r\nSource:\r\n%s"),
                inputDoc,                       // file path of the data that has errors
                pParseError->errorCode,         // error code
                pParseError->line,              // source line number
                pParseError->linepos,           // position on line
                pParseError->reason.GetBSTR(),  // parse error reason
                src.Mid(badChar, maxLen));      // part of the source surrounding the error


    WriteOutputAndDisplay(CComBSTR(msg));
}

void CxmlTransformerShlExt::WriteOutputAndDisplay(CComBSTR output)
{

    // write to a file
    
    CAtlFile oFile;
    if(FAILED(oFile.Create( szTempFilePath, GENERIC_WRITE, FILE_SHARE_READ, 
                    CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL )))
    {
        MessageBox(::GetActiveWindow(), _T("Error creating output file"),
                _T("Error"), MB_OK|MB_ICONSTOP);
        return;
    }

    oFile.Write( output.m_str, output.ByteLength() );
    oFile.Flush();
    oFile.Close();


    // display in notepad
    ShellExecute( ::GetDesktopWindow(), 
                    NULL,
                    _T("notepad.exe"), 
                    szTempFilePath, 
                    NULL, 
                    SW_SHOWDEFAULT );
 
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions