Microsoft KB Archive/169109

From BetaArchive Wiki
< Microsoft KB Archive
Revision as of 19:46, 20 July 2020 by X010 (talk | contribs) (Text replacement - ">" to ">")
Knowledge Base


Article ID: 169109

Article Last Modified on 10/13/2003



APPLIES TO

  • Microsoft Foundation Class Library 4.2, when used with:
    • Microsoft Visual C++ 4.1 Subscription
    • Microsoft Visual C++ 4.2 Professional Edition
    • Microsoft Visual C++ 5.0 Standard Edition
    • Microsoft Visual C++ .NET 2003 Standard Edition
    • Microsoft Visual C++ .NET 2002 Standard Edition



This article was previously published under Q169109

SYMPTOMS

MFC ISAPI extension cannot handle a multiple-select list box on a form. You may receive the following error message n Internet Explorer 3.0 when you select multiple items:

BAD REQUEST

Your client sent a request that this server did not understand.

CAUSE

MFC ISAPI parse maps are not designed to handle multiple-select list boxes.

RESOLUTION

One way to handle multiple selections is to override CallFunction and do the all the parsing in CallFunction without calling the base class. This involves writing the code for parsing the input from the browser.

Another method involves modifying the input to a format that can be handled by the parse maps. The sample code in the MORE INFORMATION section of this article overrides CallFunction and modifies the input in a way that the parse maps can handle.

MORE INFORMATION

If you select multiple items in the list box, the following is sent when you use the HTML in the Sample Code section:

   MFCIsapiCommand=WorksOn&Name=ssm&Days=Monday&Days=Tuesday
                

The code in CallFunction below modifies the input as follows:

   MFCIsapiCommand=WorksOn&Name=ssm&Days=Monday,Tuesday
                

In the parse map function, the variable associated with the list box contains a string with all the selected items in the list box, delimited by ','. If a comma is not a good delimiter then change the line:

   #define DELIMITER  ','
                

and specify a different character. Note that &, ?, =, + have special meanings and should not be used as delimiters.

Sample Code

HTML Form that calls the sample dll:

   <HTML>

   <form action="/scripts/MyIsapi.dll?" method="Post">
   <input type=hidden Name=MFCIsapiCommand Value=WorksOn>
   Name <input name="Name" >
   <p>
   Works on
   <SELECT MULTIPLE NAME="Days">
   <OPTION VALUE="">NONE
   <OPTION>Sunday
   <OPTION>Monday
   <OPTION>Tuesday
   <OPTION>Wednesday
   <OPTION>Thursday
   <OPTION>Friday
   <OPTION>Saturday
   </SELECT>
   <p>
   <input type=submit>
   </form>

   </HTML>
                

MFC ISAPI PARSE_MAP entries and function for the above:

   ON_PARSE_COMMAND(WorksOn, CMyIsapiExtension, ITS_PSTR ITS_PSTR)
   ON_PARSE_COMMAND_PARAMS("Name=~ Days=~")

   void CFirstISAPIExtension::WorksOn (CHttpServerContext* pCtxt,
       LPCTSTR Name, LPTSTR Days)
   {
       StartContent(pCtxt);
       *pCtxt << Name << " works on the following Days : <p>" << Days;
       EndContent(pCtxt);

   }
                

The code above generates the error message when more than one day is selected in the list box.

The following override of CallFunction modifies the input so that the parse maps can handle multiple selections:

   #define DELIMITER ","

   int CMyIsapiExtension::CallFunction(CHttpServerContext* pCtxt,
       LPTSTR pszQuery, LPTSTR pszCommand)
   {
       LPTSTR queryIn = pszQuery;
       LPTSTR queryOut = new TCHAR[_tcslen(queryIn) + sizeof(TCHAR)];
       LPTSTR pOut = queryOut;
       *pOut = NULL;

       LPTSTR pIn = queryIn;
       // Copy everything till the first ?
       if (_tcschr(pIn, '?'))
       {
           pIn = _tcschr(pIn, '?');
           pIn++;
           memcpy(pOut, queryIn, (pIn - queryIn)); //copy till the ?
           pOut += (pIn - queryIn);
           *pOut = NULL;
       }

       LPTSTR lastParameter = NULL;
       int nLastParameterLen = 0;

       while (pIn && *pIn)
       {
           // Is there a '=' in the input string
           LPTSTR q = _tcschr(pIn, '=');
           if (!q)
           {
               // No. Copy till end of the buffer and break out
               // No more parameter/value pairs.
               _tcscpy(pOut, pIn);
               break;
           }

           int paramLen = (q - pIn);

           // Is the last parameter name the same as the present
           // parameter name?
           if (paramLen &&
               nLastParameterLen == paramLen &&
               _tcsncmp(lastParameter, pIn, nLastParameterLen) == 0)
           {
               // Yes! replace & with , and just copy the value
               // of the parameter.
               q++;
               if (*q)
               {
                   LPTSTR r = _tcschr(q, '&');
                   *(pOut - 1) = ',';
                   //copy the value
                   if (r)
                   {
                       _tcsncpy(pOut, q, (r - q) + 1);
                       pOut+=(r - q) + 1;
                       pIn = r + 1;
                   }
                   else
                   {
                       _tcscpy(pOut, q);
                       break;
                   }
               }
               else
               {
                   *(pOut - 1) = ',';
                   *pOut = NULL;
                   break;
               }
           }
           else
           {
               nLastParameterLen = paramLen;
               lastParameter = pIn;

               q = _tcschr(pIn, '&');
               if (q)
               {
                   if (paramLen)
                   {
                       _tcsncpy(pOut, pIn, (q - pIn) + 1);
                       pOut += (q - pIn) + 1;
                   }
                   pIn = q + 1;
               }
               else
               {
                   if (paramLen)
                   {
                       _tcscpy(pOut, pIn);
                       break;
                   }
                   else
                   {
                       if (pOut == queryOut)
                           *pOut = NULL;
                       else
                           *(pOut - 1) = NULL;
                       break;
                   }
               }
           }
       }

       pszQuery = queryOut;

       int nRet = CHttpServer::CallFunction(pCtxt,
           pszQuery, pszCommand);

       delete []queryOut;

       return nRet;
   }
                

The following modification to the WorksOn function prints the days on different lines:

   void CMyIsapiExtension::WorksOn (CHttpServerContext* pCtxt,
       LPCTSTR Name, LPTSTR Days)
   {
       StartContent(pCtxt);
       *pCtxt << Name << " works on the following Days<p>";
       LPTSTR p = (LPTSTR)Days;
       while (p)
       {
           LPCTSTR q = p;
           p = _tcschr(p, ',');
           if (p)
               *p++ = NULL;

           *pCtxt << q << "<p>";
       }

       EndContent(pCtxt);

   }
                


Additional query words: multiple select listbox list box mfcisapi form

Keywords: kbprogramming kbprb kbcode KB169109