Introduction
This article presents a way to retrieve the GET
-POST
data from a form in an ISAPI extension. Two helpful collections class of parameters are also provided. Because a non MFC ISAPI extension is more reliable regarding the speed and the simultaneous number of connections, a non MFC version is included.
Functionality
Both MFC and Non MFC versions use Vector, Map and String STL based classes, with non MFC code inside. In the MFC version, the string
collection are based on _bstr_t
type. In non MFC version, the string
collection is based on STL String type. So, the MFC version is using the ISAPI MFC based macros to retrieve the server variables and parameters data while the non MFC version uses the WriteClient
and ServerSupportFunction
HTTP functions.
The default method writes to the browser a complex form with check boxes, edit boxes, radio buttons, text area - even a file type edit box. The idea is to receive all the POST
parameters into the same DLL extension. The form is loaded from an HTML string
resource using the LoadLongResource
helper function. This reduces the time needed to build the page because the string
is loaded into memory on the first call of the extension. How to use the HTML string
resources in your Visual Studio project is shown in my ADO Data access from ISAPI article.
The GET
data is received very easily since that type of data is sent from the browser to the server using the URL. The POST
data variables are transparent to the user and it is possible to transfer large amount of data. For more information about GET
/POST
data, see my HTTP GET-POST utility article.
MFC Version
The C++ classes used to store parameters from the data collection are Twin
and TwinVector
. The Default method of the ISAPI MFC version writes to the client browser the IDR_HTML_FORM
resource. FormRequest
is the method that receives the control after you click on the "Submit Query" button.
void CPostDataExtension::FormRequest(CHttpServerContext* pCtxt,
void* pVoid, DWORD dwBytes)
{
TwinVector vecServerCtx(pCtxt, (LPTSTR)pVoid);
WriteServerData(pCtxt);
WriteServerVar(pCtxt, vecServerCtx);
}
A little problem is to get the control from the DLL entry point to FormRequest
method. Under the MFC, that is done very easy, using the macros:
DEFAULT_PARSE_COMMAND(FormRequest, CPostDataExtension)
ON_PARSE_COMMAND(FormRequest, CPostDataExtension, ITS_RAW)
To correctly know what method will receive the POST
data, the MFC wrapper must receive from the HTML form one hidden parameter, which must be in the first place after the FORM
HTML tag:
<form action="PostData.dll?" method=post>
<input TYPE=hidden NAME="MfcISAPICommand" VALUE="FormRequest">
In the WriteServerVar
helper function, the server context variables collection is written on the HTTP stream. It's possible to directly obtain the value of a needed parameter:
bstrValue = vecServerCtx.Find(L"Filename").
for (itVec = vecServerCtx.begin(); itVec != vecServerCtx.end(); itVec++)
*pCtxt << <itvec->GetName() << " = " <<<itvec-> GetValue() << "br";
</itvec-></itvec->
In the same WriteServerVar
helper function, the POST
data collection is written to the HTTP stream in this way.
bstrToken = L"DATA";
index = vecServerCtx.Find(bstrToken);
if (index > -1)
{
map = vecServerCtx[index].GetValueAsMap();
if (!map.empty())
for (itMap = map.begin(); itMap != map.end(); itMap++)
*pCtxt << (*itMap).first << " = "
<< (*itMap).second << "br";
}
It's possible to directly obtain the value of a needed parameter:
*pCtxt << "Filename = " << map[L"Filename"] << "br".
The TwinVector
class offer the VARIANT GetVariant()
method and TwinVector(VARIANT varSafe)
constructor, to easy transport the collection over network between COM+ components.
Non MFC Version
The non MFC version is based on the MSDN article regarding GET
-POST
data in ISAPI extensions.
The C++ extension receives the entry point in the DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK pECB )
method.
Here, it launches the Run
method of the CWriteFormExtension class
- there is only one running object in our ISAPI extension.
The C++ classes used to keep the parameters in the data collection are MultipartParser
and MultipartEntry
. The cParser
variable of inherited Map STL type receive the entire collection of POST
data. That is done in Initialize
method. The GetParam
is a helper method that returns the value of a needed parameter.
String CWriteFormExtension::GetParam(MultipartParser& cParser, String sName)
{
String sValue;
MultipartEntry* pEntry = cParser[sName.c_str()];
if(pEntry != NULL)
{
sValue = (LPCTSTR) pEntry->Data();
int nLen = sValue.size();
if(sValue[nLen - 1] == '\n' && sValue[nLen - 2] == '\r')
sValue = sValue.substr(0, nLen - 2);
}
return sValue;
}
This is the result of the Run
method:
The LoadLongResource private
function is a little modified compared with the MFC version. The input/output str string
parameter is of STL string
type. In the szPath char
variable, we must put the name of the DLL file in order to load the correct resource library.
BOOL CWriteLayoutExtension::LoadLongResource(String &str, UINT nID)
{
HRSRC hRes;
BOOL bResult = FALSE;
CHAR szPath[MAX_PATH];
strcpy(szPath, "WriteForm.dll");
HINSTANCE hInst = LoadLibrary(szPath);
hRes = FindResource(hInst, MAKEINTRESOURCE(nID), RT_HTML);
if (hRes == NULL)
{
str = "Error: Resource could not be found\r\n";
}
else
{
DWORD dwSize = SizeofResource(hInst, hRes);
if (dwSize == 0)
{
str.empty();
bResult = TRUE;
}
else
{
HGLOBAL hGlob = LoadResource(hInst, hRes);
if (hGlob != NULL)
{
LPVOID lpData = LockResource(hGlob);
if (lpData != NULL)
{
str = (LPCTSTR)lpData;
bResult = TRUE;
}
FreeResource(hGlob);
}
}
if (!bResult)
str = "Error: Resource could not be load\r\n";
}
return bResult;
}
History
- 16th July, 2002 - Updated MFC.zip download (was missing a class)
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.