ADOISAPI.CPP


//--------------------------------------------------------------------
// Microsoft ADO
//
// (c) 1996 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @moduleadoisapi.cpp | ADO ISAPI sample application
//
// @devnote None
//--------------------------------------------------------------------

#include <afxdisp.h>
#include <crtdbg.h>
#include <ole2.h>
#include <initguid.h>
#include <stdio.h>

#include "adoid.h"
#include "adoint.h"
#include "httpext.h"

VOIDPatchQuery(char *szQuery, char **ppszPatchedQuery);
HRESULTFetchData(EXTENSION_CONTROL_BLOCK *pECB);
HRESULTOutputErrors(EXTENSION_CONTROL_BLOCK *pECB, HRESULT hrError);
voidOutputString(EXTENSION_CONTROL_BLOCK *pECB, LPCSTR szBuffer);

const LPCWSTRx_lpcszSource = L"OLE_DB_NWind_Jet";
const LPCWSTRx_lpcszUser = L"Admin";
const LPCWSTRx_lpcszPassword = L"";

#defineMAX_VALUE_SIZE128
ADOConnection*g_piConnection = NULL;


// Called by the system when processes and threads are initialized and terminated,
// or upon calls to the LoadLibrary and FreeLibrary functions.
BOOL WINAPIDllEntryPoint(
HINSTANCEhinstDLL,
DWORDfdwReason,
LPVOIDlpvReserved)
{
if (DLL_PROCESS_DETACH == fdwReason)
{
if (g_piConnection)
g_piConnection->Release();
CoUninitialize();
}

return TRUE;
}


BOOL WINAPIGetExtensionVersion(
HSE_VERSION_INFO *pVer)
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );

lstrcpynA( pVer->lpszExtensionDesc,
"Sample ADO ISAPI Application",
HSE_MAX_EXT_DLL_NAME_LEN );

return TRUE;
} // GetExtensionVersion()


DWORD WINAPIHttpExtensionProc(
EXTENSION_CONTROL_BLOCK *pECB )
{
DWORDdwWritten;
charszContent[] = "Content-type: text/html\r\n\r\n";

dwWritten = sizeof(szContent);
pECB->ServerSupportFunction (pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
NULL,
&dwWritten,
(LPDWORD)szContent);

if (FAILED(FetchData(pECB)))
return HSE_STATUS_ERROR;
else
return HSE_STATUS_SUCCESS;
}


charConvertHexToDec(char cHex)
{
if ((toupper(cHex) >= 'A') && (toupper(cHex) <= 'F'))
return cHex - 'A' + 10;
else
return cHex - '0';
}

// Hack to clean up the query string. This code will work
// for most, but not all cases. For instance when the query
// string has embedded '+', this code will not work.
VOID PatchQuery(
char *szQuery,
char **ppszPatchedQuery)
{
char *p = szQuery + 1;

while (*p++)
{
if (*p == '+') //replace '+' by ' '
*p = ' ';

if (*p == '%') //a number begins
{
char ch;

if (*++p)
{
ch = ConvertHexToDec(*p) << 4; //convert the first digit

if (*++p)
{
ch |= ConvertHexToDec(*p); //convert the 2nd digit

if (!*(p + 1))
{
*(p-2) = ch;
*(p-1) = '\0';
break;
}
else
{
*(p-2) = ' ';
*(p-1) = ' ';
*p = ch;
}
}
}
}
}

*ppszPatchedQuery = szQuery + 1;
return;
}


VOID OutputString(
EXTENSION_CONTROL_BLOCK *pECB,
LPCSTR szBuffer)
{
DWORD dwBuffer = strlen(szBuffer);
pECB->WriteClient(pECB->ConnID, (PVOID) szBuffer, &dwBuffer, 0);
}


HRESULTOutputErrors(
EXTENSION_CONTROL_BLOCK *pECB,
HRESULT hrError)
{
ADOErrors*piErrors = NULL;
ADOError*piError = NULL;
HRESULThr;
BSTRbstrError;
charszBuffer[128];
LONGlErrorCount;

// output hresult
sprintf(szBuffer, "<P><H1>Error Fetching Data</H1>"
"<P><H3>HRESULT</H3> %ld", hrError);
OutputString(pECB, szBuffer);

// output error description if available
if (g_piConnection != NULL)
{
hr = g_piConnection->get_Errors(&piErrors);
if (FAILED(hr))goto ErrorExit;
hr = piErrors->get_Count(&lErrorCount);
if (FAILED(hr))goto ErrorExit;
if (lErrorCount > 0)
{
OutputString(pECB, "<p><H3>Error Description</H3>");

for (short i = 0; i < lErrorCount; i++)
{
hr = piErrors->get_Item(COleVariant(i), &piError);
if (FAILED(hr))goto ErrorExit;
hr = piError->get_Description(&bstrError);
if (FAILED(hr))goto ErrorExit;
OutputString(pECB, CString((LPCWSTR)bstrError));
OutputString(pECB, "<p>");

SysFreeString(bstrError);
piError->Release();
piError = NULL;
}
}
}

ErrorExit:
if (piError)
piError->Release();
if (piErrors)
piErrors->Release();

return hr;

}


