IIS Native Module RegisterModule function not invoked - c++

I compiled IIS Native Module. If I compile 32bit and install in IIS. It gives error
The Module DLL ... failed to load. The data is the error. Data is 7E000000
If I compile 64 bit and install it in IIS, I have no error but module is not working.
I added code to write to log. When I use C:\Windows\System32\inetsrv\w3wp.exe in debugging property and debug it works and writes to log but when I use it in IIS neither RegisterModule is invoked, nor any of the notifications.
Any idea what may be wrong?
In Visual Studio elevated mode I can debug the dll just fine. Both 32 bit and 64 bit work just fine in debugging. It returns the data I want to return instead of returning actual page content. It is strange that same w3wp.exe running in IIS doesn't work with dll.
Update:
It works in Windows 7 IIS but doesn't work on Windows 10 IIS. Wondering what may be the difference.
main.cpp
#include "precomp.h"
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
// Global server instance
IHttpServer * g_pHttpServer = NULL;
// Global module context id
PVOID g_pModuleContext = NULL;
#define DTTMFMT "%Y-%m-%d %H:%M:%S "
#define DTTMSZ 21
static char* getDtTm(char* buff) {
time_t t = time(0);
strftime(buff, DTTMSZ, DTTMFMT, localtime(&t));
return buff;
}
// The RegisterModule entrypoint implementation.
// This method is called by the server when the module DLL is
// loaded in order to create the module factory,
// and register for server events.
HRESULT
__stdcall
RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pHttpServer
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << " RegisterModule.\n";
myfile.close();
HRESULT hr = S_OK;
CJCFilterFactory * pFactory = NULL;
if ( pModuleInfo == NULL || pHttpServer == NULL )
{
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Finished;
}
// step 1: save the IHttpServer and the module context id for future use
g_pModuleContext = pModuleInfo->GetId();
g_pHttpServer = pHttpServer;
// step 2: create the module factory
pFactory = new CJCFilterFactory();
if ( pFactory == NULL )
{
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
goto Finished;
}
// step 3: register for server events
// TODO: register for more server events here
hr = pModuleInfo->SetRequestNotifications( pFactory, /* module factory */
RQ_ACQUIRE_REQUEST_STATE | RQ_BEGIN_REQUEST/* server event mask */,
0 /* server post event mask */);
if ( FAILED( hr ) )
{
goto Finished;
}
// Set the request priority.
hr = pModuleInfo->SetPriorityForRequestNotification(
RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
if (FAILED(hr))
{
goto Finished;
}
pFactory = NULL;
Finished:
if ( pFactory != NULL )
{
delete pFactory;
pFactory = NULL;
}
return hr;
}
JCFilter.cpp
#include "precomp.h"
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
#define DTTMFMT "%Y-%m-%d %H:%M:%S "
#define DTTMSZ 21
static char* getDtTm(char* buff) {
time_t t = time(0);
strftime(buff, DTTMSZ, DTTMFMT, localtime(&t));
return buff;
}
// Implementation of the OnAcquireRequestState method
REQUEST_NOTIFICATION_STATUS
CJCFilter::OnAcquireRequestState(
IN IHttpContext * pHttpContext,
IN OUT IHttpEventProvider * pProvider
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << " OnAcquireRequestState.\n";
myfile.close();
HRESULT hr = S_OK;
// TODO: implement the AcquireRequestState module functionality
Finished:
if ( FAILED( hr ) )
{
return RQ_NOTIFICATION_FINISH_REQUEST;
}
else
{
return RQ_NOTIFICATION_CONTINUE;
}
}
REQUEST_NOTIFICATION_STATUS
CJCFilter::OnBeginRequest(
IN IHttpContext* pHttpContext,
IN IHttpEventProvider* pProvider
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << "OnBeginRequest.\n";
myfile.close();
UNREFERENCED_PARAMETER(pProvider);
// Create an HRESULT to receive return values from methods.
HRESULT hr;
// Retrieve a pointer to the response.
IHttpResponse* pHttpResponse = pHttpContext->GetResponse();
// Test for an error.
if (pHttpResponse != NULL)
{
// Clear the existing response.
pHttpResponse->Clear();
// Set the MIME type to plain text.
pHttpResponse->SetHeader(
HttpHeaderContentType, "text/plain",
(USHORT)strlen("text/plain"), TRUE);
// Create a string with the response.
PCSTR pszBuffer = "Hello World!";
// Create a data chunk.
HTTP_DATA_CHUNK dataChunk;
// Set the chunk to a chunk in memory.
dataChunk.DataChunkType = HttpDataChunkFromMemory;
// Buffer for bytes written of data chunk.
DWORD cbSent;
// Set the chunk to the buffer.
dataChunk.FromMemory.pBuffer =
(PVOID)pszBuffer;
// Set the chunk size to the buffer size.
dataChunk.FromMemory.BufferLength =
(USHORT)strlen(pszBuffer);
// Insert the data chunk into the response.
hr = pHttpResponse->WriteEntityChunks(
&dataChunk, 1, FALSE, TRUE, &cbSent);
// Test for an error.
if (FAILED(hr))
{
// Set the HTTP status.
pHttpResponse->SetStatus(500, "Server Error", 0, hr);
}
// End additional processing.
return RQ_NOTIFICATION_FINISH_REQUEST;
}
// Return processing to the pipeline.
return RQ_NOTIFICATION_CONTINUE;
}
// TODO: implement other desired event handler methods below

