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