home *** CD-ROM | disk | FTP | other *** search
/ Tutto per Internet / Internet.iso / soft95 / Varie / server / oleisapi.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  10.2 KB  |  328 lines

  1. /*
  2.  
  3.   OLEISAPI.CPP
  4.  
  5.   Copyright (c)1995 Microsoft Corporation, All Right Reserved
  6.  
  7.   Implements an ISAPI dll that will invoke OLE Automation objects
  8.   using IDispatch.  Any object that has a PROGID and implements one
  9.   or more methods with the following signature can be called by this dll:
  10.  
  11.     HRESULT SomeMethod(BSTR request, BSTR response)
  12.  
  13.   The first BSTR will contain either the HTTP query string (in the case
  14.   of a "GET" request) or the data contained in the HTTP request (in the
  15.   case of a "POST" request).  The second BSTR should be set by the object
  16.   to contain the HTTP response.  Note that the beginning of this string
  17.   should always be "Content-Type: " followed by a valid MIME type.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
  18.  
  19.   URLs that invoke this service from a link will look like this:
  20.  
  21.     http://machine/path/progid.method?foo=bar&baz=bleh
  22.  
  23.   This dll will also work with HTML forms that use the POST method,
  24.   in which case the parameters to the call will come from the form
  25.   elements rather than the URL.  Any parameters sent as part of the
  26.   action URL will not be passed on to the OLE object.
  27.  
  28.   Exports:
  29.  
  30.     BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
  31.     BOOL WINAPI HttpExtensionProc(   EXTENSION_CONTROL_BLOCK *pECB )
  32.     DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID pvReserved)
  33.  
  34. */
  35.  
  36. #include <windows.h>
  37. #include <httpext.h>
  38. #include <memory.h>
  39. #include <stdio.h>
  40.  
  41. #define PARAMLEN 1024
  42. #define BUFLEN 4096
  43.  
  44. // TLS is used to store OLE initialization flag
  45. static DWORD g_dwTLSIndex = (DWORD)-1;
  46.  
  47. // Many OA objects are not threadsafe, so we only allow one at a time
  48. static CRITICAL_SECTION g_csRuntime;
  49.  
  50. HRESULT HResultFromLastError()
  51. {
  52.     DWORD dwLastError = GetLastError();
  53.     return HRESULT_FROM_WIN32(dwLastError);
  54. }
  55.  
  56. //
  57. // Retrieve the class Id from the registry given its program id name.
  58. // The program ID name is converted from ASCII to wide char here since
  59. // URL strings are always ASCII.
  60. //
  61. HRESULT GetClsidFromProgIdA(LPCLSID pclsid, CHAR* pszName, long cbName)
  62. {
  63.     HRESULT hr;
  64.     // Allocate a wide char string for the Prog Id name.
  65.     OLECHAR *lpWideCharProgId = new WCHAR[cbName];
  66.     if (NULL == lpWideCharProgId) {
  67.        hr = ResultFromScode(E_OUTOFMEMORY);
  68.        goto LError;
  69.     }
  70.  
  71.     // Convert the ProgId name to wide chars.
  72.     if (0 == MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pszName, -1,
  73.                                  lpWideCharProgId, cbName) ) {
  74.       hr = (HResultFromLastError());
  75.       goto LError;
  76.     }
  77.  
  78.     // Now get the class Id from the Program Id.
  79.     hr = CLSIDFromProgID(lpWideCharProgId, pclsid);
  80.  
  81. LError:
  82.     if (NULL != lpWideCharProgId) {
  83.       delete [] lpWideCharProgId;
  84.     }
  85.     return(hr);
  86. }
  87.  
  88. //
  89. // Invoke obtains the prog ID and method to be invoked and blasts away.
  90. // If successful, it returns a string to be forced back up the pipe, else NULL
  91. //
  92. BOOL CallObject(EXTENSION_CONTROL_BLOCK *pECB,
  93.         CHAR *pszProgid, 
  94.         CHAR *pszMethod)
  95. {
  96.     BOOL fSuccess = FALSE;
  97.     BOOL fInCritSec = FALSE;
  98.     HRESULT hr;
  99.     CLSID clsid;
  100.     IDispatch *pdispObj = NULL;
  101.     IUnknown *punkObj = NULL;
  102.     OLECHAR wzMethod[PARAMLEN];
  103.     OLECHAR wzParams[PARAMLEN];
  104.     BSTR bstrParams = NULL;
  105.     BSTR bstrRetval = NULL;
  106.     CHAR *pszResults = NULL;
  107.     DWORD buflen = 0;
  108.  
  109.     OLECHAR *pwzName;
  110.     DISPID dispidMethod;
  111.     DISPPARAMS dispparms;
  112.     VARIANTARG varg[2];
  113.     EXCEPINFO excep;
  114.  
  115.     // initialize everything up front so cleanup is safe
  116.     memset(&dispparms, 0, sizeof(DISPPARAMS));
  117.     memset(&varg, 0, sizeof(VARIANTARG) * 2);
  118.     memset(&excep, 0, sizeof(EXCEPINFO));
  119.     memset(wzParams, 0, PARAMLEN);
  120.  
  121.     VariantInit(&varg[0]);
  122.     VariantInit(&varg[1]);
  123.  
  124.     // convert progid to clsid
  125.     hr = GetClsidFromProgIdA(&clsid, pszProgid, lstrlen(pszProgid)+1);
  126.     if (FAILED(hr)) goto Err;
  127.  
  128.     // Grab critical section
  129.     EnterCriticalSection(&g_csRuntime);
  130.     fInCritSec = TRUE;
  131.  
  132.     // instantiate object
  133.     CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (LPVOID *) &punkObj);
  134.     if (punkObj == NULL) goto Err;
  135.     hr = punkObj->QueryInterface(IID_IDispatch, (void**)&pdispObj);
  136.     if (FAILED(hr) || pdispObj == NULL) goto Err;
  137.     punkObj->Release();
  138.     punkObj = NULL;
  139.  
  140.     // Convert the method name and args to Wide character.
  141.     if (0 == MultiByteToWideChar(CP_ACP, 0, pszMethod, -1, wzMethod, PARAMLEN) ) {
  142.       goto Err;
  143.     }
  144.  
  145.     // If POST, grab data from control block
  146.     if (0 == strcmp(pECB->lpszMethod, "POST")) {
  147.       if (0 == MultiByteToWideChar(CP_ACP, 0, (const char*)pECB->lpbData, pECB->cbAvailable, wzParams, PARAMLEN) ) {
  148.     goto Err;
  149.       }
  150.     }
  151.     // otherwise, get it from the query string
  152.     else if (NULL != pECB->lpszQueryString) {
  153.       if (0 == MultiByteToWideChar(CP_ACP, 0, pECB->lpszQueryString, -1, wzParams, PARAMLEN) ) {
  154.     goto Err;
  155.       }
  156.     } else {
  157.       wzParams[0] = (WCHAR)0;
  158.     }
  159.     bstrParams = SysAllocString(wzParams);
  160.     if (NULL == bstrParams) goto Err;
  161.     bstrRetval = SysAllocString(L"");
  162.     if (NULL == bstrRetval) goto Err;
  163.  
  164.     // Find method name
  165.     pwzName = wzMethod;
  166.     hr = pdispObj->GetIDsOfNames(IID_NULL, &pwzName, 1, LOCALE_USER_DEFAULT, &dispidMethod);
  167.     if (FAILED(hr)) goto Err;
  168.  
  169.     // Setup parameters
  170.     dispparms.rgvarg = varg;
  171.     dispparms.rgdispidNamedArgs = NULL;
  172.     dispparms.cArgs = 2;
  173.     dispparms.cNamedArgs = 0;
  174.  
  175.     // Push in reverse order
  176.     varg[0].vt = VT_BSTR | VT_BYREF;
  177.     varg[0].pbstrVal = &bstrRetval;
  178.     varg[1].vt = VT_BSTR | VT_BYREF;
  179.     varg[1].pbstrVal = &bstrParams;
  180.  
  181.     // Now make the invocation.
  182.     hr = pdispObj->Invoke(dispidMethod, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
  183.                         &dispparms, NULL, &excep, NULL);
  184.     if (FAILED(hr)) goto Err;
  185.  
  186.     // Release critical section
  187.     fInCritSec = FALSE;
  188.     LeaveCriticalSection(&g_csRuntime);
  189.  
  190.     // Assemble result
  191.     buflen = wcslen(*(varg[0].pbstrVal));
  192.     if (buflen > 0) {
  193.       pszResults = (CHAR*)malloc(buflen + 1);
  194.       if (0 == WideCharToMultiByte(CP_ACP, 0, *(varg[0].pbstrVal), -1, pszResults, BUFLEN, NULL, NULL)) {
  195.     goto Err;
  196.       }
  197.       // null terminate string
  198.       *(pszResults + buflen) = 0;
  199.     }
  200.  
  201.     pECB->ServerSupportFunction(pECB->ConnID,
  202.                                 HSE_REQ_SEND_RESPONSE_HEADER,
  203.                 (LPDWORD) "200 means groovy",
  204.                 NULL,
  205.                  (LPDWORD)(pszResults));
  206.     fSuccess = TRUE;
  207.  
  208.     // Always fall through to cleanup
  209. Err:
  210.     if (fInCritSec) {
  211.       // Release critical section
  212.       LeaveCriticalSection(&g_csRuntime);
  213.     }
  214.     if (pdispObj != NULL) {
  215.       pdispObj->Release();
  216.     }
  217.     VariantClear(&varg[1]);
  218.     VariantClear(&varg[2]);
  219.     if (NULL != pszResults) {
  220.     free(pszResults);
  221.     }
  222.     return fSuccess;
  223. }
  224.  
  225. void ErrorResponse(EXTENSION_CONTROL_BLOCK *pECB,
  226.                  CHAR *pszProgid, 
  227.            CHAR *pszMethod)
  228. {
  229.     CHAR pszBuf[BUFLEN];
  230.  
  231.     _snprintf(pszBuf, BUFLEN, "Content-Type: text/html\r\n\r\n<body><h1>"
  232.       "OLEISAPI call failed</h1><p><b>Progid is:</b> %s\n<p><b>Method is:</b> %s\n<p>"
  233.       "<b>GET parameters are:</b> %s\n<p><b>POST parameters are:</b> %.*s</b></body>",
  234.       ((NULL != pszProgid) ? pszProgid : ""),
  235.       ((NULL != pszMethod) ? pszMethod : ""),
  236.       ((NULL != pECB->lpszQueryString) ? pECB->lpszQueryString : ""),
  237.       (pECB->cbAvailable > 0 ? pECB->cbAvailable : 1),
  238.       (pECB->cbAvailable > 0 ? (CHAR*)pECB->lpbData : ""));
  239.    
  240.     pECB->ServerSupportFunction(pECB->ConnID,
  241.                                 HSE_REQ_SEND_RESPONSE_HEADER,
  242.                 (LPDWORD) "200 Baaaad Request",
  243.                 NULL,
  244.                 (LPDWORD)pszBuf);
  245. }
  246.  
  247. BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
  248. {
  249.     pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
  250.  
  251.     strncpy(pVer->lpszExtensionDesc,
  252.             "OLE Automation Gateway",
  253.             HSE_MAX_EXT_DLL_NAME_LEN);
  254.     return TRUE;
  255. }
  256.  
  257. DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
  258. {
  259.     CHAR pszPathString[PARAMLEN];
  260.     CHAR *pszProgid = NULL;
  261.     CHAR *pszMethod = NULL;
  262.     CHAR *pszTemp = NULL;
  263.  
  264.     if (FALSE == TlsGetValue(g_dwTLSIndex)) {
  265.       OleInitialize(NULL);
  266.       TlsSetValue(g_dwTLSIndex, (void*)TRUE);
  267.     }
  268.  
  269.     // only GET and POST supported
  270.     if (strcmp(pECB->lpszMethod, "GET") && strcmp(pECB->lpszMethod, "POST"))
  271.     {
  272.       return HSE_STATUS_ERROR;
  273.     }
  274.  
  275.     // extract progid & method name from path info
  276.     strncpy(pszPathString, pECB->lpszPathInfo, PARAMLEN);
  277.     if ('/' == *pszPathString) {
  278.       pszProgid = pszPathString + 1;
  279.     }
  280.     pszMethod = strchr(pszPathString, '.');
  281.     if (NULL != pszMethod) {
  282.       // progids can have zero or one periods in them
  283.       pszTemp = strchr(pszMethod + 1, '.');
  284.       // separate progid from args
  285.       if (NULL != pszTemp) {
  286.     *pszTemp = '\0';
  287.     pszMethod = pszTemp + 1;
  288.       } else {
  289.     *pszMethod = '\0';
  290.     pszMethod++;
  291.       }
  292.     }
  293.  
  294.     // startup object, invoke method, and return results
  295.     if (FALSE == CallObject(pECB, pszProgid, pszMethod)) {
  296.       ErrorResponse(pECB, pszProgid, pszMethod);
  297.       return HSE_STATUS_ERROR;
  298.     }
  299.     return HSE_STATUS_SUCCESS;
  300. }
  301.  
  302. BOOL WINAPI DllMain(HMODULE hMod, DWORD fReason, LPVOID pvRes)
  303. {
  304.   switch (fReason) {
  305.   case DLL_PROCESS_ATTACH:
  306.     g_dwTLSIndex = TlsAlloc();
  307.     InitializeCriticalSection(&g_csRuntime);
  308.     if (-1 == g_dwTLSIndex)
  309.       return FALSE;
  310.     break;
  311.  
  312.   case DLL_THREAD_ATTACH:
  313.     // set this flag to true once ole has been initialized
  314.     TlsSetValue(g_dwTLSIndex, FALSE);
  315.     break;
  316.  
  317.   case DLL_PROCESS_DETACH:
  318.     // clean up global resources
  319.     if (-1 != g_dwTLSIndex)
  320.       TlsFree(g_dwTLSIndex);
  321.     DeleteCriticalSection(&g_csRuntime);
  322.     break;
  323.  
  324.   case DLL_THREAD_DETACH:
  325.     break;
  326.   }
  327.   return TRUE;
  328. }