Related

Access MSMQ from C++ (non COM component) code

I am new to the concept of MSMQ(Microsoft Message Queues). I had a glimpse of the sample code from Microsoft's link and am trying to create a simple MSMQ queue. Here is my full code (mostly from Microsoft's link).
#include "stdafx.h"
#include "windows.h"
#include "mq.h"
#pragma comment (lib, "Mqrt.lib")
#include "tchar.h"
#include <stdio.h>
#define BUFLEN = 256;
#include <iostream>
HRESULT CreateMSMQQueue(
LPWSTR wszPathName,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPWSTR wszOutFormatName,
DWORD *pdwOutFormatNameLength
)
{
// Define the maximum number of queue properties.
const int NUMBEROFPROPERTIES = 2;
// Define a queue property structure and the structures needed to initialize it.
MQQUEUEPROPS QueueProps;
MQPROPVARIANT aQueuePropVar[NUMBEROFPROPERTIES];
QUEUEPROPID aQueuePropId[NUMBEROFPROPERTIES];
HRESULT aQueueStatus[NUMBEROFPROPERTIES];
HRESULT hr = MQ_OK;
// Validate the input parameters.
if (wszPathName == NULL || wszOutFormatName == NULL || pdwOutFormatNameLength == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Set queue properties.
DWORD cPropId = 0;
aQueuePropId[cPropId] = PROPID_Q_PATHNAME;
aQueuePropVar[cPropId].vt = VT_LPWSTR;
aQueuePropVar[cPropId].pwszVal = wszPathName;
cPropId++;
WCHAR wszLabel[MQ_MAX_Q_LABEL_LEN] = L"Test Queue";
aQueuePropId[cPropId] = PROPID_Q_LABEL;
aQueuePropVar[cPropId].vt = VT_LPWSTR;
aQueuePropVar[cPropId].pwszVal = wszLabel;
cPropId++;
// Initialize the MQQUEUEPROPS structure.
QueueProps.cProp = cPropId; // Number of properties
QueueProps.aPropID = aQueuePropId; // IDs of the queue properties
QueueProps.aPropVar = aQueuePropVar; // Values of the queue properties
QueueProps.aStatus = aQueueStatus; // Pointer to the return status
// Call MQCreateQueue to create the queue.
WCHAR wszFormatNameBuffer[256];
DWORD dwFormatNameBufferLength = 256;
hr = MQCreateQueue(pSecurityDescriptor, // Security descriptor
&QueueProps, // Address of queue property structure
wszFormatNameBuffer, // Pointer to format name buffer
&dwFormatNameBufferLength); // Pointer to receive the queue's format name length in Unicode characters not bytes.
// Return the format name if the queue is created successfully.
if (hr == MQ_OK || hr == MQ_INFORMATION_PROPERTY)
{
if (*pdwOutFormatNameLength >= dwFormatNameBufferLength)
{
wcsncpy_s(wszOutFormatName, *pdwOutFormatNameLength - 1, wszFormatNameBuffer, _TRUNCATE);
wszOutFormatName[*pdwOutFormatNameLength - 1] = L'\0';
*pdwOutFormatNameLength = dwFormatNameBufferLength;
}
else
{
wprintf(L"The queue was created, but its format name cannot be returned.\n");
}
}
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout<<"started!";
LPWSTR sam = L".\\myQueue";
LPWSTR out_name = L"Sampleoutput";
DWORD d1 = 60;
DWORD *dd = &d1;
HRESULT hs = CreateMSMQQueue(sam,pt,out_name,dd);
return 0;
}
I didn't change much of the code. When I run this code, I get an "The application was unable to start correctly(0x0000142)" error. By debugging I found out tat its due to an "Memory access error" but there is no hint as to where it occurs. Please help me out!
Is there any format for queue names? Or the output format name ?

How to interact with internet explorer C++

I have a school project that I am working on and the outcome is pointless it seems, but it's got more to do with the experience gained through this I believe.
What I am trying to do is submit an initial URL, then pull all the URLs on that page and visit them in order and do this until I tell it to stop. All of the URLs will be recorded in a text file.
So far, I am able to open a window in IE and launch a webpage of my choosing. So now I need to know how to send IE to a new webpage using the same session and also how I can scan and pull data from the websites I visit. Thanks for any help!
Here is my code so far:
#include <string>
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
using namespace std;
int main( int argc, TCHAR *argv[] )
{
std::string uRL, prog;
int length, count;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//if( argc != 2 )
//{
// printf("Usage: %s [cmdline]\n", argv[0]);
// system("PAUSE");
// return 0;
//}
std::cout << "Enter URL: ";
std::cin >> uRL;
prog = ("C:\\Program Files\\Internet Explorer\\iexplore.exe ") + uRL;
char *cstr = new char[prog.length() + 1];
strcpy(cstr, prog.c_str());
// Start the child process.
if( !CreateProcess(NULL, // No module name (use command line)
_T(cstr), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
system("PAUSE");
return 0;
}
cout << HRESULT get_Count(long *Count) << endl;
//cout << count << endl;
system("PAUSE");
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
delete [] cstr;
return 0;
}
If you want to crawl a webpage launching Internet Explorer is not going to work very well. I also don't recommend attempting to parse the HTML page yourself unless you are prepared for a lot of heartache and hassle. Instead I recommend that you create an instance of an IWebBrowser2 object and use it to navigate to the webpage, grab the appropriate IHTMLDocument2 object and iterate through the elements picking out the URL's. It's far easier and is a common approach using components that are already installed on Windows. The example below should get your started and on your way to crawling the web like proper spider should.
#include <comutil.h> // _variant_t
#include <mshtml.h> // IHTMLDocument and IHTMLElement
#include <exdisp.h> // IWebBrowser2
#include <atlbase.h> // CComPtr
#include <string>
#include <iostream>
#include <vector>
// Make sure we link in the support library!
#pragma comment(lib, "comsuppw.lib")
// Load a webpage
HRESULT LoadWebpage(
const CComBSTR& webpageURL,
CComPtr<IWebBrowser2>& browser,
CComPtr<IHTMLDocument2>& document)
{
HRESULT hr;
VARIANT empty;
VariantInit(&empty);
// Navigate to the specifed webpage
hr = browser->Navigate(webpageURL, &empty, &empty, &empty, &empty);
// Wait for the load.
if(SUCCEEDED(hr))
{
READYSTATE state;
while(SUCCEEDED(hr = browser->get_ReadyState(&state)))
{
if(state == READYSTATE_COMPLETE) break;
}
}
// The browser now has a document object. Grab it.
if(SUCCEEDED(hr))
{
CComPtr<IDispatch> dispatch;
hr = browser->get_Document(&dispatch);
if(SUCCEEDED(hr) && dispatch != NULL)
{
hr = dispatch.QueryInterface<IHTMLDocument2>(&document);
}
else
{
hr = E_FAIL;
}
}
return hr;
}
void CrawlWebsite(const CComBSTR& webpage, std::vector<std::wstring>& urlList)
{
HRESULT hr;
// Create a browser object
CComPtr<IWebBrowser2> browser;
hr = CoCreateInstance(
CLSID_InternetExplorer,
NULL,
CLSCTX_SERVER,
IID_IWebBrowser2,
reinterpret_cast<void**>(&browser));
// Grab a web page
CComPtr<IHTMLDocument2> document;
if(SUCCEEDED(hr))
{
// Make sure these two items are scoped so CoUninitialize doesn't gump
// us up.
hr = LoadWebpage(webpage, browser, document);
}
// Grab all the anchors!
if(SUCCEEDED(hr))
{
CComPtr<IHTMLElementCollection> urls;
long count = 0;
hr = document->get_all(&urls);
if(SUCCEEDED(hr))
{
hr = urls->get_length(&count);
}
if(SUCCEEDED(hr))
{
for(long i = 0; i < count; i++)
{
CComPtr<IDispatch> element;
CComPtr<IHTMLAnchorElement> anchor;
// Get an IDispatch interface for the next option.
_variant_t index = i;
hr = urls->item( index, index, &element);
if(SUCCEEDED(hr))
{
hr = element->QueryInterface(
IID_IHTMLAnchorElement,
reinterpret_cast<void **>(&anchor));
}
if(SUCCEEDED(hr) && anchor != NULL)
{
CComBSTR url;
hr = anchor->get_href(&url);
if(SUCCEEDED(hr) && url != NULL)
{
urlList.push_back(std::wstring(url));
}
}
}
}
}
}
int main()
{
HRESULT hr;
hr = CoInitialize(NULL);
std::vector<std::wstring> urls;
CComBSTR webpage(L"http://cppreference.com");
CrawlWebsite(webpage, urls);
for(std::vector<std::wstring>::iterator it = urls.begin();
it != urls.end();
++it)
{
std::wcout << "URL: " << *it << std::endl;
}
CoUninitialize();
return 0;
}
To scan and pull data from the websites, you'll want to capture the HTML and iterate through it looking for all character sequences matching a certain pattern. Have you ever used regular expressions? Regular expressions would by far be the best here, but if you understand them (just look up a tutorial on the basics) then you can manually apply the pattern-recognition concepts to this project.
So what you're looking for is something like http(s)://.. It's more complex though, because domain names are a rather intricate pattern. You'll probably want to use a third-party HTML parser or regular expression library, but it's doable without it, although pretty tedious to program.
Here's a link about regular expressions in c++:
http://www.johndcook.com/cpp_regex.html

Using ETW to print time stamp on context switch

I am using the following code that I found on Microsoft's website. It compiles successfully and outputs a log file, as it's supposed to:
#include "stdafx.h"
#define INITGUID // Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"C:\\Documents and Settings\\Administrator\\My Documents\\My Dropbox\\Log.etl"
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
TRACEHANDLE SessionHandle = 0;
EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
ULONG BufferSize = 0;
// Allocate memory for the session properties. The memory must
// be large enough to include the log file name and session name,
// which get appended to the end of the session properties structure.
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME);
pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);
if (NULL == pSessionProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
goto cleanup;
}
// Set the session properties. You only append the log file name
// to the properties structure; the StartTrace function appends
// the session name for you.
ZeroMemory(pSessionProperties, BufferSize);
pSessionProperties->Wnode.BufferSize = BufferSize;
pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
pSessionProperties->Wnode.Guid = SystemTraceControlGuid;
pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
pSessionProperties->MaximumFileSize = 5; // 5 MB
pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME);
StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
// Create the trace session.
status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
if (ERROR_SUCCESS != status)
{
if (ERROR_ALREADY_EXISTS == status)
{
wprintf(L"The NT Kernel Logger session is already in use.\n");
}
else
{
wprintf(L"EnableTrace() failed with %lu\n", status);
getchar();
}
goto cleanup;
}
wprintf(L"Press any key to end trace session ");
_getch();
cleanup:
if (SessionHandle)
{
status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
{
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
}
if (pSessionProperties)
free(pSessionProperties);
}
I am wondering if there is a way to modify this code to make it print a time stamp when it detects a context switch. Anyone have any ideas?