HRESULTFetchData(
EXTENSION_CONTROL_BLOCK *pECB)
{
HRESULThr;
ADOConnection*piConnection = NULL;
ADORecordset*piRecordSet= NULL;
ADOFields*piFields = NULL;
ADOField*piField = NULL;
longlFieldCount = 0;
shorti;
COleVariantvarFieldVal;
char*pszPatchedQuery;
BSTRbstrPatchedQuery = NULL;
BSTRbstrName = NULL;
BSTRbstrSource = NULL;
BSTRbstrUser = NULL;
BSTRbstrPassword = NULL;
VARIANTvNull;
VARIANT_BOOLfEOF;


OutputString(pECB, "<HEAD><TITLE>Query Results"
"</TITLE></HEAD>\r\n<BODY>\r\n");

PatchQuery(pECB->lpszQueryString, &pszPatchedQuery);

OutputString(pECB, "<P><H1>Query String</H1>");
OutputString(pECB, pszPatchedQuery);

if ( g_piConnection == NULL )
{
bstrSource = SysAllocString( x_lpcszSource );
bstrUser = SysAllocString( x_lpcszUser );
bstrPassword = SysAllocString( x_lpcszPassword );
if ( bstrSource == NULL || bstrUser == NULL || bstrPassword == NULL ) goto errNoUninit;

hr = CoInitialize(NULL);
if (FAILED(hr))goto errNoUninit;

hr = CoCreateInstance(CLSID_CADOConnection, NULL, CLSCTX_INPROC_SERVER, IID_IADOConnection, (LPVOID *)&piConnection);
if (FAILED(hr))
{
CoUninitialize();
goto errNoUninit;
}

hr = piConnection->Open( bstrSource, bstrUser, bstrPassword );
if (FAILED(hr))
{
piConnection->Release();
CoUninitialize();
goto errNoUninit;
}

g_piConnection = piConnection;
}

hr = CoInitialize(NULL);
if (FAILED(hr))goto errNoUninit;

hr = CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_INPROC_SERVER, IID_IADORecordset, (LPVOID *)&piRecordSet);
if (FAILED(hr))goto errFreeStuff;

// Allocate BSTR.
bstrPatchedQuery = SysAllocStringLen(NULL, strlen(pszPatchedQuery) );

//Check returned BSTR.
if (bstrPatchedQuery == NULL )goto errFreeStuff;

// Convert the multibyte string to a wide-character string.
if ( MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszPatchedQuery, strlen(pszPatchedQuery), bstrPatchedQuery, strlen(pszPatchedQuery)) == 0 )
goto errFreeStuff;

hr = piRecordSet->put_Source(bstrPatchedQuery);
if (FAILED(hr))goto errFreeStuff;

hr = piRecordSet->putref_ActiveConnection(g_piConnection);
if (FAILED(hr))goto errFreeStuff;

vNull.vt = VT_ERROR;
vNull.scode = DISP_E_PARAMNOTFOUND;
hr = piRecordSet->Open(vNull, vNull, adOpenKeyset, adLockOptimistic, adCmdText);
if (FAILED(hr))goto errFreeStuff;

hr = piRecordSet->get_Fields(&piFields);
if (FAILED(hr))goto errFreeStuff;
hr = piFields->get_Count(&lFieldCount);
if (FAILED(hr))goto errFreeStuff;


OutputString(pECB, "<P><H1>Query Results</H1>");
OutputString(pECB, "<P><TABLE BORDER=1 CELLSPACING=4>");

//
// print column names
//
OutputString(pECB, "<TR>");

for ( i = 0; i < lFieldCount; i++ )
{
OutputString(pECB, "<TH>");

hr = piFields->get_Item(COleVariant(i), &piField);
if (FAILED(hr))goto errFreeStuff;
hr = piField->get_Name(&bstrName);
if (FAILED(hr))goto errFreeStuff;

OutputString(pECB, CString(bstrName)); //convert bstr to CString

SysFreeString(bstrName);
piField->Release();
piField = NULL;
}

//
// print data
//
hr = piRecordSet->get_EOF(&fEOF);
if (FAILED(hr))goto errFreeStuff;
while (!fEOF)
{
OutputString(pECB, "<TR>");

for (i = 0; i < lFieldCount; i++)
{
OutputString(pECB, "<TD>");

hr = piFields->get_Item(COleVariant(i), &piField);
if (FAILED(hr))goto errFreeStuff;
hr = piField->get_Value(&varFieldVal);
if (FAILED(hr))goto errFreeStuff;

if (FAILED(VariantChangeType(&varFieldVal, &varFieldVal, 0, VT_BSTR)))
OutputString(pECB, "N/A");
else
OutputString(pECB, CString(varFieldVal.bstrVal));

varFieldVal.Clear();
piField->Release();
piField = NULL;
}

OutputString(pECB, "</TR>");

hr = piRecordSet->MoveNext();
if (FAILED(hr))goto errFreeStuff;

hr = piRecordSet->get_EOF(&fEOF);
if (FAILED(hr))goto errFreeStuff;
}

OutputString(pECB, "</TABLE>");
OutputString(pECB, "</BODY>\r\n");

errFreeStuff:
if (piField)
piField->Release();
if (piFields)
piFields->Release();
if (piRecordSet)
piRecordSet->Release();
CoUninitialize();

errNoUninit:
SysFreeString(bstrSource);
SysFreeString(bstrUser);
SysFreeString(bstrPassword);
SysFreeString(bstrPatchedQuery);

if (FAILED(hr))
{
TCHAR szBuf[256];
wsprintf(szBuf, _T("Error: %d \n"), hr);
OutputErrors(pECB, hr);
}
OutputString(pECB, "</BODY>\r\n");

return hr;
}