2025-04-27 07:49:33 -04:00

503 lines
10 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name: InvokObjThreads.cpp
Abstract:
ISAPI Extension sample to invoke an automation server method
from worker threads
--*/
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <httpext.h>
#include "IsapiThread.h"
//
// Prototype for worker thread function
//
DWORD WINAPI WorkerThread(LPVOID pParam);
//
// Import type library information about the COM object
//
#import "GetUserName.dll"
//
// Global thread pool object
//
ISAPITHREAD *pThreadPool;
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
/*++
Function : DllMain
Description:
The initialization function for this DLL.
Arguments:
hinstDll - Instance handle of the DLL
dwReason - Reason why NT called this DLL
lpvContext - Reserved parameter for future use
Return Value:
Returns TRUE if successfull; otherwise FALSE.
--*/
{
#ifdef _DEBUG
CHAR szDebug[1024];
#endif
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//
// Allocate the thread pool object
//
pThreadPool = new ISAPITHREAD;
if (!pThreadPool)
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Failed to allocate thread pool object. "
"InvokObjThreads is terminating.\r\n"
);
OutputDebugString(szDebug);
#endif // _DEBUG
return FALSE;
}
//
// Initialize the worker threads
//
if (!pThreadPool->InitThreadPool(WorkerThread))
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Failed to initialize worker threads. "
"InvokObjThreads is terminating.\r\n"
);
OutputDebugString(szDebug);
#endif // _DEBUG
delete pThreadPool;
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
break;
default:
return TRUE;
}
return TRUE;
}
BOOL WINAPI
GetExtensionVersion(
HSE_VERSION_INFO *pVer
)
/*++
Purpose:
This is required ISAPI Extension DLL entry point.
Arguments:
pVer - poins to extension version info structure
Returns:
always returns TRUE
--*/
{
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
HSE_VERSION_MAJOR );
lstrcpyn( pVer->lpszExtensionDesc,
"InvokObjThreads ISAPI Sample", HSE_MAX_EXT_DLL_NAME_LEN );
return TRUE;
}
DWORD WINAPI
HttpExtensionProc(
EXTENSION_CONTROL_BLOCK *pecb
)
/*++
Purpose:
Demonstrate how to create an instance of the automation object
using VC++ 5.0 extensions and how to invoke its method.
Arguments:
pECB - pointer to the extenstion control block
Returns:
HSE_STATUS_SUCCESS on successful transmission completion
HSE_STATUS_ERROR on failure
--*/
{
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
CHAR szOutput[1024];
DWORD dwBuffSize;
//
// Add the request to the work item queue.
// If successful, we're done. If not, return an error to the client
//
if (pThreadPool->QueueWorkItem(pecb))
return HSE_STATUS_PENDING;
//
// Send headers back to client
//
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.pszHeader = "Content-type: text/html\r\n\r\n";
HeaderExInfo.cchHeader = strlen( HeaderExInfo.pszHeader );
HeaderExInfo.fKeepConn = FALSE;
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL
);
//
// Send back a message to the client indicating that the queue is full
//
wsprintf(szOutput,
"<h1>InvokObjThreads.dll</h1>"
"<hr>The resource is busy. Pleast try again later."
);
dwBuffSize = strlen(szOutput);
pecb->WriteClient(pecb->ConnID, szOutput, &dwBuffSize, 0);
return HSE_STATUS_SUCCESS;
}
BOOL WINAPI
TerminateExtension(
DWORD dwFlags
)
/*++
Purpose:
This is optional ISAPI extension DLL entry point.
If present, it will be called before unloading the DLL,
giving it a chance to perform any shutdown procedures.
Arguments:
dwFlags - specifies whether the DLL can refuse to unload or not
Returns:
TRUE, if the DLL can be unloaded
--*/
{
//
// Delete the thread pool object
//
delete pThreadPool;
//
// It is now OK to unload
//
return TRUE;
}
DWORD WINAPI WorkerThread(LPVOID pParam)
/*++
Purpose:
Implements the worker thread functionality
Arguments:
pParam - A pointer to the threadpool object to which the thread belongs
Returns:
0
--*/
{
char szOutput[1024];
DWORD dwBuffSize, dwThreadId, dwResult;
GETUSERNAMELib::IGetUserNameObjPtr pItf;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
HRESULT hr;
EXTENSION_CONTROL_BLOCK *pecb;
ISAPITHREAD *pThreadPool = (ISAPITHREAD *)pParam;
HANDLE hRequestToken;
#ifdef _DEBUG
CHAR szDebug[1024];
#endif
//
// Get the ThreadId for this thread
//
dwThreadId = GetCurrentThreadId();
#ifdef _DEBUG
wsprintf(
szDebug,
"Initializing worker thread %d.\r\n",
dwThreadId
);
OutputDebugString(szDebug);
#endif // _DEBUG
//
// Initialize COM for this thread
//
hr = CoInitialize(NULL);
if ( FAILED( hr ) )
{
#ifdef _DEBUG
wsprintf(
szDebug,
"CoIntialize failed for thread %d: 0x%08x (%d)\r\n",
dwThreadId,
hr,
hr
);
OutputDebugString(szDebug);
#endif // _DEBUG
return FALSE;
}
//
// Initialize and instance of the automation server for this thread
//
hr = pItf.CreateInstance( L"GetUserNameObj.GetUserNameObj.1" );
if ( FAILED( hr ) )
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Failed to get interface pointer for thread %d: 0x%08x (%d)\r\n",
dwThreadId,
hr,
hr
);
OutputDebugString(szDebug);
#endif // _DEBUG
goto ExitWorkerThread;
}
//
// Completed thread initialization. Now wait for work
//
while (1)
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Thread %d waiting for work.\r\n",
dwThreadId
);
OutputDebugString(szDebug);
#endif // _DEBUG
dwResult = WaitForSingleObject(
pThreadPool->m_hWorkerThreadSemaphore,
INFINITE
);
//
// Check to see that the wait succeeded
//
if (dwResult != WAIT_OBJECT_0)
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Thread %d exiting due to wait failure.\r\n",
dwThreadId
);
OutputDebugString(szDebug);
#endif // _DEBUG
goto ExitWorkerThread;
}
//
// Get the next work item in the queue. If the work item is NULL,
// the thread should exit gracefully.
//
pecb = pThreadPool->GetWorkItem();
if (!pecb)
{
#ifdef _DEBUG
wsprintf(
szDebug,
"Thread %d exiting gracefully.\r\n",
dwThreadId
);
OutputDebugString(szDebug);
#endif // _DEBUG
goto ExitWorkerThread;
}
///////
// Process the work item
///////
#ifdef _DEBUG
wsprintf(
szDebug,
"Thread %d processing work item.\r\n",
dwThreadId
);
OutputDebugString(szDebug);
#endif // _DEBUG
//
// Get the request token from IIS and set the token for this thead
//
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_GET_IMPERSONATION_TOKEN,
&hRequestToken,
NULL,
NULL
);
SetThreadToken(NULL, hRequestToken);
//
// Send headers back to client
//
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.pszHeader = "Content-type: text/html\r\n\r\n";
HeaderExInfo.cchHeader = strlen( HeaderExInfo.pszHeader );
HeaderExInfo.fKeepConn = FALSE;
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL
);
//
// Build the output using the result of the call to
// GetUserNameObj's GetMyName method
//
wsprintf(
szOutput,
"<h1>Request handled by thread %d.</h1>"
"<hr>The GetMyName method returned %s.",
dwThreadId,
(char *)pItf->GetMyName( )
);
//
// Send the output back to the client
//
dwBuffSize = strlen( szOutput );
pecb->WriteClient( pecb->ConnID, szOutput, &dwBuffSize, 0 );
//
// Notify IIS that we are done processing the request
//
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_DONE_WITH_SESSION,
NULL,
NULL,
NULL
);
}
ExitWorkerThread:
//
// Uninitialize COM for this thread and return
//
CoUninitialize();
return 0;
}