NT Kernel Logger Session Log Not Being Created

I am trying to compile the following code I got from one of Microsoft's websites (original):
#include "stdafx.h"
#define INITGUID // Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"C:\Documents and Settings\Administrator\My Documents\My Dropbox\Log.etl"
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
TRACEHANDLE SessionHandle = 0;
EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
ULONG BufferSize = 0;
// Allocate memory for the session properties. The memory must
// be large enough to include the log file name and session name,
// which get appended to the end of the session properties structure.
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME);
pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);
if (NULL == pSessionProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
goto cleanup;
}
// Set the session properties. You only append the log file name
// to the properties structure; the StartTrace function appends
// the session name for you.
ZeroMemory(pSessionProperties, BufferSize);
pSessionProperties->Wnode.BufferSize = BufferSize;
pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
pSessionProperties->Wnode.Guid = SystemTraceControlGuid;
pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_NETWORK_TCPIP;
pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
pSessionProperties->MaximumFileSize = 5; // 5 MB
pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME);
StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
// Create the trace session.
status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
if (ERROR_SUCCESS != status)
{
if (ERROR_ALREADY_EXISTS == status)
{
wprintf(L"The NT Kernel Logger session is already in use.\n");
}
else
{
wprintf(L"EnableTrace() failed with %lu\n", status);
getchar();
}
goto cleanup;
}
wprintf(L"Press any key to end trace session ");
_getch();
cleanup:
if (SessionHandle)
{
status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
{
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
}
if (pSessionProperties)
free(pSessionProperties);
}
The program seems to run successfully, but the log file is never created. Anyone know what the problem is? I am using Windows XP.
You should replace '\' in LOGFILE_PATH with '\\'. Otherwise it will be treated as escape sequence

