Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.82.2.2
1.29 paf 1: /** @file
2: Parser: IIS extension.
3:
1.82.2.1 paf 4: Copyright (c) 2000,2001-2003 ArtLebedev Group (http://www.artlebedev.com)
1.63 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.77 paf 6: */
1.29 paf 7:
1.82.2.2! paf 8: static const char* IDENT_PARSER3ISAPI_C="$Date: 2003/01/31 12:34:41 $";
1.29 paf 9:
1.1 paf 10: #ifndef _MSC_VER
1.10 paf 11: # error compile ISAPI module with MSVC [no urge for now to make it autoconf-ed (PAF)]
1.1 paf 12: #endif
1.43 parser 13:
14: #include "pa_config_includes.h"
1.1 paf 15:
1.9 paf 16: #include "pa_sapi.h"
1.1 paf 17: #include "pa_globals.h"
18: #include "pa_request.h"
19: #include "pa_version.h"
1.13 paf 20: #include "pool_storage.h"
1.24 paf 21: #include "pa_socks.h"
1.1 paf 22:
1.64 paf 23: #include <windows.h>
24: #include <process.h>
25: #include <new.h>
26:
27: #include <httpext.h>
1.51 parser 28:
1.1 paf 29: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION")
1.44 parser 30:
31: // consts
1.1 paf 32:
1.82.2.1 paf 33: const char* IIS51vars[]={
1.73 paf 34: "APPL_MD_PATH", "APPL_PHYSICAL_PATH",
35: "AUTH_PASSWORD", "AUTH_TYPE", "AUTH_USER",
36: "CERT_COOKIE", "CERT_FLAGS", "CERT_ISSUER", "CERT_KEYSIZE", "CERT_SECRETKEYSIZE",
37: "CERT_SERIALNUMBER", "CERT_SERVER_ISSUER", "CERT_SERVER_SUBJECT", "CERT_SUBJECT",
38: "CONTENT_LENGTH", "CONTENT_TYPE",
39: "LOGON_USER",
40: "HTTPS", "HTTPS_KEYSIZE", "HTTPS_SECRETKEYSIZE", "HTTPS_SERVER_ISSUER", "HTTPS_SERVER_SUBJECT",
41: "INSTANCE_ID", "INSTANCE_META_PATH",
42: "PATH_INFO", "PATH_TRANSLATED",
43: "QUERY_STRING",
44: "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_USER", "REQUEST_METHOD",
45: "SCRIPT_NAME",
46: "SERVER_NAME", "SERVER_PORT", "SERVER_PORT_SECURE", "SERVER_PROTOCOL", "SERVER_SOFTWARE",
47: "URL",
48: };
49: const int IIS51var_count=sizeof(IIS51vars)/sizeof(*IIS51vars);
50:
1.65 paf 51: // globals
52:
53: char argv0[MAX_STRING]="";
54:
1.18 paf 55: // SAPI
56:
1.38 parser 57: #ifndef DOXYGEN
58: /*
1.18 paf 59: ISAPI SAPI functions receive this context information.
1.38 parser 60: see Pool::set_context
1.18 paf 61: */
1.15 paf 62: struct SAPI_func_context {
1.3 paf 63: LPEXTENSION_CONTROL_BLOCK lpECB;
64: String *header;
65: DWORD http_response_code;
66: };
1.38 parser 67: #endif
1.3 paf 68:
1.26 paf 69: // goes to 'cs-uri-query' log file field. webmaster: switch it ON[default OFF].
1.82.2.1 paf 70: void SAPI::log(Pool& pool, const char* fmt, ...) {
1.53 parser 71: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.26 paf 72:
73: va_list args;
74: va_start(args,fmt);
75: char buf[MAX_STRING];
1.82.2.1 paf 76: const char* prefix="PARSER_ERROR:";
1.26 paf 77: strcpy(buf, prefix);
1.47 parser 78: char *start=buf+strlen(prefix);
1.51 parser 79: DWORD size=vsnprintf(start, MAX_STRING-strlen(prefix), fmt, args);
1.47 parser 80: remove_crlf(start, start+size);
81:
1.26 paf 82: ctx.lpECB->ServerSupportFunction(ctx.lpECB->ConnID,
83: HSE_APPEND_LOG_PARAMETER, buf, &size, 0);
1.55 parser 84: }
85:
86: /// @todo event log
1.82.2.1 paf 87: void SAPI::die(const char* fmt, ...) {
1.65 paf 88: if(FILE *log=fopen("c:\\die.log", "at")) {
89: va_list args;
90: va_start(args,fmt);
91: vfprintf(log, fmt, args);
92: fclose(log);
93: }
1.81 paf 94: // exit & try to produce core dump
95: abort();
1.26 paf 96: }
97:
1.82.2.1 paf 98: const char* SAPI::get_env(Pool& pool, const char* name) {
1.53 parser 99: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.1 paf 100:
101: char *variable_buf=(char *)pool.malloc(MAX_STRING);
102: DWORD variable_len = MAX_STRING-1;
103:
1.3 paf 104: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
1.1 paf 105: variable_buf, &variable_len)) {
1.73 paf 106: if(*variable_buf) { // saw returning len=1 && *buf=0 :(
107: variable_buf[variable_len]=0;
108: return variable_buf;
109: }
1.7 paf 110: } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
111: variable_buf=(char *)pool.malloc(variable_len+1);
112:
113: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
114: variable_buf, &variable_len)) {
1.73 paf 115: if(*variable_buf) {
116: variable_buf[variable_len]=0;
117: return variable_buf;
118: }
1.7 paf 119: }
1.1 paf 120: }
1.7 paf 121:
1.1 paf 122: return 0;
123: }
124:
1.82.2.1 paf 125: static int grep_char(const char* s, char c) {
1.72 paf 126: int result=0;
127: if(s) {
128: while(s=strchr(s, c)) {
129: s++; // skip found c
130: result++;
131: }
132: }
133: return result;
134: }
1.82.2.1 paf 135: static const char* mk_env_pair(Pool& pool, const char* key, const char* value) {
1.72 paf 136: char *result=(char *)pool.malloc(strlen(key)+1/*=*/+strlen(value)+1/*0*/);
137: strcpy(result, key); strcat(result, "="); strcat(result, value);
138: return result;
139: }
1.82.2.1 paf 140: const char* const *SAPI::environment(Pool& pool) {
1.72 paf 141: // we know this buf is writable
142: char *all_http_vars=const_cast<char *>(SAPI::get_env(pool, "ALL_HTTP"));
143: const int http_var_count=grep_char(all_http_vars, '\n')+1/*\n for theoretical(never saw) this \0*/;
144:
1.82.2.1 paf 145: const char* *result=
146: (const char* *)pool.malloc(sizeof(char *)*(IIS51var_count+http_var_count+1/*0*/));
147: const char* *cur=result;
1.72 paf 148:
149: // IIS5.1 vars
150: for(int i=0; i<IIS51var_count; i++) {
1.82.2.1 paf 151: const char* key=IIS51vars[i];
152: if(const char* value=SAPI::get_env(pool, key))
1.72 paf 153: *cur++=mk_env_pair(pool, key, value);
154: }
155:
156: // HTTP_* vars
157: if(char *s=all_http_vars) {
158: while(char *key=lsplit(&s, '\n'))
159: if(char *value=lsplit(key, ':'))
160: *cur++=mk_env_pair(pool, key, value);
161: }
162:
163: // mark EOE
164: *cur=0;
165:
166: return result;
167: }
168:
1.26 paf 169: size_t SAPI::read_post(Pool& pool, char *buf, size_t max_bytes) {
1.53 parser 170: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.1 paf 171:
172: DWORD read_from_buf=0;
173: DWORD read_from_input=0;
174: DWORD total_read=0;
175:
1.3 paf 176: read_from_buf=min(ctx.lpECB->cbAvailable, max_bytes);
177: memcpy(buf, ctx.lpECB->lpbData, read_from_buf);
1.1 paf 178: total_read+=read_from_buf;
179:
180: if(read_from_buf<max_bytes &&
1.3 paf 181: read_from_buf<ctx.lpECB->cbTotalBytes) {
1.1 paf 182: DWORD cbRead=0, cbSize;
183:
1.3 paf 184: read_from_input=min(max_bytes-read_from_buf,
185: ctx.lpECB->cbTotalBytes-read_from_buf);
1.1 paf 186: while(cbRead < read_from_input) {
187: cbSize=read_from_input - cbRead;
1.3 paf 188: if(!ctx.lpECB->ReadClient(ctx.lpECB->ConnID,
189: buf+read_from_buf+cbRead, &cbSize) ||
1.1 paf 190: cbSize==0)
191: break;
192: cbRead+=cbSize;
193: }
194: total_read+=cbRead;
195: }
196: return total_read;
197: }
198:
1.82.2.2! paf 199: void SAPI::add_header_attribute(Pool& pool,
! 200: const char* dont_store_key, const char* dont_store_value) {
1.53 parser 201: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.3 paf 202:
203: if(strcasecmp(key, "location")==0)
204: ctx.http_response_code=302;
205:
206: if(strcasecmp(key, "status")==0)
1.82.2.2! paf 207: ctx.http_response_code=atoi(dont_store_value);
1.3 paf 208: else {
1.82.2.2! paf 209: todo: copy dont_store_ to nonvilotile
! 210: ctx.header->APPEND_CONST(dont_store_key);
1.3 paf 211: ctx.header->APPEND_CONST(": ");
1.82.2.2! paf 212: ctx.header->APPEND_CONST(dont_store_value);
1.30 paf 213: ctx.header->APPEND_CONST("\r\n");
1.3 paf 214: }
1.1 paf 215: }
216:
1.23 paf 217: /// @todo intelligent cache-control
1.9 paf 218: void SAPI::send_header(Pool& pool) {
1.53 parser 219: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.1 paf 220:
1.64 paf 221: HSE_SEND_HEADER_EX_INFO header_info;
1.1 paf 222:
223: char status_buf[MAX_STATUS_LENGTH];
1.3 paf 224: switch(ctx.http_response_code) {
1.1 paf 225: case 200:
226: header_info.pszStatus="200 OK";
227: break;
228: case 302:
229: header_info.pszStatus="302 Moved Temporarily";
230: break;
1.8 paf 231: case 401:// useless untill parser auth mech
1.1 paf 232: header_info.pszStatus="401 Authorization Required";
1.8 paf 233: break;
1.1 paf 234: default:
1.3 paf 235: snprintf(status_buf, MAX_STATUS_LENGTH,
236: "%d Undescribed", ctx.http_response_code);
1.1 paf 237: header_info.pszStatus=status_buf;
238: break;
239: }
240: header_info.cchStatus=strlen(header_info.pszStatus);
1.66 paf 241: *ctx.header << "\r\n"; // ISAPI v<5 did quite well without it
1.3 paf 242: header_info.pszHeader=ctx.header->cstr();
243: header_info.cchHeader=ctx.header->size();
1.5 paf 244: header_info.fKeepConn=true;
1.1 paf 245:
1.3 paf 246: ctx.lpECB->dwHttpStatusCode=ctx.http_response_code;
1.1 paf 247:
1.3 paf 248: ctx.lpECB->ServerSupportFunction(ctx.lpECB->ConnID,
249: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
1.1 paf 250: }
251:
1.23 paf 252: void SAPI::send_body(Pool& pool, const void *buf, size_t size) {
1.53 parser 253: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.get_context());
1.1 paf 254:
255: DWORD num_bytes=size;
1.3 paf 256: ctx.lpECB->WriteClient(ctx.lpECB->ConnID,
1.23 paf 257: const_cast<void *>(buf), &num_bytes, HSE_IO_SYNC);
1.1 paf 258: }
1.16 paf 259:
1.1 paf 260: //
261:
1.59 paf 262: int failed_new(size_t size) {
263: SAPI::die("out of memory in 'new', failed to allocated %u bytes", size);
264: return 0; // not reached
265: }
266:
1.71 paf 267: #ifdef _DEBUG
268: static Pool_storage *global_pool_storagep;
269: #endif
1.15 paf 270: static bool parser_init() {
1.1 paf 271: static bool globals_inited=false;
272: if(globals_inited)
1.15 paf 273: return true;
1.1 paf 274: globals_inited=true;
275:
1.59 paf 276: _set_new_handler(failed_new);
277:
1.65 paf 278: static Pool_storage pool_storage;
1.71 paf 279: #ifdef _DEBUG
280: global_pool_storagep=&pool_storage;
281: #endif
1.65 paf 282: static Pool pool(&pool_storage); // global pool
1.53 parser 283: try {
1.27 paf 284: // init socks
285: init_socks(pool);
1.32 paf 286: // init global classes
287: init_methoded_array(pool);
1.1 paf 288: // init global variables
1.9 paf 289: pa_globals_init(pool);
1.65 paf 290:
1.15 paf 291: // successful finish
292: return true;
1.53 parser 293: } catch(const Exception& e) { // global problem
1.82.2.1 paf 294: const char* body=e.comment();
1.15 paf 295:
296: // unsuccessful finish
297: return false;
1.1 paf 298: }
299: }
300:
301: /// ISAPI //
302: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) {
303: pVer->dwExtensionVersion = HSE_VERSION;
1.36 parser 304: strncpy(pVer->lpszExtensionDesc, "Parser "PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN-1);
305: pVer->lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN-1]=0;
1.15 paf 306: return parser_init();
1.1 paf 307: }
308:
1.6 paf 309: /**
310: ISAPI // main workhorse
311:
1.23 paf 312: @todo
1.10 paf 313: IIS: remove trailing default-document[index.html] from $request.uri.
314: to do that we need to consult metabase,
1.12 paf 315: wich is tested&works but seems slow runtime
316: and not could-be-quickly-implemented if prepared.
1.37 parser 317: @test
318: PARSER_VERSION from outside
1.6 paf 319: */
1.53 parser 320:
321: void real_parser_handler(Pool& pool, LPEXTENSION_CONTROL_BLOCK lpECB, bool header_only) {
322: static_cast<SAPI_func_context *>(pool.get_context())->header=new(pool) String(pool);
323:
324: // Request info
325: Request::Info request_info;
326:
327: size_t path_translated_buf_size=strlen(lpECB->lpszPathTranslated)+1;
328: char *filespec_to_process=(char *)pool.malloc(path_translated_buf_size);
329: memcpy(filespec_to_process, lpECB->lpszPathTranslated, path_translated_buf_size);
330: #ifdef WIN32
331: back_slashes_to_slashes(filespec_to_process);
332: #endif
333:
1.82.2.1 paf 334: if(const char* path_info=SAPI::get_env(pool, "PATH_INFO")) {
1.53 parser 335: // IIS
336: size_t len=strlen(filespec_to_process)-strlen(path_info);
337: char *buf=(char *)pool.malloc(len+1);
338: strncpy(buf, filespec_to_process, len); buf[len]=0;
339: request_info.document_root=buf;
340: } else
1.67 paf 341: throw Exception("parser.runtime",
1.53 parser 342: 0,
343: "ISAPI: no PATH_INFO defined (in reinventing DOCUMENT_ROOT)");
344:
345: request_info.path_translated=filespec_to_process;
346: request_info.method=lpECB->lpszMethod;
347: request_info.query_string=lpECB->lpszQueryString;
348: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
349: char *reconstructed_uri=(char *)pool.malloc(
350: strlen(lpECB->lpszPathInfo)+1/*'?'*/+
351: strlen(lpECB->lpszQueryString)+1/*0*/);
352: strcpy(reconstructed_uri, lpECB->lpszPathInfo);
353: strcat(reconstructed_uri, "?");
354: strcat(reconstructed_uri, lpECB->lpszQueryString);
355: request_info.uri=reconstructed_uri;
356: } else
357: request_info.uri=lpECB->lpszPathInfo;
358:
359: request_info.content_type=lpECB->lpszContentType;
360: request_info.content_length=lpECB->cbTotalBytes;
361: request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");
1.76 paf 362: request_info.mail_received=false;
1.53 parser 363:
364: // prepare to process request
365: Request request(pool,
366: request_info,
1.60 paf 367: String::UL_HTML|String::UL_OPTIMIZE_BIT,
1.70 paf 368: #ifdef _DEBUG
369: true
370: #else
371: false
372: #endif
373: /* status_allowed */);
1.53 parser 374:
1.65 paf 375: // beside by binary
1.75 paf 376: static char beside_binary_path[MAX_STRING];
377: strncpy(beside_binary_path, argv0, MAX_STRING-1); beside_binary_path[MAX_STRING-1]=0; // filespec of my binary
1.65 paf 378: if(!(
1.75 paf 379: rsplit(beside_binary_path, '/') ||
380: rsplit(beside_binary_path, '\\'))) { // strip filename
1.65 paf 381: // no path, just filename
1.75 paf 382: beside_binary_path[0]='.'; beside_binary_path[1]=0;
1.65 paf 383: }
1.74 paf 384: char config_filespec[MAX_STRING];
385: snprintf(config_filespec, MAX_STRING,
1.65 paf 386: "%s/%s",
1.75 paf 387: beside_binary_path, AUTO_FILE_NAME);
1.79 paf 388: bool fail_on_config_read_problem=entry_exists(config_filespec);
1.65 paf 389:
1.53 parser 390: // process the request
391: request.core(
1.79 paf 392: config_filespec, fail_on_config_read_problem, // /path/to/first/auto.p
1.53 parser 393: header_only);
394: }
395:
396: void call_real_parser_handler__do_SEH(Pool& pool,
397: LPEXTENSION_CONTROL_BLOCK lpECB,
398: bool header_only) {
1.54 parser 399: #if _MSC_VER & !defined(_DEBUG)
1.53 parser 400: LPEXCEPTION_POINTERS system_exception=0;
401: __try {
402: #endif
403: real_parser_handler(pool, lpECB, header_only);
404:
1.54 parser 405: #if _MSC_VER & !defined(_DEBUG)
1.53 parser 406: } __except (
407: (system_exception=GetExceptionInformation()),
408: EXCEPTION_EXECUTE_HANDLER) {
409:
410: if(system_exception)
411: if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
1.67 paf 412: throw Exception(0,
1.53 parser 413: 0,
414: "Exception 0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress);
415: else
1.67 paf 416: throw Exception(0, 0, "Exception <no exception record>");
1.53 parser 417: else
1.67 paf 418: throw Exception(0, 0, "Exception <no exception information>");
1.53 parser 419: }
420: #endif
421: }
422:
1.71 paf 423: inline DWORD RealHttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
1.13 paf 424: Pool_storage pool_storage;
1.15 paf 425: Pool pool(&pool_storage); // no allocations until assigned context [for reporting]
426: SAPI_func_context ctx={
427: lpECB,
1.18 paf 428: 0, // filling later: so that if there would be error pool would have ctx
1.80 paf 429: 200 // default http_response_code [lpECB->dwHttpStatusCode seems to be always 0, even on 404 redirect to /404.html]
1.15 paf 430: };
431: pool.set_context(&ctx);// no allocations before this line!
1.71 paf 432:
1.1 paf 433: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
1.53 parser 434: try { // global try
435: call_real_parser_handler__do_SEH(pool, lpECB, header_only);
1.2 paf 436: // successful finish
1.53 parser 437: } catch(const Exception& e) { // global problem
1.12 paf 438: // don't allocate anything on pool here:
439: // possible pool' exception not catch-ed now
1.31 paf 440: // and there could be out-of-memory exception
1.82.2.1 paf 441: const char* body=e.comment();
1.16 paf 442: // log it
443: SAPI::log(pool, "exception in request exception handler: %s", body);
444:
445: //
1.1 paf 446: int content_length=strlen(body);
447:
1.12 paf 448: // prepare header // not using SAPI func wich allocates on pool
449: char header_buf[MAX_STRING];
450: int header_len=snprintf(header_buf, MAX_STRING,
1.30 paf 451: "content-type: text/plain\r\n"
452: "content-length: %lu\r\n"
1.69 paf 453: // "expires: Fri, 23 Mar 2001 09:32:23 GMT\r\n"
1.30 paf 454: "\r\n",
1.12 paf 455: content_length);
456:
457: HSE_SEND_HEADER_EX_INFO header_info;
458: header_info.pszStatus="200 OK";
459: header_info.cchStatus=strlen(header_info.pszStatus);
460: header_info.pszHeader=header_buf;
461: header_info.cchHeader=header_len;
462: header_info.fKeepConn=true;
463:
1.1 paf 464: // send header
1.12 paf 465: lpECB->dwHttpStatusCode=200;
466: lpECB->ServerSupportFunction(lpECB->ConnID,
467: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
1.1 paf 468:
469: // send body
470: if(!header_only)
1.9 paf 471: SAPI::send_body(pool, body, content_length);
1.1 paf 472:
473: // unsuccessful finish
474: }
1.65 paf 475: /*
1.82.2.1 paf 476: const char* body="test";
1.65 paf 477:
478: //
479: int content_length=strlen(body);
480:
481: // prepare header // not using SAPI func wich allocates on pool
482: char header_buf[MAX_STRING];
483: int header_len=snprintf(header_buf, MAX_STRING,
484: "content-type: text/plain\r\n"
485: "content-length: %lu\r\n"
486: "expires: Fri, 23 Mar 2001 09:32:23 GMT\r\n"
487: "\r\n",
488: content_length);
489: HSE_SEND_HEADER_EX_INFO header_info;
490: header_info.pszStatus="200 OK";
491: header_info.cchStatus=strlen(header_info.pszStatus);
492: header_info.pszHeader=header_buf;
493: header_info.cchHeader=header_len;
494: header_info.fKeepConn=true;
495:
496: // send header
497: lpECB->dwHttpStatusCode=200;
498: lpECB->ServerSupportFunction(lpECB->ConnID,
499: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
500:
501: // send body
502: DWORD num_bytes=content_length;
503: lpECB->WriteClient(lpECB->ConnID,
504: (void *)body, &num_bytes, HSE_IO_SYNC);
505: */
1.71 paf 506: return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
507: }
1.66 paf 508:
1.71 paf 509: #ifdef _DEBUG
510: //for memory leaks detection only
511: #undef _WINDOWS_
512: #include <afx.h>
513: #endif
514: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
515: // Declare the variables needed
516: #ifdef _DEBUG
517: // _crtBreakAlloc=97779;//97777; //997;
518:
519: CMemoryState oldMemState, newMemState, diffMemState;
520: oldMemState.Checkpoint();
521: //global_pool_storagep->fbreak_on_alloc=true;
522: #endif
523:
524: DWORD result=RealHttpExtensionProc(lpECB);
525:
526: #ifdef _DEBUG
527: newMemState.Checkpoint();
528: if( diffMemState.Difference( oldMemState, newMemState ) )
529: {
530: TRACE( "Memory leaked!\n" );
531: diffMemState.DumpStatistics( );
532: diffMemState.DumpAllObjectsSince();
533: }
534: #endif
535: return result;
1.1 paf 536: }
1.65 paf 537:
538: BOOL WINAPI DllMain(
539: HINSTANCE hinstDLL, // handle to the DLL module
540: DWORD fdwReason, // reason for calling function
541: LPVOID lpvReserved // reserved
542: ) {
543:
544: GetModuleFileName(
545: hinstDLL, // handle to module
546: argv0, // file name of module
547: sizeof(argv0) // size of buffer
548: );
549:
550: return TRUE;
551: }
E-mail: