diff loader/win32.c @ 1:3b5f5d1c5041

Initial revision
author arpi_esp
date Sat, 24 Feb 2001 20:28:24 +0000
parents
children 94a1a9f52050
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loader/win32.c	Sat Feb 24 20:28:24 2001 +0000
@@ -0,0 +1,1706 @@
+/***********************************************************
+
+	Win32 emulation code. Functions that emulate
+	responses from corresponding Win32 API calls.
+         Since we are not going to be able to load 
+       virtually any DLL, we can only implement this
+      much, adding needed functions with each new codec.
+
+************************************************************/
+
+#include <config.h>
+
+#include "win32.h"
+#include <stdio.h>
+#include <pthread.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+#include <wine/winbase.h>
+#include <wine/winreg.h>
+#include <wine/winnt.h>
+#include <wine/winerror.h>
+#include <wine/debugtools.h>
+#include <wine/module.h>
+
+#include <registry.h>
+#include <loader.h>
+#ifdef USE_TSC
+static unsigned int localcount()
+{
+    int a;
+    __asm__ __volatile__("rdtsc\n\t"
+    :"=a"(a)
+    :
+    :"edx");
+    return a;
+}
+static void longcount(long long* z)
+{
+    __asm__ __volatile__(
+    "pushl %%ebx\n\t"
+    "movl %%eax, %%ebx\n\t"
+    "rdtsc\n\t"
+    "movl %%eax, 0(%%ebx)\n\t"
+    "movl %%edx, 4(%%ebx)\n\t"
+    "popl %%ebx\n\t"
+    ::"a"(z));
+}    
+#else
+#include <sys/time.h>
+#include <unistd.h>
+static unsigned int localcount()
+{
+    struct timeval tv;
+    unsigned limit=~0;
+    limit/=1000000;
+    gettimeofday(&tv, 0);
+    return limit*tv.tv_usec;
+}
+static void longcount(long long* z)
+{
+    struct timeval tv;
+    unsigned long long result;
+    unsigned limit=~0;
+    if(!z)return;
+    limit/=1000000;
+    gettimeofday(&tv, 0);
+    result=tv.tv_sec;
+    result<<=32;
+    result+=limit*tv.tv_usec;
+    *z=result;
+}
+#endif
+
+void dbgprintf(char* fmt, ...)
+{
+#ifdef DETAILED_OUT
+#if 1
+    va_list va;
+    va_start(va, fmt);
+    vprintf(fmt, va);
+    va_end(va);
+#else
+    va_list va;
+    FILE* f;
+    va_start(va, fmt);
+    f=fopen("./log", "a");
+    if(f==0)return;
+    vfprintf(f, fmt, va);
+    fsync(f);
+    fclose(f);
+#endif
+#endif
+}    
+char export_names[500][30]={
+"name1",
+//"name2",
+//"name3"
+};
+//#define min(x,y) ((x)<(y)?(x):(y))
+
+static unsigned char* heap=NULL; 
+static int heap_counter=0;
+void test_heap()
+{
+    int offset=0;	
+    if(heap==0)
+	return;
+    while(offset<heap_counter)
+    {
+	if(*(int*)(heap+offset)!=0x433476)
+	{
+	    printf("Heap corruption at address %d\n", offset);
+	    return;
+	}
+	offset+=8+*(int*)(heap+offset+4);
+    }
+    for(;offset<min(offset+1000, 20000000); offset++)
+	if(heap[offset]!=0xCC)
+	    {
+		printf("Free heap corruption at address %d\n", offset);
+	}	    
+}
+#undef MEMORY_DEBUG
+
+#ifdef MEMORY_DEBUG
+
+void* my_mreq(int size, int to_zero)
+{
+    static int test=0;
+    test++;
+    if(test%10==0)printf("Memory: %d bytes allocated\n", heap_counter);
+//    test_heap();
+    if(heap==NULL)
+    {
+	heap=malloc(20000000);
+	memset(heap, 0xCC,20000000);
+    }
+    if(heap==0)
+    {
+	printf("No enough memory\n");
+	return 0;
+    }	
+    if(heap_counter+size>20000000)
+    {
+	printf("No enough memory\n");
+	return 0;
+    }	
+    *(int*)(heap+heap_counter)=0x433476;
+    heap_counter+=4;
+    *(int*)(heap+heap_counter)=size;
+    heap_counter+=4;
+    printf("Allocated %d bytes of memory: sys %d, user %d-%d\n", size, heap_counter-8, heap_counter, heap_counter+size);
+    if(to_zero)
+    	memset(heap+heap_counter, 0, size);	    
+    heap_counter+=size;
+    return heap+heap_counter-size;	
+}
+int my_release(char* memory)
+{
+//    test_heap();
+    if(memory==NULL)
+    {
+	printf("ERROR: free(0)\n");
+	return 0;
+    }	
+    if(*(int*)(memory-8)!=0x433476)
+    {
+	printf("MEMORY CORRUPTION !!!!!!!!!!!!!!!!!!!\n");
+	return 0;
+    }
+    printf("Freed %d bytes of memory\n", *(int*)(memory-4));
+//    memset(memory-8, *(int*)(memory-4), 0xCC);
+    return 0;
+}    	     
+
+#else
+void* my_mreq(int size, int to_zero)
+{
+    void* answer; 
+    if(to_zero)
+	answer=calloc(size+4, 1);
+    else
+	answer=malloc(size+4);
+    *(int*)answer=size;
+    return (int*)answer+1;
+}	
+int my_release(char* memory)
+{
+    if(memory==0)return 0;
+    free(memory-4);
+    return 0;
+}
+#endif
+int my_size(char* memory)
+{
+    return *(int*)(memory-4);
+}    
+
+extern int unk_exp1;
+char extcode[20000];// place for 200 unresolved exports
+int pos=0;
+
+int WINAPI ext_unknown()
+{
+    printf("Unknown func called\n");
+    return 0;
+}    
+int WINAPI expIsBadWritePtr(void* ptr, unsigned int count)
+{
+    dbgprintf("IsBadWritePtr(%x, %x)\n", ptr, count);
+    if(count==0)
+	return 0;
+    if(ptr==0)
+        return 1;
+    return 0;
+}
+int WINAPI expIsBadReadPtr(void* ptr, unsigned int count)
+{
+    dbgprintf("IsBadReadPtr(%x, %x)\n", ptr, count);
+    if(count==0)
+	return 0;
+    if(ptr==0)
+        return 1;
+    return 0;
+}
+void* CDECL expmalloc(int size)
+{
+//printf("malloc");
+//    return malloc(size);
+    void* result=my_mreq(size,0);
+    dbgprintf("malloc(%x)\n", size);
+    if(result==0)
+    {
+	dbgprintf("returns 0\n");
+	printf("WARNING: malloc() failed\n");
+    }	
+    return result;
+}
+void CDECL expfree(void* mem)
+{
+//    return free(mem);
+    dbgprintf("free(%x)\n", mem);
+    my_release(mem);
+}
+void* CDECL expnew(int size)
+{
+//    printf("NEW:: Call from address %08x\n STACK DUMP:\n", *(-1+(int*)&size));
+//    printf("%08x %08x %08x %08x\n",
+//    size, *(1+(int*)&size),
+//    *(2+(int*)&size),*(3+(int*)&size));
+    void* result=expmalloc(size);
+    dbgprintf("new(%x)\n", size);
+    if(result==0)
+    {
+	dbgprintf("returns 0\n");
+	printf("WARNING: malloc() failed\n");
+    }	
+    return result;
+
+}    
+int CDECL expdelete(void* memory)
+{
+    dbgprintf("delete(%x)\n", memory);
+    expfree(memory);
+    return 0;
+}
+int WINAPI expDisableThreadLibraryCalls(int module)
+{
+    dbgprintf("DisableThreadLibraryCalls(%x)\n", module);
+    return 0;
+}    
+int CDECL exp_initterm(int v1, int v2)
+{
+    return 0;
+}    
+
+typedef struct {
+    unsigned int     	uDriverSignature;
+    void*        	hDriverModule;
+    void*    		DriverProc;
+    unsigned int        dwDriverID;
+} DRVR;
+
+void* WINAPI expGetDriverModuleHandle(DRVR* pdrv)
+{
+    dbgprintf("GetDriverModuleHandle(%x)\n", pdrv);
+    return pdrv->hDriverModule;
+}
+
+void* WINAPI expGetModuleHandleA(const char* name)
+{
+	WINE_MODREF* wm;
+        dbgprintf("GetModuleHandleA(%s)\n", name);
+	if(!name)return 0;
+        wm=MODULE_FindModule(name);
+        if(wm==0)return 0;
+        return (void*)(wm->module);
+}
+struct th_list_t;
+typedef struct th_list_t{
+int id;
+void* thread;
+struct th_list_t* next;
+struct th_list_t* prev;
+}th_list;
+
+static th_list* list=NULL;
+
+
+
+void* WINAPI expCreateThread(void* pSecAttr, long dwStackSize, void* lpStartAddress,
+	void* lpParameter, long dwFlags, long* dwThreadId)
+{
+    pthread_t *pth;
+//    printf("CreateThread:");
+    pth=my_mreq(sizeof(pthread_t), 0);
+    dbgprintf("pthread_create\n");
+    pthread_create(pth, NULL, (void*(*)(void*))lpStartAddress, lpParameter);
+    if(dwFlags)
+	dbgprintf( "WARNING: CreateThread flags not supported\n");
+    if(dwThreadId)
+	*dwThreadId=(long)pth;
+    dbgprintf( "Created thread %08X\n", pth);
+    if(list==NULL)
+    {
+	list=my_mreq(sizeof(th_list), 1);
+	list->next=list->prev=NULL;
+    }
+    else
+    {
+	list->next=my_mreq(sizeof(th_list), 0);
+	list->next->prev=list;
+	list->next->next=NULL;
+	list=list->next;
+    }		
+    list->thread=pth;
+    return pth;
+}
+
+struct mutex_list_t;
+
+struct mutex_list_t
+{
+    pthread_mutex_t *pm;
+    char name[64];
+    struct mutex_list_t* next;
+    struct mutex_list_t* prev;
+};
+typedef struct mutex_list_t mutex_list;
+static mutex_list* mlist=NULL; 
+void* WINAPI expCreateEventA(void* pSecAttr, char bManualReset, 
+    char bInitialState, const char* name)
+{
+#warning ManualReset
+    pthread_mutex_t *pm;
+    dbgprintf("CreateEvent\n");
+    if(mlist!=NULL)
+    {
+	mutex_list* pp=mlist;
+	if(name!=NULL)
+	do
+	{
+	    if(strcmp(pp->name, name)==0)
+		return pp->pm;
+	}while(pp=pp->prev);
+    }	
+    pm=my_mreq(sizeof(pthread_mutex_t), 0);
+    pthread_mutex_init(pm, NULL);
+    if(mlist==NULL)
+    {
+	mlist=my_mreq(sizeof(mutex_list), 00);
+	mlist->next=mlist->prev=NULL;
+    }
+    else
+    {
+	mlist->next=my_mreq(sizeof(mutex_list), 00);
+	mlist->next->prev=mlist->next;
+	mlist->next->next=NULL;
+	mlist=mlist->next;
+    }
+    mlist->pm=pm;
+    if(name!=NULL)
+        strncpy(mlist->name, name, 64);
+	else
+	mlist->name[0]=0;
+    if(pm==NULL)
+	dbgprintf("ERROR::: CreateEventA failure\n");
+    if(bInitialState)
+        pthread_mutex_lock(pm);
+    return pm;
+}    
+
+void* WINAPI expSetEvent(void* event)
+{
+    dbgprintf("Trying to lock %X\n", event);
+    pthread_mutex_lock(event);
+}
+void* WINAPI expResetEvent(void* event)
+{
+    dbgprintf("Unlocking %X\n", event);
+    pthread_mutex_unlock(event);    
+}
+
+void* WINAPI expWaitForSingleObject(void* object, int duration)
+{
+#warning not sure
+    dbgprintf("WaitForSingleObject: duration %d\n", duration);
+    pthread_mutex_lock(object);
+    pthread_mutex_unlock(object);
+}    
+
+static BYTE PF[64] = {0,};
+
+void WINAPI expGetSystemInfo(SYSTEM_INFO* si)
+{
+    	/* FIXME: better values for the two entries below... */
+	static int cache = 0;
+	static SYSTEM_INFO cachedsi;
+	HKEY	xhkey=0,hkey;
+        dbgprintf("GetSystemInfo()\n");
+
+	if (cache) {
+		memcpy(si,&cachedsi,sizeof(*si));
+		return;
+	}
+	memset(PF,0,sizeof(PF));
+
+	cachedsi.u.s.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
+	cachedsi.dwPageSize 			= getpagesize();
+
+	/* FIXME: better values for the two entries below... */
+	cachedsi.lpMinimumApplicationAddress	= (void *)0x40000000;
+	cachedsi.lpMaximumApplicationAddress	= (void *)0x7FFFFFFF;
+	cachedsi.dwActiveProcessorMask		= 1;
+	cachedsi.dwNumberOfProcessors		= 1;
+	cachedsi.dwProcessorType		= PROCESSOR_INTEL_386;
+	cachedsi.dwAllocationGranularity	= 0x10000;
+	cachedsi.wProcessorLevel		= 3; /* pentium */
+	cachedsi.wProcessorRevision		= 0;
+	
+#ifdef __FreeBSD__
+        cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+        cachedsi.wProcessorLevel= 5;
+	PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
+#ifdef MMX
+        PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
+#endif
+        cachedsi.dwNumberOfProcessors=1;
+#else
+	{
+	char buf[20];
+	char line[200];
+	FILE *f = fopen ("/proc/cpuinfo", "r");
+
+	if (!f)
+		return;
+        xhkey = 0;
+	while (fgets(line,200,f)!=NULL) {
+		char	*s,*value;
+
+		/* NOTE: the ':' is the only character we can rely on */
+		if (!(value = strchr(line,':')))
+			continue;
+		/* terminate the valuename */
+		*value++ = '\0';
+		/* skip any leading spaces */
+		while (*value==' ') value++;
+		if ((s=strchr(value,'\n')))
+			*s='\0';
+
+		/* 2.1 method */
+		if (!lstrncmpiA(line, "cpu family",strlen("cpu family"))) {
+			if (isdigit (value[0])) {
+				switch (value[0] - '0') {
+				case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
+					cachedsi.wProcessorLevel= 3;
+					break;
+				case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
+					cachedsi.wProcessorLevel= 4;
+					break;
+				case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				}
+			}
+			/* set the CPU type of the current processor */
+			sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
+			continue;
+		}
+		/* old 2.0 method */
+		if (!lstrncmpiA(line, "cpu",strlen("cpu"))) {
+			if (	isdigit (value[0]) && value[1] == '8' && 
+				value[2] == '6' && value[3] == 0
+			) {
+				switch (value[0] - '0') {
+				case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
+					cachedsi.wProcessorLevel= 3;
+					break;
+				case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
+					cachedsi.wProcessorLevel= 4;
+					break;
+				case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+					cachedsi.wProcessorLevel= 5;
+					break;
+				}
+			}
+			/* set the CPU type of the current processor */
+			sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
+			continue;
+		}
+		if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) {
+			if (!lstrncmpiA(value,"yes",3))
+				PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
+
+			continue;
+		}
+		if (!lstrncmpiA(line,"fpu",strlen("fpu"))) {
+			if (!lstrncmpiA(value,"no",2))
+				PF[PF_FLOATING_POINT_EMULATED] = TRUE;
+
+			continue;
+		}
+		if (!lstrncmpiA(line,"processor",strlen("processor"))) {
+			/* processor number counts up...*/
+			int	x;
+
+			if (sscanf(value,"%d",&x))
+				if (x+1>cachedsi.dwNumberOfProcessors)
+					cachedsi.dwNumberOfProcessors=x+1;
+
+			/* Create a new processor subkey on a multiprocessor
+			 * system
+			 */
+			sprintf(buf,"%d",x);
+		}
+		if (!lstrncmpiA(line,"stepping",strlen("stepping"))) {
+			int	x;
+
+			if (sscanf(value,"%d",&x))
+				cachedsi.wProcessorRevision = x;
+		}
+		if ( (!lstrncmpiA(line,"flags",strlen("flags"))) ||
+                     (!lstrncmpiA(line,"features",strlen("features"))) ) {
+			if (strstr(value,"cx8"))
+				PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
+			if (strstr(value,"mmx"))
+				PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
+
+		}
+	}
+	fclose (f);
+	}
+#endif /* __FreeBSD__ */
+	memcpy(si,&cachedsi,sizeof(*si));
+}
+
+long WINAPI expGetVersion()
+{
+    return 0xC0000A04;//Windows 98
+}    
+
+HANDLE WINAPI expHeapCreate(long flags, long init_size, long max_size)
+{
+//    printf("HeapCreate:");
+    dbgprintf("HeapCreate(%X, %X, %X)\n", flags, init_size, max_size); 
+    if(init_size==0)
+    	return (HANDLE)my_mreq(0x110000, 0);
+    else
+	return (HANDLE)my_mreq(init_size, 0);
+}		
+void* WINAPI expHeapAlloc(HANDLE heap, int flags, int size)
+{
+    void* z;
+    dbgprintf("HeapAlloc(%X, %X, %X)\n", heap, flags, size); 
+//    printf("HeapAlloc:");
+    z=my_mreq(size, flags&8);    
+//    z=HeapAlloc(heap,flags,size);
+    if(z==0)
+	printf("HeapAlloc failure\n");
+    return z;
+}
+long WINAPI expHeapDestroy(void* heap)
+{
+    dbgprintf("HeapDestroy(%X)\n", heap); 
+    my_release(heap);
+    return 1;
+}
+
+long WINAPI expHeapFree(int arg1, int arg2, void* ptr)
+{
+    dbgprintf("HeapFree(%X, %X, %X)\n", arg1, arg2, ptr);
+    my_release(ptr);
+    return 1;
+}    	
+long WINAPI expHeapSize(int heap, int flags, void* pointer)
+{
+    return my_size(pointer);
+} 
+long WINAPI expGetProcessHeap(void)
+{
+    return 1;
+}    
+void* WINAPI expVirtualAlloc(void* v1, long v2, long v3, long v4)
+{
+    void* z;
+    dbgprintf("VirtualAlloc(%d %d %d %d) \n",v1,v2,v3,v4);
+    z=VirtualAlloc(v1, v2, v3, v4);
+    if(z==0)
+	printf("VirtualAlloc failure\n");
+    return z;
+}
+int WINAPI expVirtualFree(void* v1, int v2, int v3)
+{
+    dbgprintf("VirtualFree(%X %X %X) \n",v1,v2,v3);
+    return VirtualFree(v1,v2,v3);
+}    
+struct CRITSECT 
+{
+    pthread_t id;
+    pthread_mutex_t mutex;
+    int locked;
+};
+void WINAPI expInitializeCriticalSection(CRITICAL_SECTION* c)
+{
+    struct CRITSECT cs;
+    dbgprintf("InitCriticalSection(%X) \n", c);
+/*    if(sizeof(pthread_mutex_t)>sizeof(CRITICAL_SECTION))
+    {
+	printf(" ERROR:::: sizeof(pthread_mutex_t) is %d, expected <=%d!\n",
+	     sizeof(pthread_mutex_t), sizeof(CRITICAL_SECTION));
+	return;
+    }*/
+/*    pthread_mutex_init((pthread_mutex_t*)c, NULL);   */
+    pthread_mutex_init(&cs.mutex, NULL);   
+    cs.locked=0;
+    *(void**)c=malloc(sizeof cs);
+    memcpy(*(void**)c, &cs, sizeof cs);
+    return;
+}          
+void WINAPI expEnterCriticalSection(CRITICAL_SECTION* c)
+{
+    struct CRITSECT* cs=(struct CRITSECT*)c;
+    dbgprintf("EnterCriticalSection(%X) \n",c);
+//    cs.id=pthread_self();
+    if(cs->locked)
+	if(cs->id==pthread_self())
+	    return;
+    pthread_mutex_lock(&(cs->mutex));
+    cs->locked=1;
+    cs->id=pthread_self();
+    return;
+}          
+void WINAPI expLeaveCriticalSection(CRITICAL_SECTION* c)
+{
+    struct CRITSECT* cs=(struct CRITSECT*)c;
+    dbgprintf("LeaveCriticalSection(%X) \n",c);
+    cs->locked=0;
+    pthread_mutex_unlock(&(cs->mutex));
+    return;
+}
+void WINAPI expDeleteCriticalSection(CRITICAL_SECTION *c)
+{
+    dbgprintf("DeleteCriticalSection(%X) \n",c);
+    pthread_mutex_destroy((pthread_mutex_t*)c);
+    return;
+}
+int WINAPI expGetCurrentThreadId()
+{
+    dbgprintf("GetCurrentThreadId() \n");
+    return getpid();
+}                  
+struct tls_s;
+typedef struct tls_s
+{
+    void* value;
+    int used;
+    struct tls_s* prev;
+    struct tls_s* next;
+}tls_t;
+
+tls_t* g_tls=NULL;    
+    
+void* WINAPI expTlsAlloc()
+{
+    dbgprintf("TlsAlloc \n");
+    if(g_tls==NULL)
+    {
+	g_tls=my_mreq(sizeof(tls_t), 0);
+	g_tls->next=g_tls->prev=NULL;
+    }
+    else
+    {
+	g_tls->next=my_mreq(sizeof(tls_t), 0);
+	g_tls->next->prev=g_tls;
+	g_tls->next->next=NULL;
+	g_tls=g_tls->next;
+    }
+    return g_tls;
+}
+
+int WINAPI expTlsSetValue(tls_t* index, void* value)
+{
+    dbgprintf("TlsSetVal(%X %X) \n", index, value );
+    if(index==0)
+	return 0;
+    index->value=value;
+    return 1;
+}
+void* WINAPI expTlsGetValue(tls_t* index)
+{
+    dbgprintf("TlsGetVal(%X) \n", index );
+    if(index==0)
+	return 0;
+    return index->value;	
+}
+int WINAPI expTlsFree(tls_t* index)
+{
+    dbgprintf("TlsFree(%X) \n", index);
+    if(index==0)
+	return 0;
+    if(index->next)
+	index->next->prev=index->prev;
+    if(index->prev)
+        index->prev->next=index->next;
+    my_release((void*)index);
+    return 1;
+}     
+
+void* WINAPI expLocalAlloc(int flags, int size)
+{
+    void* z;
+    dbgprintf("LocalAlloc(%d, flags %X)\n", size, flags);
+    if(flags&GMEM_ZEROINIT)
+	z=my_mreq(size, 1);
+    else
+	z=my_mreq(size, 0);
+    if(z==0)
+	printf("LocalAlloc() failed\n");
+    return z;
+}	
+void* WINAPI expLocalLock(void* z)
+{
+   dbgprintf("LocalLock\n");
+    return z;
+}    
+void* WINAPI expGlobalAlloc(int flags, int size)
+{
+    void* z;
+     dbgprintf("GlobalAlloc(%d, flags 0x%X)\n", size, flags);
+    if(flags&GMEM_ZEROINIT)
+	z=my_mreq(size, 1);
+	else
+	z=my_mreq(size, 0);
+    if(z==0)
+	printf("LocalAlloc() failed\n");
+    return z;
+}	
+void* WINAPI expGlobalLock(void* z)
+{
+     dbgprintf("GlobalLock\n");
+    return z;
+}    
+
+int WINAPI expLoadStringA(long instance, long  id, void* buf, long size)
+{
+    dbgprintf("LoadStringA\n");
+    return LoadStringA(instance, id, buf, size);
+}    	    	
+
+long WINAPI expMultiByteToWideChar(long v1, long v2, char* s1, long siz1, char* s2, int siz2)
+{
+#warning FIXME
+    dbgprintf("MB2WCh\n");
+    dbgprintf("WARNING: Unsupported call: MBToWCh %s\n", s1);       
+    if(s2==0)
+	return 1;
+    s2[0]=s2[1]=0;
+    return 1;
+}
+long WINAPI expWideCharToMultiByte(long v1, long v2, short* s1, long siz1, char* s2, int siz2, char* c3, int* siz3)
+{
+    int result;
+    dbgprintf("WCh2MB\n");
+    result=WideCharToMultiByte(v1, v2, s1, siz1, s2, siz2, c3, siz3);
+    dbgprintf("=> %d\n", result);
+    return result;
+}
+long WINAPI expGetVersionExA(OSVERSIONINFOA* c)
+{
+    dbgprintf("GetVersionExA\n");
+    c->dwMajorVersion=4;
+    c->dwMinorVersion=10;
+    c->dwBuildNumber=0x40a07ce;
+    c->dwPlatformId=VER_PLATFORM_WIN32_WINDOWS;
+    strcpy(c->szCSDVersion, "Win98");
+    return 1;
+}        
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+HANDLE WINAPI expCreateSemaphoreA(char* v1, long init_count, long max_count, char* name)
+{
+#warning FIXME
+/*    struct sembuf buf[1];
+    int sem=semget(IPC_PRIVATE,1,IPC_CREAT);
+    if(sem==-1)
+    {
+	printf("semget() failed\n");
+	return (HANDLE)-1;
+    }	
+    buf[0].sem_num=0;
+    printf("%s\n", name);
+    printf("Init count %d, max count %d\n", init_count, max_count);
+    buf[0].sem_op=-max_count+init_count;
+    buf[0].sem_flg=0;
+    if(semop(sem, &buf, 1)<0)
+    {
+	printf("semop() failed\n");
+    }
+    return sem;	
+*/    
+    void* z;
+    dbgprintf("CreateSemaphoreA\n");
+    z=my_mreq(24, 0);
+    pthread_mutex_init(z, NULL);
+    return (HANDLE)z;
+}
+        
+long WINAPI expReleaseSemaphore(long hsem, long increment, long* prev_count)
+{
+// The state of a semaphore object is signaled when its count 
+// is greater than zero and nonsignaled when its count is equal to zero
+// Each time a waiting thread is released because of the semaphore's signaled
+// state, the count of the semaphore is decreased by one. 
+    struct sembuf buf[1];
+    dbgprintf("ReleaseSemaphore\n");
+    dbgprintf("WARNING: Unsupported call: ReleaseSemaphoreA\n");       
+/*    if(hsem==-1)return 0;
+    buf[0].sem_num=0;
+    buf[0].sem_op=-1;
+    buf[0].sem_flg=0;
+    if(semop(hsem, &buf, 1)<0)
+    {
+	printf("ReleaseSemaphore: semop() failed\n");
+    }*/
+
+    return 1;//zero on error
+}
+
+
+long WINAPI expRegOpenKeyExA(long key, const char* subkey, long reserved, long access, int* newkey)
+{
+    dbgprintf("RegOpenKeyExA(%d,%s)\n", key, subkey);
+    return RegOpenKeyExA(key, subkey, reserved, access, newkey);
+}    
+long WINAPI expRegCloseKey(long key)
+{
+    dbgprintf("RegCloseKey()\n");
+    return RegCloseKey(key);
+}         
+long WINAPI expRegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count)
+{
+    dbgprintf("RegQueryValueExA()\n");
+    return RegQueryValueExA(key, value, reserved, type, data, count);
+}  
+long WINAPI expRegCreateKeyExA(long key, const char* name, long reserved,
+							   void* classs, long options, long security,
+							   void* sec_attr, int* newkey, int* status) 
+{
+    dbgprintf("RegCreateKeyExA()\n");
+    return RegCreateKeyExA(key, name, reserved, classs, options, security, sec_attr, newkey, status);
+}
+long WINAPI expRegSetValueExA(long key, const char* name, long v1, long v2, void* data, long size)
+{
+    dbgprintf("RegSetValueExA()\n");
+    return RegSetValueExA(key, name, v1, v2, data, size);
+}        
+
+long WINAPI expRegOpenKeyA (
+long hKey,
+ LPCSTR lpSubKey,
+ int* phkResult
+){
+    return  RegOpenKeyExA(hKey, lpSubKey, 0, 0, phkResult);
+}
+
+long WINAPI expQueryPerformanceCounter(long long* z)
+{
+    dbgprintf("QueryPerformanceCounter()\n");
+    longcount(z);
+    return 1; 
+}
+
+static double old_freq()
+{
+    int i=time(NULL);
+    int x,y;
+    while(i==time(NULL));
+    x=localcount();
+    i++;
+    while(i==time(NULL));
+    y=localcount();
+    return (double)(y-x)/1000.;
+}
+static double CPU_Freq()
+{
+#ifdef USE_TSC
+	FILE *f = fopen ("/proc/cpuinfo", "r");
+	char line[200];
+	char model[200]="unknown";
+	char flags[500]="";
+	char	*s,*value;
+	double freq=-1;
+	
+	if (!f)
+	{
+	    printf("Can't open /proc/cpuinfo for reading\n");
+	    return old_freq();
+	}    
+	while (fgets(line,200,f)!=NULL) 
+	{
+		/* NOTE: the ':' is the only character we can rely on */
+		if (!(value = strchr(line,':')))
+			continue;
+		/* terminate the valuename */
+		*value++ = '\0';
+		/* skip any leading spaces */
+		while (*value==' ') value++;
+		if ((s=strchr(value,'\n')))
+			*s='\0';
+
+		if (!strncasecmp(line, "cpu MHz",strlen("cpu MHz"))) 
+		{
+		    sscanf(value, "%lf", &freq);
+		    freq*=1000;
+		    break;
+		}
+		continue;
+		
+	}
+	fclose(f);
+	if(freq<0)return old_freq();
+	return freq;
+#else
+	return old_freq();
+#endif    	
+}
+
+long WINAPI expQueryPerformanceFrequency(long long* z)
+{
+    dbgprintf("QueryPerformanceFrequency()\n");
+    *z=(long long)CPU_Freq();
+    return 1; 
+}
+long WINAPI exptimeGetTime()
+{
+    struct timeval t;
+    dbgprintf("timeGetTime()\n");
+    gettimeofday(&t, 0);
+    return 1000*t.tv_sec+t.tv_usec/1000;
+}
+void* WINAPI expLocalHandle(void* v)
+{
+    dbgprintf("LocalHandle\n");
+    return v;
+}        
+void* WINAPI expGlobalHandle(void* v)
+{
+    dbgprintf("GlobalHandle\n");
+    return v;
+}        
+int WINAPI expGlobalUnlock(void* v)
+{
+    dbgprintf("GlobalUnlock\n");
+    return 1;
+}
+//
+void* WINAPI expGlobalFree(void* v)
+{
+    dbgprintf("GlobalFree(%X)\n", v);
+    my_release(v);
+    return 0;
+}        
+
+int WINAPI expLocalUnlock(void* v)
+{
+    dbgprintf("LocalUnlock\n");
+    return 1;
+}
+//
+void* WINAPI expLocalFree(void* v)
+{
+    dbgprintf("LocalFree(%X)\n", v);
+    my_release(v);
+    return 0;
+}        
+
+HRSRC WINAPI expFindResourceA(HMODULE module, char* name, char* type)
+{
+    dbgprintf("FindResourceA\n");
+    return FindResourceA(module, name, type);
+}
+HGLOBAL WINAPI expLoadResource(HMODULE module, HRSRC res)
+{
+    dbgprintf("LoadResource\n");
+    return LoadResource(module, res);;    
+}
+void* WINAPI expLockResource(long res)
+{
+    dbgprintf("LockResource\n");
+    return LockResource(res);
+}    
+int WINAPI expFreeResource(long res)
+{
+    dbgprintf("FreeResource\n");
+    return FreeResource(res);
+}    
+//bool fun(HANDLE)
+//!0 on success
+int WINAPI expCloseHandle(long v1)
+{
+    dbgprintf("CloseHandle\n");
+    return 1;
+}    
+
+const char* WINAPI expGetCommandLineA()
+{
+    dbgprintf("GetCommandLine\n");
+    return "c:\\aviplay.exe";
+}
+LPWSTR WINAPI expGetEnvironmentStringsW()
+{
+    static wchar_t envs[]={'p', 'a', 't', 'h', ' ', 'c', ':', '\\', 0, 0};
+    dbgprintf("GetEnvStringsW\n");
+    return (LPWSTR)envs;
+}
+
+int WINAPI expFreeEnvironmentStringsW(short* strings)
+{
+    dbgprintf("FreeEnvStringsW\n");
+    return 1;
+}
+LPCSTR WINAPI expGetEnvironmentStrings()
+{
+    dbgprintf("GetEnvStrings\n");
+    return "\0\0";
+}
+
+int WINAPI expGetStartupInfoA(STARTUPINFOA *s)
+{
+    int i;    
+    dbgprintf("GetStartupInfoA\n");
+/*    
+    for(i=0; i<sizeof(STARTUPINFOA)/4; i++)
+     ((int*)s)[i]=i+0x200;
+*/
+    memset(s, 0, sizeof(*s));
+    s->cb=sizeof(*s);
+    s->lpReserved="qwe";
+    s->lpDesktop="rty";
+    s->lpTitle="uio";
+    s->dwX=s->dwY=0;
+    s->dwXSize=s->dwYSize=200;
+    s->dwFlags=s->wShowWindow=0;
+    return 1;
+}    
+
+int WINAPI expGetStdHandle(int z)
+{
+    dbgprintf("GetStdHandle\n");
+    dbgprintf("WARNING: Unsupported call: GetStdHandle\n");       
+    return 1234;
+}
+int WINAPI expGetFileType(int handle)
+{
+    dbgprintf("GetFileType\n");
+    dbgprintf("WARNING: Unsupported call: GetFileType\n");       
+    return 5678;
+}
+int WINAPI expSetHandleCount(int count)
+{
+    dbgprintf("SetHandleCount\n");
+    return 1;        
+}
+int WINAPI expGetACP()
+{
+    dbgprintf("GetACP\n");
+    dbgprintf("WARNING: Unsupported call: GetACP\n");       
+    return 0; 
+}
+extern WINE_MODREF *MODULE32_LookupHMODULE(HMODULE m);
+int WINAPI expGetModuleFileNameA(int module, char* s, int len)
+{
+    WINE_MODREF *mr;
+    dbgprintf("GetModuleFileNameA\n");
+//    printf("File name of module %X requested\n", module);
+    if(s==0)
+    return 0;
+    if(len<35)
+    return 0;
+    strcpy(s, "c:\\windows\\system\\");
+    mr=MODULE32_LookupHMODULE(module);
+    if(mr==0)//oops
+    {
+        strcat(s, "aviplay.dll");
+	return 1;
+    }	
+    if(strrchr(mr->filename, '/')==NULL)
+	strcat(s, mr->filename);
+    else
+	strcat(s, strrchr(mr->filename, '/')+1);
+    return 1;
+}    
+    
+int WINAPI expSetUnhandledExceptionFilter(void* filter)
+{
+    dbgprintf("SetUnhandledExcFilter\n");
+    return 1;//unsupported and probably won't ever be supported
+}    
+extern char* def_path;
+
+int WINAPI expLoadLibraryA(char* name)
+{
+    char qq[256];
+    dbgprintf("LoadLibraryA\n");
+    printf("They want library %s\n", name);
+    strcpy(qq, def_path);
+    strcat(qq, "/");
+    strcat(qq, name);
+    return LoadLibraryA(qq);
+}      
+int WINAPI expFreeLibrary(int module)
+{
+    dbgprintf("FreeLibrary\n");
+    return FreeLibrary(module);
+}   
+void* WINAPI expGetProcAddress(HMODULE mod, char* name)
+{
+    dbgprintf("GetProcAddress\n");
+    return GetProcAddress(mod, name);
+}    
+
+long WINAPI expCreateFileMappingA(int hFile, void* lpAttr,
+    long flProtect, long dwMaxHigh, long dwMaxLow, const char* name)
+{
+    dbgprintf("CreateFileMappingA\n");
+    return CreateFileMappingA(hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, name);
+}    
+
+long WINAPI expOpenFileMappingA(long hFile, long hz, const char* name)
+{
+    dbgprintf("OpenFileMappingA\n");
+    return OpenFileMappingA(hFile, hz, name);
+}
+
+void* WINAPI expMapViewOfFile(HANDLE file, DWORD mode, DWORD offHigh, DWORD offLow, DWORD size)
+{
+    dbgprintf("MapViewOfFile(%d, %x, %x, %x, %x)\n",
+	file,mode,offHigh,offLow,size);
+    return (char*)file+offLow;
+}
+
+void* WINAPI expUnmapViewOfFile(void* view)
+{
+    dbgprintf("UnmapViewOfFile()\n");
+    return 0;
+}
+
+void* WINAPI expSleep(int time)
+{
+    dbgprintf("Sleep(%d)\n", time);
+    usleep(time);
+    return 0;
+}
+ // why does IV32 codec want to call this? I don't know ...
+void* WINAPI expCreateCompatibleDC(int hdc)
+{
+        dbgprintf("CreateCompatibleDC(%d)\n", hdc);
+        return (void*)129;
+}
+
+int WINAPI expGetDeviceCaps(int hdc, int unk)
+{
+        dbgprintf("GetDeviceCaps(%d, %d)\n", hdc, unk);
+        return 0;
+}
+
+WIN_BOOL WINAPI expDeleteDC(int hdc)
+{
+        dbgprintf("DeleteDC(%d)\n", hdc);
+        return 0;
+}
+
+int expwsprintfA(char* string, char* format, ...)
+{
+    va_list va;
+    va_start(va, format);
+    dbgprintf("wsprintfA\n");
+    return vsprintf(string, format, va);
+}
+
+int WINAPI expGetPrivateProfileIntA(const char* appname, const char* keyname, int default_value, const char* filename)
+{
+    int size=255;
+    char buffer[256];
+    char* fullname;
+    int result;
+    
+    buffer[255]=0;
+    dbgprintf("GetPrivateProfileIntA(%s, %s, %s)\n", appname, keyname, filename );
+    if(!(appname && keyname && filename) ) return default_value;
+    fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
+    strcpy(fullname, "Software\\IniFileMapping\\");
+    strcat(fullname, appname);
+    strcat(fullname, "\\");
+    strcat(fullname, keyname);
+    strcat(fullname, "\\");
+    strcat(fullname, filename);
+    result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)buffer, &size);
+    if((size>=0)&&(size<256))
+	buffer[size]=0;
+//    printf("GetPrivateProfileIntA(%s, %s, %s) -> %s\n", appname, keyname, filename, buffer);
+    free(fullname); 
+    if(result)
+    return default_value;
+    else
+	return atoi(buffer);    	
+}
+int WINAPI expGetPrivateProfileStringA(const char* appname, const char* keyname,
+	const char* def_val, char* dest, unsigned int len, const char* filename)
+{
+    int result;
+    int size;
+    char* fullname;
+    dbgprintf("GetPrivateProfileStringA(%s, %s, %s, %X, %X, %s)\n", appname, keyname, def_val, dest, len, filename );
+    if(!(appname && keyname && filename) ) return 0;
+    fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
+    strcpy(fullname, "Software\\IniFileMapping\\");
+    strcat(fullname, appname);
+    strcat(fullname, "\\");
+    strcat(fullname, keyname);
+    strcat(fullname, "\\");
+    strcat(fullname, filename);
+    size=len;
+    result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)dest, &size);
+//    printf("GetPrivateProfileStringA(%s, %s, %s, %X, %X, %s)\n", appname, keyname, def_val, dest, len, filename );
+    free(fullname); 
+    if(!result)
+	return size;
+    strncpy(dest, def_val, size);
+    return size;
+}
+int WINAPI expWritePrivateProfileStringA(const char* appname, const char* keyname,
+	const char* string, const char* filename)
+{
+    int size=256;
+    char* fullname;
+    dbgprintf("WritePrivateProfileStringA(%s, %s, %s, %s)\n", appname, keyname, string, filename );
+    if(!(appname && keyname && filename) ) return -1;
+    fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
+    strcpy(fullname, "Software\\IniFileMapping\\");
+    strcat(fullname, appname);
+    strcat(fullname, "\\");
+    strcat(fullname, keyname);
+    strcat(fullname, "\\");
+    strcat(fullname, filename);
+    RegSetValueExA(HKEY_LOCAL_MACHINE, fullname, 0, REG_SZ, (int*)string, strlen(string));
+//    printf("RegSetValueExA(%s,%d)\n", string, strlen(string));
+//    printf("WritePrivateProfileStringA(%s, %s, %s, %s)\n", appname, keyname, string, filename );
+    free(fullname); 
+    return 0;
+}
+
+unsigned int _GetPrivateProfileIntA(const char* appname, const char* keyname, INT default_value, const char* filename)
+{
+    return expGetPrivateProfileIntA(appname, keyname, default_value, filename);
+}
+int _GetPrivateProfileStringA(const char* appname, const char* keyname,
+	const char* def_val, char* dest, unsigned int len, const char* filename)
+{
+    return expGetPrivateProfileStringA(appname, keyname, def_val, dest, len, filename);
+}
+int _WritePrivateProfileStringA(const char* appname, const char* keyname,
+	const char* string, const char* filename)
+{
+    return expWritePrivateProfileStringA(appname, keyname, string, filename);
+}
+
+
+int WINAPI expDefDriverProc(int _private, int id, int msg, int arg1, int arg2)
+{
+    printf("Called DefDriverProc(%X)\n", msg);
+    return 0;
+}    
+
+int WINAPI expSizeofResource(int v1, int v2)
+{
+    dbgprintf("SizeofResource()\n");
+    return SizeofResource(v1, v2);
+}    
+
+int WINAPI expGetLastError()
+{
+    dbgprintf("GetLastError()\n");
+    return GetLastError();
+}
+
+void WINAPI expSetLastError(int error)
+{
+    dbgprintf("SetLastError()\n");
+    SetLastError(error);
+}        
+
+char* expstrrchr(char* string, int value)
+{
+    return strrchr(string, value);
+}    
+
+char* expstrchr(char* string, int value)
+{
+    return strchr(string, value);
+}    
+
+int WINAPI expGetFileVersionInfoSizeA(const char* name, int* lpHandle)
+{
+    printf("GetFileVersionInfoSizeA(%s,0x%X)\n", name, lpHandle);
+    return 0;
+}    
+
+int WINAPI expIsBadStringPtrW(const short* string, int nchars)
+{
+    if(string==0)return 1;
+    return 0;
+}    
+extern long WINAPI InterlockedExchangeAdd( long* dest, long incr )
+{
+    long ret;
+    __asm__ __volatile__( "lock; xaddl %0,(%1)"
+                          : "=r" (ret) : "r" (dest), "0" (incr) : "memory" );
+    return ret;
+}
+
+extern long WINAPI expInterlockedIncrement( long* dest )
+{
+    return InterlockedExchangeAdd( dest, 1 ) + 1;
+}
+extern long WINAPI expInterlockedDecrement( long* dest )
+{
+    return InterlockedExchangeAdd( dest, -1 ) - 1;
+}
+
+extern void WINAPI expOutputDebugStringA( const char* string )
+{
+    fprintf(stderr, "DEBUG: %s\n", string);
+}    
+
+int WINAPI expGetDC(int hwnd)
+{
+    return 0;
+}
+
+int WINAPI expGetDesktopWindow()
+{
+    return 0;
+}
+     
+int WINAPI expReleaseDC(int hwnd, int hdc)
+{
+    return 0;
+}    
+
+int WINAPI expGetSystemPaletteEntries(int hdc, int iStartIndex, int nEntries, void* lppe)
+{
+    return 0;
+}    
+/*
+typedef struct _TIME_ZONE_INFORMATION {
+    long Bias;
+    char StandardName[32];
+    SYSTEMTIME StandardDate;
+    long StandardBias;
+    char DaylightName[32];
+    SYSTEMTIME DaylightDate;
+    long DaylightBias;
+} TIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;    
+*/
+
+int WINAPI expGetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
+{
+    memset(lpTimeZoneInformation, 0, sizeof(TIME_ZONE_INFORMATION));
+    return 0;
+}    
+
+void WINAPI expGetLocalTime(SYSTEMTIME* systime)
+{
+    time_t local_time;
+    struct tm *local_tm;
+    struct timeval tv;
+    
+    gettimeofday(&tv, NULL);
+    local_time=tv.tv_sec;
+    local_tm=localtime(&local_time);
+    
+    systime->wYear = local_tm->tm_year + 1900;
+    systime->wMonth = local_tm->tm_mon + 1;
+    systime->wDayOfWeek = local_tm->tm_wday;
+    systime->wDay = local_tm->tm_mday;
+    systime->wHour = local_tm->tm_hour;
+    systime->wMinute = local_tm->tm_min;
+    systime->wSecond = local_tm->tm_sec;
+    systime->wMilliseconds = (tv.tv_usec / 1000) % 1000;
+}
+
+int WINAPI expGetSystemTime(SYSTEMTIME* systime)
+{
+    time_t local_time;
+    struct tm *local_tm;
+    struct timeval tv;
+    
+    gettimeofday(&tv, NULL);
+    local_time=tv.tv_sec;
+    local_tm=gmtime(&local_time);
+    
+    systime->wYear = local_tm->tm_year + 1900;
+    systime->wMonth = local_tm->tm_mon + 1;
+    systime->wDayOfWeek = local_tm->tm_wday;
+    systime->wDay = local_tm->tm_mday;
+    systime->wHour = local_tm->tm_hour;
+    systime->wMinute = local_tm->tm_min;
+    systime->wSecond = local_tm->tm_sec;
+    systime->wMilliseconds = (tv.tv_usec / 1000) % 1000;
+    
+}
+
+int WINAPI expGetEnvironmentVariableA(const char* name, char* field, int size)
+{
+    dbgprintf("GetEnvironmentVariableA\n");
+    printf("%s %x %x\n", name, field, size);
+    if(field)field[0]=0;
+    return 0;
+}
+
+
+//HDRVR WINAPI expOpenDriverA(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam2);
+//HDRVR WINAPI expOpenDriverW(LPCWSTR szDriverName, LPCWSTR szSectionName, LPARAM lParam2);
+HDRVR WINAPI expOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam2){
+  printf("winmm32::OpenDriver() called\n");
+  return NULL;
+}
+
+
+struct exports
+{
+    char name[64];
+    int id;
+    void* func;
+};
+struct libs 
+{
+    char name[64];
+    int length;
+    struct exports* exps;
+};
+
+#define FF(X,Y) \
+{#X, Y, (void*)exp##X},
+
+struct exports exp_kernel32[]={
+FF(IsBadWritePtr, 357)
+FF(IsBadReadPtr, 354)
+FF(IsBadStringPtrW, -1)
+FF(DisableThreadLibraryCalls, -1)
+FF(CreateThread, -1)
+FF(CreateEventA, -1)
+FF(SetEvent, -1)
+FF(ResetEvent, -1)
+FF(WaitForSingleObject, -1)
+FF(GetSystemInfo, -1)
+FF(GetVersion, 332)
+FF(HeapCreate, 461)
+FF(HeapAlloc, -1)
+FF(HeapDestroy, -1)
+FF(HeapFree, -1)
+FF(HeapSize, -1)
+FF(GetProcessHeap, -1)
+FF(VirtualAlloc, -1)
+FF(VirtualFree, -1)
+FF(InitializeCriticalSection, -1) 
+FF(EnterCriticalSection, -1)
+FF(LeaveCriticalSection, -1) 
+FF(DeleteCriticalSection, -1)
+FF(TlsAlloc, -1)
+FF(TlsFree, -1)
+FF(TlsGetValue, -1)
+FF(TlsSetValue, -1)
+FF(GetCurrentThreadId, -1)
+FF(LocalAlloc, -1) 
+FF(LocalLock, -1)
+FF(GlobalAlloc, -1)
+FF(GlobalLock, -1)
+FF(MultiByteToWideChar, 427)
+FF(WideCharToMultiByte, -1)
+FF(GetVersionExA, -1)
+FF(CreateSemaphoreA, -1)
+FF(QueryPerformanceCounter, -1)
+FF(QueryPerformanceFrequency, -1)
+FF(LocalHandle, -1)
+FF(LocalUnlock, -1)
+FF(LocalFree, -1)
+FF(GlobalHandle, -1)
+FF(GlobalUnlock, -1)
+FF(GlobalFree, -1)
+FF(LoadResource, -1)
+FF(ReleaseSemaphore, -1) 
+FF(FindResourceA, -1)
+FF(LockResource, -1)
+FF(FreeResource, -1)
+FF(SizeofResource, -1)
+FF(CloseHandle, -1)
+FF(GetCommandLineA, -1)
+FF(GetEnvironmentStringsW, -1)
+FF(FreeEnvironmentStringsW, -1)
+FF(GetEnvironmentStrings, -1)  
+FF(GetStartupInfoA, -1)
+FF(GetStdHandle, -1)
+FF(GetFileType, -1)
+FF(SetHandleCount, -1)
+FF(GetACP, -1)
+FF(GetModuleFileNameA, -1)
+FF(SetUnhandledExceptionFilter, -1)
+FF(LoadLibraryA, -1)
+FF(GetProcAddress, -1)
+FF(FreeLibrary, -1)
+FF(CreateFileMappingA, -1)
+FF(OpenFileMappingA, -1)
+FF(MapViewOfFile, -1)
+FF(UnmapViewOfFile, -1)
+FF(Sleep, -1)
+FF(GetModuleHandleA, -1)
+FF(GetPrivateProfileIntA, -1)
+FF(GetPrivateProfileStringA, -1)
+FF(WritePrivateProfileStringA, -1)
+FF(GetLastError, -1)
+FF(SetLastError, -1)
+FF(InterlockedIncrement, -1)
+FF(InterlockedDecrement, -1)
+FF(GetTimeZoneInformation, -1)
+FF(OutputDebugStringA, -1)
+FF(GetLocalTime, -1)
+FF(GetSystemTime, -1)
+FF(GetEnvironmentVariableA, -1)
+};
+
+struct exports exp_msvcrt[]={
+FF(malloc, -1)
+FF(_initterm, -1)
+FF(free, -1)
+{"??3@YAXPAX@Z", -1, expdelete},
+{"??2@YAPAXI@Z", -1, expnew},
+FF(strrchr, -1)
+FF(strchr, -1)
+};
+struct exports exp_winmm[]={
+FF(GetDriverModuleHandle, -1)
+FF(timeGetTime, -1)
+FF(DefDriverProc, -1)
+FF(OpenDriver, -1)
+};
+struct exports exp_user32[]={
+FF(LoadStringA, -1)
+FF(wsprintfA, -1)
+FF(GetDC, -1)
+FF(GetDesktopWindow, -1)
+FF(ReleaseDC, -1)
+};
+struct exports exp_advapi32[]={
+FF(RegOpenKeyA, -1)
+FF(RegOpenKeyExA, -1)
+FF(RegCreateKeyExA, -1)
+FF(RegQueryValueExA, -1)
+FF(RegSetValueExA, -1)
+FF(RegCloseKey, -1)
+};
+struct exports exp_gdi32[]={
+FF(CreateCompatibleDC, -1)
+FF(GetDeviceCaps, -1)
+FF(DeleteDC, -1)
+FF(GetSystemPaletteEntries, -1)
+};
+struct exports exp_version[]={
+FF(GetFileVersionInfoSizeA, -1)
+};
+#define LL(X) \
+{#X".dll", sizeof(exp_##X)/sizeof(struct exports), exp_##X},
+
+struct libs libraries[]={
+LL(kernel32)
+LL(msvcrt)
+LL(winmm)
+LL(user32)
+LL(advapi32)
+LL(gdi32)
+LL(version)
+};
+
+void* LookupExternal(const char* library, int ordinal)
+{
+    char* answ;
+    int i,j;
+    if(library==0)
+    {
+	printf("ERROR: library=0\n");
+	return (void*)ext_unknown;
+    }
+    printf("External func %s:%d\n", library, ordinal);
+//    printf("%x %x\n", &unk_exp1, &unk_exp2);
+
+    for(i=0; i<sizeof(libraries)/sizeof(struct libs); i++)
+    {
+	if(strcasecmp(library, libraries[i].name))
+	    continue;
+	for(j=0; j<libraries[i].length; j++)
+	{
+	    if(ordinal!=libraries[i].exps[j].id)
+		continue;
+	    printf("Hit: 0x%08X\n", libraries[i].exps[j].func);
+	    return libraries[i].exps[j].func;
+	}
+    }
+    if(pos>150)return 0;
+    answ=(char*)extcode+pos*0x64;
+    memcpy(answ, &unk_exp1, 0x64);
+    *(int*)(answ+9)=pos;
+    *(int*)(answ+47)-=((int)answ-(int)&unk_exp1);
+    sprintf(export_names[pos], "%s:%d", library, ordinal);
+    pos++;    
+    return (void*)answ;
+}    
+
+void* LookupExternalByName(const char* library, const char* name)
+{
+    char* answ;
+    int i,j;
+//   return (void*)ext_unknown;
+    if(library==0)
+    {
+	printf("ERROR: library=0\n");
+	return (void*)ext_unknown;
+    }
+    if(name==0)
+    {
+	printf("ERROR: name=0\n");
+	return (void*)ext_unknown;
+    }
+//    printf("External func %s:%s\n", library, name);
+    for(i=0; i<sizeof(libraries)/sizeof(struct libs); i++)
+    {
+	if(strcasecmp(library, libraries[i].name))
+	    continue;
+	for(j=0; j<libraries[i].length; j++)
+	{
+	    if(strcmp(name, libraries[i].exps[j].name))
+		continue;
+//	    printf("Hit: 0x%08X\n", libraries[i].exps[j].func);
+	    return libraries[i].exps[j].func;
+	}
+    }//    printf("%x %x\n", &unk_exp1, &unk_exp2);
+    //printf("Missing (%d) External func %s:%s\n", pos, library, name);
+    if(pos>150){
+//      printf("Warning! Too many missing externals!\n");
+      return 0;
+    }
+    strcpy(export_names[pos], name);
+    answ=(char*)extcode+pos*0x64;
+    memcpy(answ, &unk_exp1, 0x64);
+    *(int*)(answ+9)=pos;
+    *(int*)(answ+47)-=((int)answ-(int)&unk_exp1);
+    pos++;
+    return (void*)answ;
+//    memcpy(extcode, &unk_exp1, 0x64);
+//    *(int*)(extcode+52)-=((int)extcode-(int)&unk_exp1);
+//    return (void*)extcode;
+//    printf("Unknown func %s:%s\n", library, name);
+//    return (void*)ext_unknown;
+}
+