MSXML. Get data as Base64

I'm using C++ with MSXML and want to get data from XML file as Base64. I'm using this code:
hr = nodeList->get_item((long)i, (IXMLDOMNode **)&vXMLNode);
if ( FAILED(hr) )
throw "Unable to retrieve child node";
vXMLNode->put_dataType(_bstr_t("bin.base64"));
hr = vXMLNode->get_nodeTypedValue(&varValue);
if ( FAILED(hr) )
throw "Unable to retrieve 'xmltext' text";
So vXMLNode is a child node with data. Node type of vXMLNode is NODE_ELEMENT. If I check data type for this node, I get VT_NULL. Therefore I get my data as a string.
What is wrong in my code?
I believe the problem lies outside of your supplied sample code. Here's a working console program that uses nodeTypedValue. I hope this helps.
// Base64CPP.cpp : Defines the entry point for the console application.
// NOTE:
// This code is provided as is in the form of a sample with no warranties of any kind,
// either expressed or implied for any purpose. Use at your own risk.
#include "stdafx.h"
#include <TCHAR.H>
#include <stdio.h>
#include <sys/stat.h>
#include <fstream>
#include <string.h>
#include <atlbase.h>
#import <msxml4.dll> named_guids
using namespace MSXML2;
inline void EVAL_HR( HRESULT _hr )
{ if FAILED(_hr) throw(_hr); }
// Binary to Base64 Encoding
bool DoEncoding(LPCTSTR lpszXMLFile, LPCTSTR lpszBinFile)
{
bool bRetVal = false;
try
{
long lFileSize;
struct stat fileSizeVal;
// Get the file size
if (stat(lpszBinFile, &fileSizeVal) == 0)
{
lFileSize = fileSizeVal.st_size;
if(lFileSize <= 0)
return false;
}
else
return false;
// Instantiate XML DOMDocument
CComPtr<IXMLDOMDocument2> spXMLDoc;
CComPtr<MSXML2::IXMLDOMElement> spDataElement;
HRESULT hr = spXMLDoc.CoCreateInstance(CLSID_DOMDocument40);
EVAL_HR(hr);
spXMLDoc->loadXML(_T("<?xml version='1.0' encoding='UTF-8'?> <Data/>"));
// Prepare the top node to store binary data as base64
spDataElement = spXMLDoc->documentElement;
ATLASSERT(spDataElement != NULL && _T("Failed to get document element."));
hr = spDataElement->put_dataType(CComBSTR(_T("bin.base64")));
EVAL_HR(hr);
// Read the file into memory
std::ifstream binDataFile;
binDataFile.open(lpszBinFile, std::ios::binary);
binDataFile.seekg(std::ios::beg);
SAFEARRAY* psa = SafeArrayCreateVector( VT_UI1, 0L, lFileSize);
binDataFile.read((char*)psa->pvData, lFileSize);
binDataFile.close();
// Save the binary data into Data node
VARIANT var;
VariantInit(&var);
var.parray = psa;
var.vt = (VT_ARRAY | VT_UI1 );
spDataElement->nodeTypedValue = var;
// Save the XML Document
spXMLDoc->save(lpszXMLFile);
bRetVal = true;
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
return bRetVal;
}
// Base64 to binary decoding
bool DoDecoding(LPCTSTR lpszXMLFile, LPCTSTR lpszBinFile)
{
bool bRetVal = false;
try
{
// Instantiate DOMDocument and load XML file
CComPtr<IXMLDOMDocument2> spXMLDoc;
CComPtr<MSXML2::IXMLDOMElement> spDataElement;
HRESULT hr = spXMLDoc.CoCreateInstance(CLSID_DOMDocument40);
EVAL_HR(hr);
CComVariant vtFileName = CComBSTR(lpszXMLFile);
spXMLDoc->load(vtFileName);
// ASSUMPTION: documentElement (top element) contains base64 data
spDataElement = spXMLDoc->documentElement;
ATLASSERT(spDataElement != NULL && _T("Failed to get document element."));
// Prepare the file for writing
std::ofstream binDataFile (lpszBinFile, std::ios::out | std::ios::binary);
// Save the binary data into data file
long lDataLength=0;
hr = SafeArrayGetUBound(spDataElement->nodeTypedValue.parray, 1, &lDataLength);
EVAL_HR(hr);
lDataLength++;
binDataFile.write((char*)(spDataElement->nodeTypedValue.parray->pvData), lDataLength);
binDataFile.close();
bRetVal = true;
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
return bRetVal;
}
int main(int argc, char* argv[])
{
if(argc < 4)
{//insufficient parameters
printf(_T("\nSample app to encode/decode binary data as base64 XML using MSXML.\n"));
printf(_T("\nUsage:\tBase64CPP.exe <e>|<d> <XMLFileName> <BinaryDataFile>"));
printf(_T("\n\nExamples:"));
printf(_T("\n\tEncode binary data in 1.jpg and save as Base64 into 1.xml:"));
printf(_T("\n\t\tBase64CPP.exe e c:\\1.xml c:\\1.jpg\n"));
printf(_T("\n\tDecode base64 data in 1.xml and save as binary into 2.jpg:"));
printf(_T("\n\t\tBase64CPP.exe d c:\\1.xml c:\\2.jpg\n\n"));
return -1;
}
try
{
HRESULT hr = CoInitialize(NULL);
EVAL_HR(hr);
if(_tcsicmp(argv[1], _T("e")) == 0)
{
if(DoEncoding(argv[2], argv[3]))
printf(_T("Success. See %s for results."), argv[2]);
else
printf(_T("Failed."));
}
else
{
if(DoDecoding(argv[2], argv[3]))
printf(_T("Success. See %s for results."), argv[3]);
else
printf(_T("Failed."));
}
}
catch(int)
{
//TODO: Error handling
printf(_T("Exception raised!"));
}
CoUninitialize();
getchar();
return 0;
}