]> git.sesse.net Git - vlc/blob - loader/win32.c
* Fix the Mac OS X Resources MAKE_DIST (untested)
[vlc] / loader / win32.c
1 /***********************************************************
2
3 Win32 emulation code. Functions that emulate
4 responses from corresponding Win32 API calls.
5 Since we are not going to be able to load
6 virtually any DLL, we can only implement this
7 much, adding needed functions with each new codec.
8
9 Basic principle of implementation: it's not good
10 for DLL to know too much about its environment.
11
12 ************************************************************/
13
14 /*
15  * Modified for use with MPlayer, detailed CVS changelog at
16  * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
17  * $Id$
18  */
19
20 #include "config.h"
21
22 #ifdef MPLAYER
23 #ifdef USE_QTX_CODECS
24 #define QTX
25 #endif
26 #define REALPLAYER
27 //#define LOADLIB_TRY_NATIVE
28 #endif
29
30 #ifdef QTX
31 #define PSEUDO_SCREEN_WIDTH     /*640*/800
32 #define PSEUDO_SCREEN_HEIGHT    /*480*/600
33 #endif
34
35 #include "wine/winbase.h"
36 #include "wine/winreg.h"
37 #include "wine/winnt.h"
38 #include "wine/winerror.h"
39 #include "wine/debugtools.h"
40 #include "wine/module.h"
41 #include "wine/winuser.h"
42
43 #include <stdio.h>
44 #include "win32.h"
45
46 #include "registry.h"
47 #include "loader.h"
48 #include "com.h"
49 #include "ext.h"
50
51 #include <stdlib.h>
52 #include <assert.h>
53 #include <stdarg.h>
54 #include <ctype.h>
55 #include <pthread.h>
56 #include <errno.h>
57 #ifdef HAVE_MALLOC_H
58 #include <malloc.h>
59 #endif
60 #include <time.h>
61 #include <math.h>
62 #include <unistd.h>
63 #include <fcntl.h>
64 #include <sys/types.h>
65 #include <dirent.h>
66 #include <sys/time.h>
67 #include <sys/timeb.h>
68 #ifdef  HAVE_KSTAT
69 #include <kstat.h>
70 #endif
71
72 #if HAVE_VSSCANF
73 int vsscanf( const char *str, const char *format, va_list ap);
74 #else
75 /* system has no vsscanf.  try to provide one */
76 static int vsscanf( const char *str, const char *format, va_list ap)
77 {
78     long p1 = va_arg(ap, long);
79     long p2 = va_arg(ap, long);
80     long p3 = va_arg(ap, long);
81     long p4 = va_arg(ap, long);
82     long p5 = va_arg(ap, long);
83     return sscanf(str, format, p1, p2, p3, p4, p5);
84 }
85 #endif
86
87 char* def_path = WIN32_PATH;
88
89 static void do_cpuid(unsigned int ax, unsigned int *regs)
90 {
91     __asm__ __volatile__
92         (
93          "pushl %%ebx; pushl %%ecx; pushl %%edx;"
94          ".byte  0x0f, 0xa2;"
95          "movl   %%eax, (%2);"
96          "movl   %%ebx, 4(%2);"
97          "movl   %%ecx, 8(%2);"
98          "movl   %%edx, 12(%2);"
99          "popl %%edx; popl %%ecx; popl %%ebx;"
100          : "=a" (ax)
101          :  "0" (ax), "S" (regs)
102         );
103 }
104 static unsigned int c_localcount_tsc()
105 {
106     int a;
107     __asm__ __volatile__
108         (
109          "rdtsc\n\t"
110          :"=a"(a)
111          :
112          :"edx"
113         );
114     return a;
115 }
116 static void c_longcount_tsc(long long* z)
117 {
118     __asm__ __volatile__
119         (
120          "pushl %%ebx\n\t"
121          "movl %%eax, %%ebx\n\t"
122          "rdtsc\n\t"
123          "movl %%eax, 0(%%ebx)\n\t"
124          "movl %%edx, 4(%%ebx)\n\t"
125          "popl %%ebx\n\t"
126          ::"a"(z)
127          :"edx"
128         );
129 }
130 static unsigned int c_localcount_notsc()
131 {
132     struct timeval tv;
133     unsigned limit=~0;
134     limit/=1000000;
135     gettimeofday(&tv, 0);
136     return limit*tv.tv_usec;
137 }
138 static void c_longcount_notsc(long long* z)
139 {
140     struct timeval tv;
141     unsigned long long result;
142     unsigned limit=~0;
143     if(!z)return;
144     limit/=1000000;
145     gettimeofday(&tv, 0);
146     result=tv.tv_sec;
147     result<<=32;
148     result+=limit*tv.tv_usec;
149     *z=result;
150 }
151 static unsigned int localcount_stub(void);
152 static void longcount_stub(long long*);
153 static unsigned int (*localcount)()=localcount_stub;
154 static void (*longcount)(long long*)=longcount_stub;
155
156 static pthread_mutex_t memmut;
157
158 static unsigned int localcount_stub(void)
159 {
160     unsigned int regs[4];
161     do_cpuid(1, regs);
162     if ((regs[3] & 0x00000010) != 0)
163     {
164         localcount=c_localcount_tsc;
165         longcount=c_longcount_tsc;
166     }
167     else
168     {
169         localcount=c_localcount_notsc;
170         longcount=c_longcount_notsc;
171     }
172     return localcount();
173 }
174 static void longcount_stub(long long* z)
175 {
176     unsigned int regs[4];
177     do_cpuid(1, regs);
178     if ((regs[3] & 0x00000010) != 0)
179     {
180         localcount=c_localcount_tsc;
181         longcount=c_longcount_tsc;
182     }
183     else
184     {
185         localcount=c_localcount_notsc;
186         longcount=c_longcount_notsc;
187     }
188     longcount(z);
189 }
190
191 #ifdef MPLAYER
192 #include "../mp_msg.h"
193 #endif
194 int LOADER_DEBUG=1; // active only if compiled with -DDETAILED_OUT
195 //#define DETAILED_OUT
196 static inline void dbgprintf(char* fmt, ...)
197 {
198 #ifdef DETAILED_OUT
199     if(LOADER_DEBUG)
200     {
201         FILE* f;
202         va_list va;
203         va_start(va, fmt);
204         f=fopen("./log", "a");
205         vprintf(fmt, va);
206         fflush(stdout);
207         if(f)
208         {
209             vfprintf(f, fmt, va);
210             fsync(fileno(f));
211             fclose(f);
212         }
213         va_end(va);
214     }
215 #endif
216 #ifdef MPLAYER
217     if (verbose > 2)
218     {
219         va_list va;
220         
221         va_start(va, fmt);
222         vprintf(fmt, va);
223 //      mp_dbg(MSGT_WIN32, MSGL_DBG3, fmt, va);
224         va_end(va);
225     }
226   fflush(stdout);
227 #endif
228 }
229
230
231 char export_names[300][32]={
232     "name1",
233     //"name2",
234     //"name3"
235 };
236 //#define min(x,y) ((x)<(y)?(x):(y))
237
238 void destroy_event(void* event);
239
240 struct th_list_t;
241 typedef struct th_list_t{
242     int id;
243     void* thread;
244     struct th_list_t* next;
245     struct th_list_t* prev;
246 } th_list;
247
248
249 // have to be cleared by GARBAGE COLLECTOR
250 static unsigned char* heap=NULL;
251 static int heap_counter=0;
252 static tls_t* g_tls=NULL;
253 static th_list* list=NULL;
254
255 static void test_heap(void)
256 {
257     int offset=0;
258     if(heap==0)
259         return;
260     while(offset<heap_counter)
261     {
262         if(*(int*)(heap+offset)!=0x433476)
263         {
264             printf("Heap corruption at address %d\n", offset);
265             return;
266         }
267         offset+=8+*(int*)(heap+offset+4);
268     }
269     for(;offset<min(offset+1000, 20000000); offset++)
270         if(heap[offset]!=0xCC)
271         {
272             printf("Free heap corruption at address %d\n", offset);
273         }
274 }
275 #undef MEMORY_DEBUG
276
277 #ifdef MEMORY_DEBUG
278
279 static void* my_mreq(int size, int to_zero)
280 {
281     static int test=0;
282     test++;
283     if(test%10==0)printf("Memory: %d bytes allocated\n", heap_counter);
284     //    test_heap();
285     if(heap==NULL)
286     {
287         heap=malloc(20000000);
288         memset(heap, 0xCC,20000000);
289     }
290     if(heap==0)
291     {
292         printf("No enough memory\n");
293         return 0;
294     }
295     if(heap_counter+size>20000000)
296     {
297         printf("No enough memory\n");
298         return 0;
299     }
300     *(int*)(heap+heap_counter)=0x433476;
301     heap_counter+=4;
302     *(int*)(heap+heap_counter)=size;
303     heap_counter+=4;
304     printf("Allocated %d bytes of memory: sys %d, user %d-%d\n", size, heap_counter-8, heap_counter, heap_counter+size);
305     if(to_zero)
306         memset(heap+heap_counter, 0, size);
307     else
308         memset(heap+heap_counter, 0xcc, size);  // make crash reproducable
309     heap_counter+=size;
310     return heap+heap_counter-size;
311 }
312 static int my_release(char* memory)
313 {
314     //    test_heap();
315     if(memory==NULL)
316     {
317         printf("ERROR: free(0)\n");
318         return 0;
319     }
320     if(*(int*)(memory-8)!=0x433476)
321     {
322         printf("MEMORY CORRUPTION !!!!!!!!!!!!!!!!!!!\n");
323         return 0;
324     }
325     printf("Freed %d bytes of memory\n", *(int*)(memory-4));
326     //    memset(memory-8, *(int*)(memory-4), 0xCC);
327     return 0;
328 }
329
330 #else
331 #define GARBAGE
332 typedef struct alloc_header_t alloc_header;
333 struct alloc_header_t
334 {
335     // let's keep allocated data 16 byte aligned
336     alloc_header* prev;
337     alloc_header* next;
338     long deadbeef;
339     long size;
340     long type;
341     long reserved1;
342     long reserved2;
343     long reserved3;
344 };
345
346 #ifdef GARBAGE
347 static alloc_header* last_alloc = NULL;
348 static int alccnt = 0;
349 #endif
350
351 #define AREATYPE_CLIENT 0
352 #define AREATYPE_EVENT 1
353 #define AREATYPE_MUTEX 2
354 #define AREATYPE_COND 3
355 #define AREATYPE_CRITSECT 4
356
357 /* -- critical sections -- */
358 struct CRITSECT
359 {
360     pthread_t id;
361     pthread_mutex_t mutex;
362     int locked;
363     long deadbeef;
364 };
365
366 void* mreq_private(int size, int to_zero, int type);
367 void* mreq_private(int size, int to_zero, int type)
368 {
369     int nsize = size + sizeof(alloc_header);
370     alloc_header* header = (alloc_header* ) malloc(nsize);
371     if (!header)
372         return 0;
373     if (to_zero)
374         memset(header, 0, nsize);
375 #ifdef GARBAGE
376     if (!last_alloc)
377     {
378         pthread_mutex_init(&memmut, NULL);
379         pthread_mutex_lock(&memmut);
380     }
381     else
382     {
383         pthread_mutex_lock(&memmut);
384         last_alloc->next = header;  /* set next */
385     }
386
387     header->prev = last_alloc;
388     header->next = 0;
389     last_alloc = header;
390     alccnt++;
391     pthread_mutex_unlock(&memmut);
392 #endif
393     header->deadbeef = 0xdeadbeef;
394     header->size = size;
395     header->type = type;
396
397     //if (alccnt < 40000) printf("MY_REQ: %p\t%d   t:%d  (cnt:%d)\n",  header, size, type, alccnt);
398     return header + 1;
399 }
400
401 static int my_release(void* memory)
402 {
403     alloc_header* header = (alloc_header*) memory - 1;
404 #ifdef GARBAGE
405     alloc_header* prevmem;
406     alloc_header* nextmem;
407
408     if (memory == 0)
409         return 0;
410
411     if (header->deadbeef != (long) 0xdeadbeef)
412     {
413         dbgprintf("FATAL releasing corrupted memory! %p  0x%lx  (%d)\n", header, header->deadbeef, alccnt);
414         return 0;
415     }
416
417     pthread_mutex_lock(&memmut);
418
419     switch(header->type)
420     {
421     case AREATYPE_EVENT:
422         destroy_event(memory);
423         break;
424     case AREATYPE_COND:
425         pthread_cond_destroy((pthread_cond_t*)memory);
426         break;
427     case AREATYPE_MUTEX:
428         pthread_mutex_destroy((pthread_mutex_t*)memory);
429         break;
430     case AREATYPE_CRITSECT:
431         pthread_mutex_destroy(&((struct CRITSECT*)memory)->mutex);
432         break;
433     default:
434         //memset(memory, 0xcc, header->size);
435         ;
436     }
437
438     header->deadbeef = 0;
439     prevmem = header->prev;
440     nextmem = header->next;
441
442     if (prevmem)
443         prevmem->next = nextmem;
444     if (nextmem)
445         nextmem->prev = prevmem;
446
447     if (header == last_alloc)
448         last_alloc = prevmem;
449
450     alccnt--;
451
452     if (last_alloc)
453         pthread_mutex_unlock(&memmut);
454     else
455         pthread_mutex_destroy(&memmut);
456
457     //if (alccnt < 40000) printf("MY_RELEASE: %p\t%ld    (%d)\n", header, header->size, alccnt);
458 #else
459     if (memory == 0)
460         return 0;
461 #endif
462     //memset(header + 1, 0xcc, header->size);
463     free(header);
464     return 0;
465 }
466 #endif
467
468 static inline void* my_mreq(int size, int to_zero)
469 {
470     return mreq_private(size, to_zero, AREATYPE_CLIENT);
471 }
472
473 static int my_size(void* memory)
474 {
475     if(!memory) return 0;
476     return ((alloc_header*)memory)[-1].size;
477 }
478
479 static void* my_realloc(void* memory, int size)
480 {
481     void *ans = memory;
482     int osize;
483     if (memory == NULL)
484         return my_mreq(size, 0);
485     osize = my_size(memory);
486     if (osize < size)
487     {
488         ans = my_mreq(size, 0);
489         memcpy(ans, memory, osize);
490         my_release(memory);
491     }
492     return ans;
493 }
494
495 /*
496  *
497  *  WINE  API  - native implementation for several win32 libraries
498  *
499  */
500
501 static int WINAPI ext_unknown()
502 {
503     printf("Unknown func called\n");
504     return 0;
505 }
506
507 static int  WINAPI expGetVolumeInformationA( const char *root, char *label,
508                                        unsigned int label_len, unsigned int *serial,
509                                        unsigned int *filename_len,unsigned int *flags,
510                                        char *fsname, unsigned int fsname_len )
511 {
512 dbgprintf("GetVolumeInformationA( %s, 0x%x, %ld, 0x%x, 0x%x, 0x%x, 0x%x, %ld) => 1\n",
513                       root,label,label_len,serial,filename_len,flags,fsname,fsname_len);
514 //hack Do not return any real data - do nothing
515 return 1;
516 }
517
518 static unsigned int WINAPI expGetDriveTypeA( const char *root )
519 {
520  dbgprintf("GetDriveTypeA( %s ) => %d\n",root,DRIVE_FIXED);
521  // hack return as Fixed Drive Type
522  return DRIVE_FIXED;
523 }
524
525 static unsigned int WINAPI expGetLogicalDriveStringsA( unsigned int len, char *buffer )
526 {
527  dbgprintf("GetLogicalDriveStringsA(%d, 0x%x) => 4\n",len,buffer);
528  // hack only have one drive c:\ in this hack
529   *buffer++='c';
530   *buffer++=':';
531   *buffer++='\\';
532   *buffer++='\0';
533   *buffer= '\0';
534 return 4; // 1 drive * 4 bytes (includes null)
535 }
536
537
538 static int WINAPI expIsBadWritePtr(void* ptr, unsigned int count)
539 {
540     int result = (count == 0 || ptr != 0) ? 0 : 1;
541     dbgprintf("IsBadWritePtr(0x%x, 0x%x) => %d\n", ptr, count, result);
542     return result;
543 }
544 static int WINAPI expIsBadReadPtr(void* ptr, unsigned int count)
545 {
546     int result = (count == 0 || ptr != 0) ? 0 : 1;
547     dbgprintf("IsBadReadPtr(0x%x, 0x%x) => %d\n", ptr, count, result);
548     return result;
549 }
550 static int WINAPI expDisableThreadLibraryCalls(int module)
551 {
552     dbgprintf("DisableThreadLibraryCalls(0x%x) => 0\n", module);
553     return 0;
554 }
555
556 static HMODULE WINAPI expGetDriverModuleHandle(DRVR* pdrv)
557 {
558     HMODULE result;
559     if (pdrv==NULL)
560         result=0;
561     else
562         result=pdrv->hDriverModule;
563     dbgprintf("GetDriverModuleHandle(%p) => %p\n", pdrv, result);
564     return result;
565 }
566
567 #define MODULE_HANDLE_kernel32  ((HMODULE)0x120)
568 #define MODULE_HANDLE_user32    ((HMODULE)0x121)
569 #ifdef QTX
570 #define MODULE_HANDLE_wininet   ((HMODULE)0x122)
571 #define MODULE_HANDLE_ddraw     ((HMODULE)0x123)
572 #define MODULE_HANDLE_advapi32  ((HMODULE)0x124)
573 #endif
574 #define MODULE_HANDLE_comdlg32  ((HMODULE)0x125)
575 #define MODULE_HANDLE_msvcrt    ((HMODULE)0x126)
576 #define MODULE_HANDLE_ole32     ((HMODULE)0x127)
577 #define MODULE_HANDLE_winmm     ((HMODULE)0x128)
578
579 static HMODULE WINAPI expGetModuleHandleA(const char* name)
580 {
581     WINE_MODREF* wm;
582     HMODULE result;
583     if(!name)
584 #ifdef QTX
585         result=1;
586 #else
587         result=0;
588 #endif
589     else
590     {
591         wm=MODULE_FindModule(name);
592         if(wm==0)result=0;
593         else
594             result=(HMODULE)(wm->module);
595     }
596     if(!result)
597     {
598         if(name && (strcasecmp(name, "kernel32")==0 || !strcasecmp(name, "kernel32.dll")))
599             result=MODULE_HANDLE_kernel32;
600 #ifdef QTX
601         if(name && strcasecmp(name, "user32")==0)
602             result=MODULE_HANDLE_user32;
603 #endif
604     }
605     dbgprintf("GetModuleHandleA('%s') => 0x%x\n", name, result);
606     return result;
607 }
608
609 static void* WINAPI expCreateThread(void* pSecAttr, long dwStackSize,
610                                     void* lpStartAddress, void* lpParameter,
611                                     long dwFlags, long* dwThreadId)
612 {
613     pthread_t *pth;
614     //    printf("CreateThread:");
615     pth = (pthread_t*) my_mreq(sizeof(pthread_t), 0);
616     pthread_create(pth, NULL, (void*(*)(void*))lpStartAddress, lpParameter);
617     if(dwFlags)
618         printf( "WARNING: CreateThread flags not supported\n");
619     if(dwThreadId)
620         *dwThreadId=(long)pth;
621     if(list==NULL)
622     {
623         list=my_mreq(sizeof(th_list), 1);
624         list->next=list->prev=NULL;
625     }
626     else
627     {
628         list->next=my_mreq(sizeof(th_list), 0);
629         list->next->prev=list;
630         list->next->next=NULL;
631         list=list->next;
632     }
633     list->thread=pth;
634     dbgprintf("CreateThread(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) => 0x%x\n",
635               pSecAttr, dwStackSize, lpStartAddress, lpParameter, dwFlags, dwThreadId, pth);
636     return pth;
637 }
638
639 struct mutex_list_t;
640
641 struct mutex_list_t
642 {
643     char type;
644     pthread_mutex_t *pm;
645     pthread_cond_t  *pc;
646     char state;
647     char reset;
648     char name[128];
649     int  semaphore;
650     struct mutex_list_t* next;
651     struct mutex_list_t* prev;
652 };
653 typedef struct mutex_list_t mutex_list;
654 static mutex_list* mlist=NULL;
655
656 void destroy_event(void* event)
657 {
658     mutex_list* pp=mlist;
659     //    printf("garbage collector: destroy_event(%x)\n", event);
660     while(pp)
661     {
662         if(pp==(mutex_list*)event)
663         {
664             if(pp->next)
665                 pp->next->prev=pp->prev;
666             if(pp->prev)
667                 pp->prev->next=pp->next;
668             if(mlist==(mutex_list*)event)
669                 mlist=mlist->prev;
670             /*
671              pp=mlist;
672              while(pp)
673              {
674              printf("%x => ", pp);
675              pp=pp->prev;
676              }
677              printf("0\n");
678              */
679             return;
680         }
681         pp=pp->prev;
682     }
683 }
684
685 static void* WINAPI expCreateEventA(void* pSecAttr, char bManualReset,
686                                     char bInitialState, const char* name)
687 {
688     pthread_mutex_t *pm;
689     pthread_cond_t  *pc;
690     /*
691      mutex_list* pp;
692      pp=mlist;
693      while(pp)
694      {
695      printf("%x => ", pp);
696      pp=pp->prev;
697      }
698      printf("0\n");
699      */
700     if(mlist!=NULL)
701     {
702         mutex_list* pp=mlist;
703         if(name!=NULL)
704             do
705         {
706             if((strcmp(pp->name, name)==0) && (pp->type==0))
707             {
708                 dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n",
709                           pSecAttr, bManualReset, bInitialState, name, name, pp->pm);
710                 return pp->pm;
711             }
712         }while((pp=pp->prev) != NULL);
713     }
714     pm=mreq_private(sizeof(pthread_mutex_t), 0, AREATYPE_MUTEX);
715     pthread_mutex_init(pm, NULL);
716     pc=mreq_private(sizeof(pthread_cond_t), 0, AREATYPE_COND);
717     pthread_cond_init(pc, NULL);
718     if(mlist==NULL)
719     {
720         mlist=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
721         mlist->next=mlist->prev=NULL;
722     }
723     else
724     {
725         mlist->next=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
726         mlist->next->prev=mlist;
727         mlist->next->next=NULL;
728         mlist=mlist->next;
729     }
730     mlist->type=0; /* Type Event */
731     mlist->pm=pm;
732     mlist->pc=pc;
733     mlist->state=bInitialState;
734     mlist->reset=bManualReset;
735     if(name)
736         strncpy(mlist->name, name, 127);
737     else
738         mlist->name[0]=0;
739     if(pm==NULL)
740         dbgprintf("ERROR::: CreateEventA failure\n");
741     /*
742      if(bInitialState)
743      pthread_mutex_lock(pm);
744      */
745     if(name)
746         dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n",
747                   pSecAttr, bManualReset, bInitialState, name, name, mlist);
748     else
749         dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, NULL) => 0x%x\n",
750                   pSecAttr, bManualReset, bInitialState, mlist);
751     return mlist;
752 }
753
754 static void* WINAPI expSetEvent(void* event)
755 {
756     mutex_list *ml = (mutex_list *)event;
757     dbgprintf("SetEvent(%x) => 0x1\n", event);
758     pthread_mutex_lock(ml->pm);
759     if (ml->state == 0) {
760         ml->state = 1;
761         pthread_cond_signal(ml->pc);
762     }
763     pthread_mutex_unlock(ml->pm);
764
765     return (void *)1;
766 }
767 static void* WINAPI expResetEvent(void* event)
768 {
769     mutex_list *ml = (mutex_list *)event;
770     dbgprintf("ResetEvent(0x%x) => 0x1\n", event);
771     pthread_mutex_lock(ml->pm);
772     ml->state = 0;
773     pthread_mutex_unlock(ml->pm);
774
775     return (void *)1;
776 }
777
778 static void* WINAPI expWaitForSingleObject(void* object, int duration)
779 {
780     mutex_list *ml = (mutex_list *)object;
781     // FIXME FIXME FIXME - this value is sometime unititialize !!!
782     int ret = WAIT_FAILED;
783     mutex_list* pp=mlist;
784     if(object == (void*)0xcfcf9898)
785     {
786         /**
787          From GetCurrentThread() documentation:
788          A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes.
789
790          This handle has the maximum possible access to the thread object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is THREAD_ALL_ACCESS.
791
792          The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function.
793          **/
794         dbgprintf("WaitForSingleObject(thread_handle) called\n");
795         return (void*)WAIT_FAILED;
796     }
797     dbgprintf("WaitForSingleObject(0x%x, duration %d) =>\n",object, duration);
798
799     // loop below was slightly fixed - its used just for checking if
800     // this object really exists in our list
801     if (!ml)
802         return (void*) ret;
803     while (pp && (pp->pm != ml->pm))
804         pp = pp->prev;
805     if (!pp) {
806         dbgprintf("WaitForSingleObject: NotFound\n");
807         return (void*)ret;
808     }
809
810     pthread_mutex_lock(ml->pm);
811
812     switch(ml->type) {
813     case 0: /* Event */
814         if (duration == 0) { /* Check Only */
815             if (ml->state == 1) ret = WAIT_FAILED;
816             else                   ret = WAIT_OBJECT_0;
817         }
818         if (duration == -1) { /* INFINITE */
819             if (ml->state == 0)
820                 pthread_cond_wait(ml->pc,ml->pm);
821             if (ml->reset)
822                 ml->state = 0;
823             ret = WAIT_OBJECT_0;
824         }
825         if (duration > 0) {  /* Timed Wait */
826             struct timespec abstime;
827             struct timeval now;
828             gettimeofday(&now, 0);
829             abstime.tv_sec = now.tv_sec + (now.tv_usec+duration)/1000000;
830             abstime.tv_nsec = ((now.tv_usec+duration)%1000000)*1000;
831             if (ml->state == 0)
832                 ret=pthread_cond_timedwait(ml->pc,ml->pm,&abstime);
833             if (ret == ETIMEDOUT) ret = WAIT_TIMEOUT;
834             else                  ret = WAIT_OBJECT_0;
835             if (ml->reset)
836                 ml->state = 0;
837         }
838         break;
839     case 1:  /* Semaphore */
840         if (duration == 0) {
841             if(ml->semaphore==0) ret = WAIT_FAILED;
842             else {
843                 ml->semaphore++;
844                 ret = WAIT_OBJECT_0;
845             }
846         }
847         if (duration == -1) {
848             if (ml->semaphore==0)
849                 pthread_cond_wait(ml->pc,ml->pm);
850             ml->semaphore--;
851         }
852         break;
853     }
854     pthread_mutex_unlock(ml->pm);
855
856     dbgprintf("WaitForSingleObject(0x%x, %d): 0x%x => 0x%x \n",object,duration,ml,ret);
857     return (void *)ret;
858 }
859
860 #ifdef QTX
861 static void* WINAPI expWaitForMultipleObjects(int count, const void** objects,
862                     int WaitAll, int duration)
863 {
864     int i;
865     void *object;
866     void *ret;
867
868     dbgprintf("WaitForMultipleObjects(%d, 0x%x, %d, duration %d) =>\n",
869         count, objects, WaitAll, duration);
870     
871     for (i = 0; i < count; i++)
872     {
873         object = (void *)objects[i];
874         ret = expWaitForSingleObject(object, duration);
875         if (WaitAll)
876             dbgprintf("WaitAll flag not yet supported...\n");
877         else
878             return ret;
879     }
880     return NULL;
881 }
882
883 static void WINAPI expExitThread(int retcode)
884 {
885     dbgprintf("ExitThread(%d)\n", retcode);
886     pthread_exit(&retcode);
887 }
888
889 static HANDLE WINAPI expCreateMutexA(void *pSecAttr,
890                     char bInitialOwner, const char *name)
891 {
892     HANDLE mlist = (HANDLE)expCreateEventA(pSecAttr, 0, 0, name);
893     
894     if (name)
895         dbgprintf("CreateMutexA(0x%x, %d, '%s') => 0x%x\n",
896             pSecAttr, bInitialOwner, name, mlist);
897     else
898         dbgprintf("CreateMutexA(0x%x, %d, NULL) => 0x%x\n",
899             pSecAttr, bInitialOwner, mlist);
900 #ifndef QTX
901     /* 10l to QTX, if CreateMutex returns a real mutex, WaitForSingleObject
902        waits for ever, else it works ;) */
903     return mlist;
904 #endif
905 }
906
907 static int WINAPI expReleaseMutex(HANDLE hMutex)
908 {
909     dbgprintf("ReleaseMutex(%x) => 1\n", hMutex);
910     /* FIXME:XXX !! not yet implemented */
911     return 1;
912 }
913 #endif
914
915 static int pf_set = 0;
916 static BYTE PF[64] = {0,};
917
918 static void DumpSystemInfo(const SYSTEM_INFO* si)
919 {
920     dbgprintf("  Processor architecture %d\n", si->u.s.wProcessorArchitecture);
921     dbgprintf("  Page size: %d\n", si->dwPageSize);
922     dbgprintf("  Minimum app address: %d\n", si->lpMinimumApplicationAddress);
923     dbgprintf("  Maximum app address: %d\n", si->lpMaximumApplicationAddress);
924     dbgprintf("  Active processor mask: 0x%x\n", si->dwActiveProcessorMask);
925     dbgprintf("  Number of processors: %d\n", si->dwNumberOfProcessors);
926     dbgprintf("  Processor type: 0x%x\n", si->dwProcessorType);
927     dbgprintf("  Allocation granularity: 0x%x\n", si->dwAllocationGranularity);
928     dbgprintf("  Processor level: 0x%x\n", si->wProcessorLevel);
929     dbgprintf("  Processor revision: 0x%x\n", si->wProcessorRevision);
930 }
931
932 static void WINAPI expGetSystemInfo(SYSTEM_INFO* si)
933 {
934     /* FIXME: better values for the two entries below... */
935     static int cache = 0;
936     static SYSTEM_INFO cachedsi;
937     unsigned int regs[4];
938     dbgprintf("GetSystemInfo(%p) =>\n", si);
939
940     if (cache) {
941         memcpy(si,&cachedsi,sizeof(*si));
942         DumpSystemInfo(si);
943         return;
944     }
945     memset(PF,0,sizeof(PF));
946     pf_set = 1;
947
948     cachedsi.u.s.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
949     cachedsi.dwPageSize                         = getpagesize();
950
951     /* FIXME: better values for the two entries below... */
952     cachedsi.lpMinimumApplicationAddress        = (void *)0x00000000;
953     cachedsi.lpMaximumApplicationAddress        = (void *)0x7FFFFFFF;
954     cachedsi.dwActiveProcessorMask              = 1;
955     cachedsi.dwNumberOfProcessors               = 1;
956     cachedsi.dwProcessorType            = PROCESSOR_INTEL_386;
957     cachedsi.dwAllocationGranularity    = 0x10000;
958     cachedsi.wProcessorLevel            = 5; /* pentium */
959     cachedsi.wProcessorRevision         = 0x0101;
960
961 #ifdef MPLAYER
962     /* mplayer's way to detect PF's */
963     {
964 #include "../cpudetect.h"
965         extern CpuCaps gCpuCaps;
966
967         if (gCpuCaps.hasMMX)
968             PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
969         if (gCpuCaps.hasSSE)
970             PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
971         if (gCpuCaps.has3DNow)
972             PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE;
973
974             if (gCpuCaps.cpuType == 4)
975             {
976                 cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
977                 cachedsi.wProcessorLevel = 4;
978             }
979             else if (gCpuCaps.cpuType >= 5)
980             {
981                 cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
982                 cachedsi.wProcessorLevel = 5;
983             }
984             else
985             {
986                 cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
987                 cachedsi.wProcessorLevel = 3;
988             }
989             cachedsi.wProcessorRevision = gCpuCaps.cpuStepping;
990             cachedsi.dwNumberOfProcessors = 1;  /* hardcoded */
991     }
992 #endif
993
994 /* disable cpuid based detection (mplayer's cpudetect.c does this - see above) */
995 #ifndef MPLAYER
996 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__svr4__) || defined(__DragonFly__)
997     do_cpuid(1, regs);
998     switch ((regs[0] >> 8) & 0xf) {                     // cpu family
999     case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
1000     cachedsi.wProcessorLevel= 3;
1001     break;
1002     case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
1003     cachedsi.wProcessorLevel= 4;
1004     break;
1005     case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1006     cachedsi.wProcessorLevel= 5;
1007     break;
1008     case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1009     cachedsi.wProcessorLevel= 5;
1010     break;
1011     default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1012     cachedsi.wProcessorLevel= 5;
1013     break;
1014     }
1015     cachedsi.wProcessorRevision = regs[0] & 0xf;        // stepping
1016     if (regs[3] & (1 <<  8))
1017         PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
1018     if (regs[3] & (1 << 23))
1019         PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
1020     if (regs[3] & (1 << 25))
1021         PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
1022     if (regs[3] & (1 << 31))
1023         PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE;
1024     cachedsi.dwNumberOfProcessors=1;
1025 #endif
1026 #endif /* MPLAYER */
1027
1028 /* MPlayer: linux detection enabled (based on proc/cpuinfo) for checking
1029    fdiv_bug and fpu emulation flags -- alex/MPlayer */
1030 #ifdef __linux__
1031     {
1032         char buf[20];
1033         char line[200];
1034         FILE *f = fopen ("/proc/cpuinfo", "r");
1035
1036         if (!f)
1037             return;
1038         while (fgets(line,200,f)!=NULL) {
1039             char        *s,*value;
1040
1041             /* NOTE: the ':' is the only character we can rely on */
1042             if (!(value = strchr(line,':')))
1043                 continue;
1044             /* terminate the valuename */
1045             *value++ = '\0';
1046             /* skip any leading spaces */
1047             while (*value==' ') value++;
1048             if ((s=strchr(value,'\n')))
1049                 *s='\0';
1050
1051             /* 2.1 method */
1052             if (!lstrncmpiA(line, "cpu family",strlen("cpu family"))) {
1053                 if (isdigit (value[0])) {
1054                     switch (value[0] - '0') {
1055                     case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
1056                     cachedsi.wProcessorLevel= 3;
1057                     break;
1058                     case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
1059                     cachedsi.wProcessorLevel= 4;
1060                     break;
1061                     case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1062                     cachedsi.wProcessorLevel= 5;
1063                     break;
1064                     case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1065                     cachedsi.wProcessorLevel= 5;
1066                     break;
1067                     default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1068                     cachedsi.wProcessorLevel= 5;
1069                     break;
1070                     }
1071                 }
1072                 /* set the CPU type of the current processor */
1073                 sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
1074                 continue;
1075             }
1076             /* old 2.0 method */
1077             if (!lstrncmpiA(line, "cpu",strlen("cpu"))) {
1078                 if (    isdigit (value[0]) && value[1] == '8' &&
1079                         value[2] == '6' && value[3] == 0
1080                    ) {
1081                     switch (value[0] - '0') {
1082                     case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
1083                     cachedsi.wProcessorLevel= 3;
1084                     break;
1085                     case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
1086                     cachedsi.wProcessorLevel= 4;
1087                     break;
1088                     case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1089                     cachedsi.wProcessorLevel= 5;
1090                     break;
1091                     case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1092                     cachedsi.wProcessorLevel= 5;
1093                     break;
1094                     default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
1095                     cachedsi.wProcessorLevel= 5;
1096                     break;
1097                     }
1098                 }
1099                 /* set the CPU type of the current processor */
1100                 sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
1101                 continue;
1102             }
1103             if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) {
1104                 if (!lstrncmpiA(value,"yes",3))
1105                     PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
1106
1107                 continue;
1108             }
1109             if (!lstrncmpiA(line,"fpu",strlen("fpu"))) {
1110                 if (!lstrncmpiA(value,"no",2))
1111                     PF[PF_FLOATING_POINT_EMULATED] = TRUE;
1112
1113                 continue;
1114             }
1115             if (!lstrncmpiA(line,"processor",strlen("processor"))) {
1116                 /* processor number counts up...*/
1117                 unsigned int x;
1118
1119                 if (sscanf(value,"%d",&x))
1120                     if (x+1>cachedsi.dwNumberOfProcessors)
1121                         cachedsi.dwNumberOfProcessors=x+1;
1122
1123                 /* Create a new processor subkey on a multiprocessor
1124                  * system
1125                  */
1126                 sprintf(buf,"%d",x);
1127             }
1128             if (!lstrncmpiA(line,"stepping",strlen("stepping"))) {
1129                 int     x;
1130
1131                 if (sscanf(value,"%d",&x))
1132                     cachedsi.wProcessorRevision = x;
1133             }
1134             if
1135                 ( (!lstrncmpiA(line,"flags",strlen("flags")))
1136                   || (!lstrncmpiA(line,"features",strlen("features"))) )
1137             {
1138                 if (strstr(value,"cx8"))
1139                     PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
1140                 if (strstr(value,"mmx"))
1141                     PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
1142                 if (strstr(value,"tsc"))
1143                     PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
1144                 if (strstr(value,"xmm"))
1145                     PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
1146                 if (strstr(value,"3dnow"))
1147                     PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE;
1148             }
1149         }
1150         fclose (f);
1151         /*
1152          *      ad hoc fix for smp machines.
1153          *      some problems on WaitForSingleObject,CreateEvent,SetEvent
1154          *                      CreateThread ...etc..
1155          *
1156          */
1157         cachedsi.dwNumberOfProcessors=1;
1158     }
1159 #endif /* __linux__ */
1160     cache = 1;
1161     memcpy(si,&cachedsi,sizeof(*si));
1162     DumpSystemInfo(si);
1163 }
1164
1165 // avoid undefined expGetSystemInfo
1166 static WIN_BOOL WINAPI expIsProcessorFeaturePresent(DWORD v)
1167 {
1168     WIN_BOOL result = 0;
1169     if (!pf_set)
1170     {
1171         SYSTEM_INFO si;
1172         expGetSystemInfo(&si);
1173     }
1174     if(v<64) result=PF[v];
1175     dbgprintf("IsProcessorFeaturePresent(0x%x) => 0x%x\n", v, result);
1176     return result;
1177 }
1178
1179
1180 static long WINAPI expGetVersion()
1181 {
1182     dbgprintf("GetVersion() => 0xC0000004\n");
1183     return 0xC0000004;//Windows 95
1184 }
1185
1186 static HANDLE WINAPI expHeapCreate(long flags, long init_size, long max_size)
1187 {
1188     //    printf("HeapCreate:");
1189     HANDLE result;
1190     if(init_size==0)
1191         result=(HANDLE)my_mreq(0x110000, 0);
1192     else
1193         result=(HANDLE)my_mreq((init_size + 0xfff) & 0x7ffff000 , 0);
1194     dbgprintf("HeapCreate(flags 0x%x, initial size %d, maximum size %d) => 0x%x\n", flags, init_size, max_size, result);
1195     return result;
1196 }
1197
1198 // this is another dirty hack
1199 // VP31 is releasing one allocated Heap chunk twice
1200 // we will silently ignore this second call...
1201 static void* heapfreehack = 0;
1202 static int heapfreehackshown = 0;
1203 //extern void trapbug(void);
1204 static void* WINAPI expHeapAlloc(HANDLE heap, int flags, int size)
1205 {
1206     void* z;
1207     /**
1208      Morgan's m3jpeg32.dll v. 2.0 encoder expects that request for
1209      HeapAlloc returns area larger than size argument :-/
1210
1211      actually according to M$ Doc  HeapCreate size should be rounded
1212      to page boundaries thus we should simulate this
1213      **/
1214     //if (size == 22276) trapbug();
1215     z=my_mreq((size + 0xfff) & 0x7ffff000, (flags & HEAP_ZERO_MEMORY));
1216     if(z==0)
1217         printf("HeapAlloc failure\n");
1218     dbgprintf("HeapAlloc(heap 0x%x, flags 0x%x, size %d) => 0x%x\n", heap, flags, size, z);
1219     heapfreehack = 0; // reset
1220     return z;
1221 }
1222 static long WINAPI expHeapDestroy(void* heap)
1223 {
1224     dbgprintf("HeapDestroy(heap 0x%x) => 1\n", heap);
1225     my_release(heap);
1226     return 1;
1227 }
1228
1229 static long WINAPI expHeapFree(HANDLE heap, DWORD dwFlags, LPVOID lpMem)
1230 {
1231     dbgprintf("HeapFree(0x%x, 0x%x, pointer 0x%x) => 1\n", heap, dwFlags, lpMem);
1232     if (heapfreehack != lpMem && lpMem != (void*)0xffffffff
1233         && lpMem != (void*)0xbdbdbdbd)
1234         // 0xbdbdbdbd is for i263_drv.drv && libefence
1235         // it seems to be reading from relased memory
1236         // EF_PROTECT_FREE doens't show any probleme
1237         my_release(lpMem);
1238     else
1239     {
1240         if (!heapfreehackshown++)
1241             printf("Info: HeapFree deallocating same memory twice! (%p)\n", lpMem);
1242     }
1243     heapfreehack = lpMem;
1244     return 1;
1245 }
1246 static long WINAPI expHeapSize(int heap, int flags, void* pointer)
1247 {
1248     long result=my_size(pointer);
1249     dbgprintf("HeapSize(heap 0x%x, flags 0x%x, pointer 0x%x) => %d\n", heap, flags, pointer, result);
1250     return result;
1251 }
1252 static void* WINAPI expHeapReAlloc(HANDLE heap,int flags,void *lpMem,int size)
1253 {
1254     long orgsize = my_size(lpMem);
1255     dbgprintf("HeapReAlloc() Size %ld org %d\n",orgsize,size);
1256     return my_realloc(lpMem, size);
1257 }
1258 static long WINAPI expGetProcessHeap(void)
1259 {
1260     dbgprintf("GetProcessHeap() => 1\n");
1261     return 1;
1262 }
1263 static void* WINAPI expVirtualAlloc(void* v1, long v2, long v3, long v4)
1264 {
1265     void* z = VirtualAlloc(v1, v2, v3, v4);
1266     if(z==0)
1267         printf("VirtualAlloc failure\n");
1268     dbgprintf("VirtualAlloc(0x%x, %d, %d, %d) => 0x%x \n",v1,v2,v3,v4, z);
1269     return z;
1270 }
1271 static int WINAPI expVirtualFree(void* v1, int v2, int v3)
1272 {
1273     int result = VirtualFree(v1,v2,v3);
1274     dbgprintf("VirtualFree(0x%x, %d, %d) => %d\n",v1,v2,v3, result);
1275     return result;
1276 }
1277
1278 /* we're building a table of critical sections. cs_win pointer uses the DLL
1279  cs_unix is the real structure, we're using cs_win only to identifying cs_unix */
1280 struct critsecs_list_t
1281 {
1282     CRITICAL_SECTION *cs_win;
1283     struct CRITSECT *cs_unix;
1284 };
1285
1286 /* 'NEWTYPE' is working with VIVO, 3ivX and QTX dll (no more segfaults) -- alex */
1287 #undef CRITSECS_NEWTYPE
1288 //#define CRITSECS_NEWTYPE 1
1289
1290 #ifdef CRITSECS_NEWTYPE
1291 /* increased due to ucod needs more than 32 entries */
1292 /* and 64 should be enough for everything */
1293 #define CRITSECS_LIST_MAX 64
1294 static struct critsecs_list_t critsecs_list[CRITSECS_LIST_MAX];
1295
1296 static int critsecs_get_pos(CRITICAL_SECTION *cs_win)
1297 {
1298     int i;
1299
1300     for (i=0; i < CRITSECS_LIST_MAX; i++)
1301         if (critsecs_list[i].cs_win == cs_win)
1302             return(i);
1303     return(-1);
1304 }
1305
1306 static int critsecs_get_unused(void)
1307 {
1308     int i;
1309
1310     for (i=0; i < CRITSECS_LIST_MAX; i++)
1311         if (critsecs_list[i].cs_win == NULL)
1312             return(i);
1313     return(-1);
1314 }
1315
1316 struct CRITSECT *critsecs_get_unix(CRITICAL_SECTION *cs_win)
1317 {
1318     int i;
1319
1320     for (i=0; i < CRITSECS_LIST_MAX; i++)
1321         if (critsecs_list[i].cs_win == cs_win && critsecs_list[i].cs_unix)
1322             return(critsecs_list[i].cs_unix);
1323     return(NULL);
1324 }
1325 #endif
1326
1327 static void WINAPI expInitializeCriticalSection(CRITICAL_SECTION* c)
1328 {
1329     dbgprintf("InitializeCriticalSection(0x%x)\n", c);
1330     /*    if(sizeof(pthread_mutex_t)>sizeof(CRITICAL_SECTION))
1331      {
1332      printf(" ERROR:::: sizeof(pthread_mutex_t) is %d, expected <=%d!\n",
1333      sizeof(pthread_mutex_t), sizeof(CRITICAL_SECTION));
1334      return;
1335      }*/
1336     /*    pthread_mutex_init((pthread_mutex_t*)c, NULL);   */
1337 #ifdef CRITSECS_NEWTYPE
1338     {
1339         struct CRITSECT *cs;
1340         int i = critsecs_get_unused();
1341
1342         if (i < 0)
1343         {
1344             printf("InitializeCriticalSection(%p) - no more space in list\n", c);
1345             return;
1346         }
1347         dbgprintf("got unused space at %d\n", i);
1348         cs = malloc(sizeof(struct CRITSECT));
1349         if (!cs)
1350         {
1351             printf("InitializeCriticalSection(%p) - out of memory\n", c);
1352             return;
1353         }
1354         pthread_mutex_init(&cs->mutex, NULL);
1355         cs->locked = 0;
1356         critsecs_list[i].cs_win = c;
1357         critsecs_list[i].cs_unix = cs;
1358         dbgprintf("InitializeCriticalSection -> itemno=%d, cs_win=%p, cs_unix=%p\n",
1359                   i, c, cs);
1360     }
1361 #else
1362     {
1363         struct CRITSECT* cs = mreq_private(sizeof(struct CRITSECT) + sizeof(CRITICAL_SECTION),
1364                                            0, AREATYPE_CRITSECT);
1365         pthread_mutex_init(&cs->mutex, NULL);
1366         cs->locked=0;
1367         cs->deadbeef = 0xdeadbeef;
1368         *(void**)c = cs;
1369     }
1370 #endif
1371     return;
1372 }
1373
1374 static void WINAPI expEnterCriticalSection(CRITICAL_SECTION* c)
1375 {
1376 #ifdef CRITSECS_NEWTYPE
1377     struct CRITSECT* cs = critsecs_get_unix(c);
1378 #else
1379     struct CRITSECT* cs = (*(struct CRITSECT**)c);
1380 #endif
1381     dbgprintf("EnterCriticalSection(0x%x) %p\n",c, cs);
1382     if (!cs)
1383     {
1384         dbgprintf("entered uninitialized critisec!\n");
1385         expInitializeCriticalSection(c);
1386 #ifdef CRITSECS_NEWTYPE
1387         cs=critsecs_get_unix(c);
1388 #else
1389         cs = (*(struct CRITSECT**)c);
1390 #endif
1391         dbgprintf("Win32 Warning: Accessed uninitialized Critical Section (%p)!\n", c);
1392     }
1393     if(cs->locked)
1394         if(cs->id==pthread_self())
1395             return;
1396     pthread_mutex_lock(&(cs->mutex));
1397     cs->locked=1;
1398     cs->id=pthread_self();
1399     return;
1400 }
1401 static void WINAPI expLeaveCriticalSection(CRITICAL_SECTION* c)
1402 {
1403 #ifdef CRITSECS_NEWTYPE
1404     struct CRITSECT* cs = critsecs_get_unix(c);
1405 #else
1406     struct CRITSECT* cs = (*(struct CRITSECT**)c);
1407 #endif
1408     //    struct CRITSECT* cs=(struct CRITSECT*)c;
1409     dbgprintf("LeaveCriticalSection(0x%x) 0x%x\n",c, cs);
1410     if (!cs)
1411     {
1412         dbgprintf("Win32 Warning: Leaving uninitialized Critical Section %p!!\n", c);
1413         return;
1414     }
1415     if (cs->locked)
1416     {
1417         cs->locked=0;
1418         pthread_mutex_unlock(&(cs->mutex));
1419     }
1420     else
1421         dbgprintf("Win32 Warning: Unlocking unlocked Critical Section %p!!\n", c);
1422     return;
1423 }
1424
1425 static void expfree(void* mem); /* forward declaration */
1426
1427 static void WINAPI expDeleteCriticalSection(CRITICAL_SECTION *c)
1428 {
1429 #ifdef CRITSECS_NEWTYPE
1430     struct CRITSECT* cs = critsecs_get_unix(c);
1431 #else
1432     struct CRITSECT* cs= (*(struct CRITSECT**)c);
1433 #endif
1434     //    struct CRITSECT* cs=(struct CRITSECT*)c;
1435     dbgprintf("DeleteCriticalSection(0x%x)\n",c);
1436
1437     if (!cs)
1438     {
1439         dbgprintf("Win32 Warning: Deleting uninitialized Critical Section %p!!\n", c);
1440         return;
1441     }
1442     
1443     if (cs->locked)
1444     {
1445         dbgprintf("Win32 Warning: Deleting unlocked Critical Section %p!!\n", c);
1446         pthread_mutex_unlock(&(cs->mutex));
1447     }
1448
1449 #ifndef GARBAGE
1450     pthread_mutex_destroy(&(cs->mutex));
1451     // released by GarbageCollector in my_relase otherwise
1452 #endif
1453     my_release(cs);
1454 #ifdef CRITSECS_NEWTYPE
1455     {
1456         int i = critsecs_get_pos(c);
1457
1458         if (i < 0)
1459         {
1460             printf("DeleteCriticalSection(%p) error (critsec not found)\n", c);
1461             return;
1462         }
1463
1464         critsecs_list[i].cs_win = NULL;
1465         expfree(critsecs_list[i].cs_unix);
1466         critsecs_list[i].cs_unix = NULL;
1467         dbgprintf("DeleteCriticalSection -> itemno=%d\n", i);
1468     }
1469 #endif
1470     return;
1471 }
1472 static int WINAPI expGetCurrentThreadId()
1473 {
1474     dbgprintf("GetCurrentThreadId() => %d\n", pthread_self());
1475     return pthread_self();
1476 }
1477 static int WINAPI expGetCurrentProcess()
1478 {
1479     dbgprintf("GetCurrentProcess() => %d\n", getpid());
1480     return getpid();
1481 }
1482
1483 #ifdef QTX
1484 // this version is required for Quicktime codecs (.qtx/.qts) to work.
1485 // (they assume some pointers at FS: segment)
1486
1487 extern void* fs_seg;
1488
1489 //static int tls_count;
1490 static int tls_use_map[64];
1491 static int WINAPI expTlsAlloc()
1492 {
1493     int i;
1494     for(i=0; i<64; i++)
1495         if(tls_use_map[i]==0)
1496         {
1497             tls_use_map[i]=1;
1498             dbgprintf("TlsAlloc() => %d\n",i);
1499             return i;
1500         }
1501     dbgprintf("TlsAlloc() => -1 (ERROR)\n");
1502     return -1;
1503 }
1504
1505 //static int WINAPI expTlsSetValue(DWORD index, void* value)
1506 static int WINAPI expTlsSetValue(int index, void* value)
1507 {
1508     dbgprintf("TlsSetValue(%d,0x%x) => 1\n",index,value);
1509 //    if((index<0) || (index>64))
1510     if((index>=64))
1511         return 0;
1512     *(void**)((char*)fs_seg+0x88+4*index) = value;
1513     return 1;
1514 }
1515
1516 static void* WINAPI expTlsGetValue(DWORD index)
1517 {
1518     dbgprintf("TlsGetValue(%d)\n",index);
1519 //    if((index<0) || (index>64))
1520     if((index>=64)) return NULL;
1521     return *(void**)((char*)fs_seg+0x88+4*index);
1522 }
1523
1524 static int WINAPI expTlsFree(int idx)
1525 {
1526     int index = (int) idx;
1527     dbgprintf("TlsFree(%d)\n",index);
1528     if((index<0) || (index>64))
1529         return 0;
1530     tls_use_map[index]=0;
1531     return 1;
1532 }
1533
1534 #else
1535 struct tls_s {
1536     void* value;
1537     int used;
1538     struct tls_s* prev;
1539     struct tls_s* next;
1540 };
1541
1542 static void* WINAPI expTlsAlloc()
1543 {
1544     if (g_tls == NULL)
1545     {
1546         g_tls=my_mreq(sizeof(tls_t), 0);
1547         g_tls->next=g_tls->prev=NULL;
1548     }
1549     else
1550     {
1551         g_tls->next=my_mreq(sizeof(tls_t), 0);
1552         g_tls->next->prev=g_tls;
1553         g_tls->next->next=NULL;
1554         g_tls=g_tls->next;
1555     }
1556     dbgprintf("TlsAlloc() => 0x%x\n", g_tls);
1557     if (g_tls)
1558         g_tls->value=0; /* XXX For Divx.dll */
1559     return g_tls;
1560 }
1561
1562 static int WINAPI expTlsSetValue(void* idx, void* value)
1563 {
1564     tls_t* index = (tls_t*) idx;
1565     int result;
1566     if(index==0)
1567         result=0;
1568     else
1569     {
1570         index->value=value;
1571         result=1;
1572     }
1573     dbgprintf("TlsSetValue(index 0x%x, value 0x%x) => %d \n", index, value, result );
1574     return result;
1575 }
1576 static void* WINAPI expTlsGetValue(void* idx)
1577 {
1578     tls_t* index = (tls_t*) idx;
1579     void* result;
1580     if(index==0)
1581         result=0;
1582     else
1583         result=index->value;
1584     dbgprintf("TlsGetValue(index 0x%x) => 0x%x\n", index, result);
1585     return result;
1586 }
1587 static int WINAPI expTlsFree(void* idx)
1588 {
1589     tls_t* index = (tls_t*) idx;
1590     int result;
1591     if(index==0)
1592         result=0;
1593     else
1594     {
1595         if(index->next)
1596             index->next->prev=index->prev;
1597         if(index->prev)
1598             index->prev->next=index->next;
1599         if (g_tls == index)
1600             g_tls = index->prev;
1601         my_release((void*)index);
1602         result=1;
1603     }
1604     dbgprintf("TlsFree(index 0x%x) => %d\n", index, result);
1605     return result;
1606 }
1607 #endif
1608
1609 static void* WINAPI expLocalAlloc(int flags, int size)
1610 {
1611     void* z = my_mreq(size, (flags & GMEM_ZEROINIT));
1612     if (z == 0)
1613         printf("LocalAlloc() failed\n");
1614     dbgprintf("LocalAlloc(%d, flags 0x%x) => 0x%x\n", size, flags, z);
1615     return z;
1616 }
1617
1618 static void* WINAPI expLocalReAlloc(int handle,int size, int flags)
1619 {
1620     void *newpointer;
1621     int oldsize;
1622
1623     newpointer=NULL;
1624     if (flags & LMEM_MODIFY) {
1625         dbgprintf("LocalReAlloc MODIFY\n");
1626         return (void *)handle;
1627     }
1628     oldsize = my_size((void *)handle);
1629     newpointer = my_realloc((void *)handle,size);
1630     dbgprintf("LocalReAlloc(%x %d(old %d), flags 0x%x) => 0x%x\n", handle,size,oldsize, flags,newpointer);
1631
1632     return newpointer;
1633 }
1634
1635 static void* WINAPI expLocalLock(void* z)
1636 {
1637     dbgprintf("LocalLock(0x%x) => 0x%x\n", z, z);
1638     return z;
1639 }
1640
1641 static void* WINAPI expGlobalAlloc(int flags, int size)
1642 {
1643     void* z;
1644     dbgprintf("GlobalAlloc(%d, flags 0x%X)\n", size, flags);
1645
1646     z=my_mreq(size, (flags & GMEM_ZEROINIT));
1647     //z=calloc(size, 1);
1648     //z=malloc(size);
1649     if(z==0)
1650         printf("GlobalAlloc() failed\n");
1651     dbgprintf("GlobalAlloc(%d, flags 0x%x) => 0x%x\n", size, flags, z);
1652     return z;
1653 }
1654 static void* WINAPI expGlobalLock(void* z)
1655 {
1656     dbgprintf("GlobalLock(0x%x) => 0x%x\n", z, z);
1657     return z;
1658 }
1659 // pvmjpg20 - but doesn't work anyway
1660 static int WINAPI expGlobalSize(void* amem)
1661 {
1662     int size = 100000;
1663 #ifdef GARBAGE
1664     alloc_header* header = last_alloc;
1665     alloc_header* mem = (alloc_header*) amem - 1;
1666     if (amem == 0)
1667         return 0;
1668     pthread_mutex_lock(&memmut);
1669     while (header)
1670     {
1671         if (header->deadbeef != 0xdeadbeef)
1672         {
1673             dbgprintf("FATAL found corrupted memory! %p  0x%lx  (%d)\n", header, header->deadbeef, alccnt);
1674             break;
1675         }
1676
1677         if (header == mem)
1678         {
1679             size = header->size;
1680             break;
1681         }
1682
1683         header = header->prev;
1684     }
1685     pthread_mutex_unlock(&memmut);
1686 #endif
1687
1688     dbgprintf("GlobalSize(0x%x)\n", amem);
1689     return size;
1690 }
1691
1692 static int WINAPI expLoadIconA( long hinstance, char *name )
1693 {
1694  dbgprintf("LoadIconA( %ld, 0x%x ) => 1\n",hinstance,name);
1695  return 1;
1696 }
1697
1698 static int WINAPI expLoadStringA(long instance, long  id, void* buf, long size)
1699 {
1700     int result=LoadStringA(instance, id, buf, size);
1701     //    if(buf)
1702     dbgprintf("LoadStringA(instance 0x%x, id 0x%x, buffer 0x%x, size %d) => %d ( %s )\n",
1703               instance, id, buf, size, result, buf);
1704     //    else
1705     //    dbgprintf("LoadStringA(instance 0x%x, id 0x%x, buffer 0x%x, size %d) => %d\n",
1706     //  instance, id, buf, size, result);
1707     return result;
1708 }
1709
1710 static long WINAPI expMultiByteToWideChar(long v1, long v2, char* s1, long siz1, short* s2, int siz2)
1711 {
1712 #warning FIXME
1713     int i;
1714     int result;
1715     if(s2==0)
1716         result=1;
1717     else
1718     {
1719         if(siz1>siz2/2)siz1=siz2/2;
1720         for(i=1; i<=siz1; i++)
1721         {
1722             *s2=*s1;
1723             if(!*s1)break;
1724             s2++;
1725             s1++;
1726         }
1727         result=i;
1728     }
1729     if(s1)
1730         dbgprintf("MultiByteToWideChar(codepage %d, flags 0x%x, string 0x%x='%s',"
1731                   "size %d, dest buffer 0x%x, dest size %d) => %d\n",
1732                   v1, v2, s1, s1, siz1, s2, siz2, result);
1733     else
1734         dbgprintf("MultiByteToWideChar(codepage %d, flags 0x%x, string NULL,"
1735                   "size %d, dest buffer 0x%x, dest size %d) =>\n",
1736                   v1, v2, siz1, s2, siz2, result);
1737     return result;
1738 }
1739 static void wch_print(const short* str)
1740 {
1741     dbgprintf("  src: ");
1742     while(*str)dbgprintf("%c", *str++);
1743     dbgprintf("\n");
1744 }
1745 static long WINAPI expWideCharToMultiByte(long v1, long v2, short* s1, long siz1,
1746                                           char* s2, int siz2, char* c3, int* siz3)
1747 {
1748     int result;
1749     dbgprintf("WideCharToMultiByte(codepage %d, flags 0x%x, src 0x%x, src size %d, "
1750               "dest 0x%x, dest size %d, defch 0x%x, used_defch 0x%x)", v1, v2, s1, siz1, s2, siz2, c3, siz3);
1751     result=WideCharToMultiByte(v1, v2, s1, siz1, s2, siz2, c3, siz3);
1752     dbgprintf("=> %d\n", result);
1753     //if(s1)wch_print(s1);
1754     if(s2)dbgprintf("  dest: %s\n", s2);
1755     return result;
1756 }
1757 static long WINAPI expGetVersionExA(OSVERSIONINFOA* c)
1758 {
1759     dbgprintf("GetVersionExA(0x%x) => 1\n");
1760     c->dwOSVersionInfoSize=sizeof(*c);
1761     c->dwMajorVersion=4;
1762     c->dwMinorVersion=0;
1763     c->dwBuildNumber=0x4000457;
1764 #if 1
1765     // leave it here for testing win9x-only codecs
1766     c->dwPlatformId=VER_PLATFORM_WIN32_WINDOWS;
1767     strcpy(c->szCSDVersion, " B");
1768 #else
1769     c->dwPlatformId=VER_PLATFORM_WIN32_NT; // let's not make DLL assume that it can read CR* registers
1770     strcpy(c->szCSDVersion, "Service Pack 3");
1771 #endif
1772     dbgprintf("  Major version: 4\n  Minor version: 0\n  Build number: 0x4000457\n"
1773               "  Platform Id: VER_PLATFORM_WIN32_NT\n Version string: 'Service Pack 3'\n");
1774     return 1;
1775 }
1776 static HANDLE WINAPI expCreateSemaphoreA(char* v1, long init_count,
1777                                          long max_count, char* name)
1778 {
1779     pthread_mutex_t *pm;
1780     pthread_cond_t  *pc;
1781     mutex_list* pp;
1782     /*
1783      printf("CreateSemaphoreA(%p = %s)\n", name, (name ? name : "<null>"));
1784      pp=mlist;
1785      while(pp)
1786      {
1787      printf("%p => ", pp);
1788      pp=pp->prev;
1789      }
1790      printf("0\n");
1791      */
1792     if(mlist!=NULL)
1793     {
1794         mutex_list* pp=mlist;
1795         if(name!=NULL)
1796             do
1797         {
1798             if((strcmp(pp->name, name)==0) && (pp->type==1))
1799             {
1800                 dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0x%x='%s') => 0x%x\n",
1801                           v1, init_count, max_count, name, name, mlist);
1802                 return (HANDLE)mlist;
1803             }
1804         }while((pp=pp->prev) != NULL);
1805     }
1806     pm=mreq_private(sizeof(pthread_mutex_t), 0, AREATYPE_MUTEX);
1807     pthread_mutex_init(pm, NULL);
1808     pc=mreq_private(sizeof(pthread_cond_t), 0, AREATYPE_COND);
1809     pthread_cond_init(pc, NULL);
1810     if(mlist==NULL)
1811     {
1812         mlist=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
1813         mlist->next=mlist->prev=NULL;
1814     }
1815     else
1816     {
1817         mlist->next=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT);
1818         mlist->next->prev=mlist;
1819         mlist->next->next=NULL;
1820         mlist=mlist->next;
1821         //      printf("new semaphore %p\n", mlist);
1822     }
1823     mlist->type=1; /* Type Semaphore */
1824     mlist->pm=pm;
1825     mlist->pc=pc;
1826     mlist->state=0;
1827     mlist->reset=0;
1828     mlist->semaphore=init_count;
1829     if(name!=NULL)
1830         strncpy(mlist->name, name, 64);
1831     else
1832         mlist->name[0]=0;
1833     if(pm==NULL)
1834         dbgprintf("ERROR::: CreateSemaphoreA failure\n");
1835     if(name)
1836         dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0x%x='%s') => 0x%x\n",
1837                   v1, init_count, max_count, name, name, mlist);
1838     else
1839         dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0) => 0x%x\n",
1840                   v1, init_count, max_count, mlist);
1841     return (HANDLE)mlist;
1842 }
1843
1844 static long WINAPI expReleaseSemaphore(long hsem, long increment, long* prev_count)
1845 {
1846     // The state of a semaphore object is signaled when its count
1847     // is greater than zero and nonsignaled when its count is equal to zero
1848     // Each time a waiting thread is released because of the semaphore's signaled
1849     // state, the count of the semaphore is decreased by one.
1850     mutex_list *ml = (mutex_list *)hsem;
1851
1852     pthread_mutex_lock(ml->pm);
1853     if (prev_count != 0) *prev_count = ml->semaphore;
1854     if (ml->semaphore == 0) pthread_cond_signal(ml->pc);
1855     ml->semaphore += increment;
1856     pthread_mutex_unlock(ml->pm);
1857     dbgprintf("ReleaseSemaphore(semaphore 0x%x, increment %d, prev_count 0x%x) => 1\n",
1858               hsem, increment, prev_count);
1859     return 1;
1860 }
1861
1862
1863 static long WINAPI expRegOpenKeyExA(long key, const char* subkey, long reserved, long access, int* newkey)
1864 {
1865     long result=RegOpenKeyExA(key, subkey, reserved, access, newkey);
1866     dbgprintf("RegOpenKeyExA(key 0x%x, subkey %s, reserved %d, access 0x%x, pnewkey 0x%x) => %d\n",
1867               key, subkey, reserved, access, newkey, result);
1868     if(newkey)dbgprintf("  New key: 0x%x\n", *newkey);
1869     return result;
1870 }
1871 static long WINAPI expRegCloseKey(long key)
1872 {
1873     long result=RegCloseKey(key);
1874     dbgprintf("RegCloseKey(0x%x) => %d\n", key, result);
1875     return result;
1876 }
1877 static long WINAPI expRegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count)
1878 {
1879     long result=RegQueryValueExA(key, value, reserved, type, data, count);
1880     dbgprintf("RegQueryValueExA(key 0x%x, value %s, reserved 0x%x, data 0x%x, count 0x%x)"
1881               " => 0x%x\n", key, value, reserved, data, count, result);
1882     if(data && count)dbgprintf("  read %d bytes: '%s'\n", *count, data);
1883     return result;
1884 }
1885
1886 //from wine source dlls/advapi32/registry.c
1887 static long WINAPI expRegCreateKeyA(long hkey, const char* name, int *retkey)
1888 {
1889     dbgprintf("RegCreateKeyA(key 0x%x, name 0x%x='%s',newkey=0x%x)\n",hkey,name,retkey);
1890     return RegCreateKeyExA( hkey, name, 0, NULL,REG_OPTION_NON_VOLATILE,
1891                             KEY_ALL_ACCESS , NULL, retkey, NULL );
1892 }
1893
1894 static long WINAPI expRegCreateKeyExA(long key, const char* name, long reserved,
1895                                       void* classs, long options, long security,
1896                                       void* sec_attr, int* newkey, int* status)
1897 {
1898     long result=RegCreateKeyExA(key, name, reserved, classs, options, security, sec_attr, newkey, status);
1899     dbgprintf("RegCreateKeyExA(key 0x%x, name 0x%x='%s', reserved=0x%x,"
1900               " 0x%x, 0x%x, 0x%x, newkey=0x%x, status=0x%x) => %d\n",
1901               key, name, name, reserved, classs, options, security, sec_attr, newkey, status, result);
1902     if(!result && newkey) dbgprintf("  New key: 0x%x\n", *newkey);
1903     if(!result && status) dbgprintf("  New key status: 0x%x\n", *status);
1904     return result;
1905 }
1906 static long WINAPI expRegSetValueExA(long key, const char* name, long v1, long v2, void* data, long size)
1907 {
1908     long result=RegSetValueExA(key, name, v1, v2, data, size);
1909     dbgprintf("RegSetValueExA(key 0x%x, name '%s', 0x%x, 0x%x, data 0x%x -> 0x%x '%s', size=%d) => %d",
1910               key, name, v1, v2, data, *(int*)data, data, size, result);
1911     return result;
1912 }
1913
1914 static long WINAPI expRegOpenKeyA (long hKey, LPCSTR lpSubKey, int* phkResult)
1915 {
1916     long result=RegOpenKeyExA(hKey, lpSubKey, 0, 0, phkResult);
1917     dbgprintf("RegOpenKeyExA(key 0x%x, subkey '%s', 0x%x) => %d\n",
1918               hKey, lpSubKey, phkResult, result);
1919     if(!result && phkResult) dbgprintf("  New key: 0x%x\n", *phkResult);
1920     return result;
1921 }
1922
1923 static DWORD WINAPI expRegEnumValueA(HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1924                                      LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count)
1925 {
1926     return RegEnumValueA(hkey, index, value, val_count,
1927                          reserved, type, data, count);
1928 }
1929
1930 static DWORD WINAPI expRegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName,
1931                                      LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass,
1932                                      LPFILETIME lpftLastWriteTime)
1933 {
1934     return RegEnumKeyExA(hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass,
1935                          lpcbClass, lpftLastWriteTime);
1936 }
1937
1938 static long WINAPI expQueryPerformanceCounter(long long* z)
1939 {
1940     longcount(z);
1941     dbgprintf("QueryPerformanceCounter(0x%x) => 1 ( %Ld )\n", z, *z);
1942     return 1;
1943 }
1944
1945 /*
1946  * dummy function RegQueryInfoKeyA(), required by vss codecs
1947  */
1948 static DWORD WINAPI expRegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1949                                          LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1950                                          LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1951                                          LPDWORD security, FILETIME *modif )
1952 {
1953     return ERROR_SUCCESS;
1954 }
1955
1956 /*
1957  * return CPU clock (in kHz), using linux's /proc filesystem (/proc/cpuinfo)
1958  */
1959 static double linux_cpuinfo_freq()
1960 {
1961     double freq=-1;
1962     FILE *f;
1963     char line[200];
1964     char *s,*value;
1965
1966     f = fopen ("/proc/cpuinfo", "r");
1967     if (f != NULL) {
1968         while (fgets(line,sizeof(line),f)!=NULL) {
1969             /* NOTE: the ':' is the only character we can rely on */
1970             if (!(value = strchr(line,':')))
1971                 continue;
1972             /* terminate the valuename */
1973             *value++ = '\0';
1974             /* skip any leading spaces */
1975             while (*value==' ') value++;
1976             if ((s=strchr(value,'\n')))
1977                 *s='\0';
1978
1979             if (!strncasecmp(line, "cpu MHz",strlen("cpu MHz"))
1980                 && sscanf(value, "%lf", &freq) == 1) {
1981                 freq*=1000;
1982                 break;
1983             }
1984         }
1985         fclose(f);
1986     }
1987     return freq;
1988 }
1989
1990
1991 static double solaris_kstat_freq()
1992 {
1993 #if     defined(HAVE_LIBKSTAT) && defined(KSTAT_DATA_INT32)
1994     /*
1995      * try to extract the CPU speed from the solaris kernel's kstat data
1996      */
1997     kstat_ctl_t   *kc;
1998     kstat_t       *ksp;
1999     kstat_named_t *kdata;
2000     int            mhz = 0;
2001
2002     kc = kstat_open();
2003     if (kc != NULL)
2004     {
2005         ksp = kstat_lookup(kc, "cpu_info", 0, "cpu_info0");
2006
2007         /* kstat found and name/value pairs? */
2008         if (ksp != NULL && ksp->ks_type == KSTAT_TYPE_NAMED)
2009         {
2010             /* read the kstat data from the kernel */
2011             if (kstat_read(kc, ksp, NULL) != -1)
2012             {
2013                 /*
2014                  * lookup desired "clock_MHz" entry, check the expected
2015                  * data type
2016                  */
2017                 kdata = (kstat_named_t *)kstat_data_lookup(ksp, "clock_MHz");
2018                 if (kdata != NULL && kdata->data_type == KSTAT_DATA_INT32)
2019                     mhz = kdata->value.i32;
2020             }
2021         }
2022         kstat_close(kc);
2023     }
2024
2025     if (mhz > 0)
2026         return mhz * 1000.;
2027 #endif  /* HAVE_LIBKSTAT */
2028     return -1;          // kstat stuff is not available, CPU freq is unknown
2029 }
2030
2031 /*
2032  * Measure CPU freq using the pentium's time stamp counter register (TSC)
2033  */
2034 static double tsc_freq()
2035 {
2036     static double ofreq=0.0;
2037     int i;
2038     int x,y;
2039     i=time(NULL);
2040     if (ofreq != 0.0) return ofreq;
2041     while(i==time(NULL));
2042     x=localcount();
2043     i++;
2044     while(i==time(NULL));
2045     y=localcount();
2046     ofreq = (double)(y-x)/1000.;
2047     return ofreq;
2048 }
2049
2050 static double CPU_Freq()
2051 {
2052     double freq;
2053
2054     if ((freq = linux_cpuinfo_freq()) > 0)
2055         return freq;
2056
2057     if ((freq = solaris_kstat_freq()) > 0)
2058         return freq;
2059
2060     return tsc_freq();
2061 }
2062
2063 static long WINAPI expQueryPerformanceFrequency(long long* z)
2064 {
2065     *z=(long long)CPU_Freq();
2066     dbgprintf("QueryPerformanceFrequency(0x%x) => 1 ( %Ld )\n", z, *z);
2067     return 1;
2068 }
2069 static long WINAPI exptimeGetTime()
2070 {
2071     struct timeval t;
2072     long result;
2073     gettimeofday(&t, 0);
2074     result=1000*t.tv_sec+t.tv_usec/1000;
2075     dbgprintf("timeGetTime() => %d\n", result);
2076     return result;
2077 }
2078 static void* WINAPI expLocalHandle(void* v)
2079 {
2080     dbgprintf("LocalHandle(0x%x) => 0x%x\n", v, v);
2081     return v;
2082 }
2083
2084 static void* WINAPI expGlobalHandle(void* v)
2085 {
2086     dbgprintf("GlobalHandle(0x%x) => 0x%x\n", v, v);
2087     return v;
2088 }
2089 static int WINAPI expGlobalUnlock(void* v)
2090 {
2091     dbgprintf("GlobalUnlock(0x%x) => 1\n", v);
2092     return 1;
2093 }
2094 static void* WINAPI expGlobalFree(void* v)
2095 {
2096     dbgprintf("GlobalFree(0x%x) => 0\n", v);
2097     my_release(v);
2098     //free(v);
2099     return 0;
2100 }
2101
2102 static void* WINAPI expGlobalReAlloc(void* v, int size, int flags)
2103 {
2104     void* result=my_realloc(v, size);
2105     //void* result=realloc(v, size);
2106     dbgprintf("GlobalReAlloc(0x%x, size %d, flags 0x%x) => 0x%x\n", v,size,flags,result);
2107     return result;
2108 }
2109
2110 static int WINAPI expLocalUnlock(void* v)
2111 {
2112     dbgprintf("LocalUnlock(0x%x) => 1\n", v);
2113     return 1;
2114 }
2115 //
2116 static void* WINAPI expLocalFree(void* v)
2117 {
2118     dbgprintf("LocalFree(0x%x) => 0\n", v);
2119     my_release(v);
2120     return 0;
2121 }
2122 static HRSRC WINAPI expFindResourceA(HMODULE module, char* name, char* type)
2123 {
2124     HRSRC result;
2125
2126     result=FindResourceA(module, name, type);
2127     dbgprintf("FindResourceA(module 0x%x, name 0x%x(%s), type 0x%x(%s)) => 0x%x\n",
2128         module, name, HIWORD(name) ? name : "UNICODE", type, HIWORD(type) ? type : "UNICODE", result);
2129     return result;
2130 }
2131
2132 extern HRSRC WINAPI LoadResource(HMODULE, HRSRC);
2133 static HGLOBAL WINAPI expLoadResource(HMODULE module, HRSRC res)
2134 {
2135     HGLOBAL result=LoadResource(module, res);
2136     dbgprintf("LoadResource(module 0x%x, resource 0x%x) => 0x%x\n", module, res, result);
2137     return result;
2138 }
2139 static void* WINAPI expLockResource(long res)
2140 {
2141     void* result=LockResource(res);
2142     dbgprintf("LockResource(0x%x) => 0x%x\n", res, result);
2143     return result;
2144 }
2145 static int WINAPI expFreeResource(long res)
2146 {
2147     int result=FreeResource(res);
2148     dbgprintf("FreeResource(0x%x) => %d\n", res, result);
2149     return result;
2150 }
2151 //bool fun(HANDLE)
2152 //!0 on success
2153 static int WINAPI expCloseHandle(long v1)
2154 {
2155     dbgprintf("CloseHandle(0x%x) => 1\n", v1);
2156     /* do not close stdin,stdout and stderr */
2157     if (v1 > 2)
2158         if (!close(v1))
2159             return 0;
2160     return 1;
2161 }
2162
2163 static const char* WINAPI expGetCommandLineA()
2164 {
2165     dbgprintf("GetCommandLineA() => \"c:\\aviplay.exe\"\n");
2166     return "c:\\aviplay.exe";
2167 }
2168 static short envs[]={'p', 'a', 't', 'h', ' ', 'c', ':', '\\', 0, 0};
2169 static LPWSTR WINAPI expGetEnvironmentStringsW()
2170 {
2171     dbgprintf("GetEnvironmentStringsW() => 0\n", envs);
2172     return 0;
2173 }
2174 static void * WINAPI expRtlZeroMemory(void *p, size_t len)
2175 {
2176     void* result=memset(p,0,len);
2177     dbgprintf("RtlZeroMemory(0x%x, len %d) => 0x%x\n",p,len,result);
2178     return result;
2179 }
2180 static void * WINAPI expRtlMoveMemory(void *dst, void *src, size_t len)
2181 {
2182     void* result=memmove(dst,src,len);
2183     dbgprintf("RtlMoveMemory (dest 0x%x, src 0x%x, len %d) => 0x%x\n",dst,src,len,result);
2184     return result;
2185 }
2186
2187 static void * WINAPI expRtlFillMemory(void *p, int ch, size_t len)
2188 {
2189     void* result=memset(p,ch,len);
2190     dbgprintf("RtlFillMemory(0x%x, char 0x%x, len %d) => 0x%x\n",p,ch,len,result);
2191     return result;
2192 }
2193 static int WINAPI expFreeEnvironmentStringsW(short* strings)
2194 {
2195     dbgprintf("FreeEnvironmentStringsW(0x%x) => 1\n", strings);
2196     return 1;
2197 }
2198 static int WINAPI expFreeEnvironmentStringsA(char* strings)
2199 {
2200     dbgprintf("FreeEnvironmentStringsA(0x%x) => 1\n", strings);
2201     return 1;
2202 }
2203
2204 static const char ch_envs[]=
2205 "__MSVCRT_HEAP_SELECT=__GLOBAL_HEAP_SELECTED,1\r\n"
2206 "PATH=C:\\;C:\\windows\\;C:\\windows\\system\r\n";
2207 static LPCSTR WINAPI expGetEnvironmentStrings()
2208 {
2209     dbgprintf("GetEnvironmentStrings() => 0x%x\n", ch_envs);
2210     return (LPCSTR)ch_envs;
2211     // dbgprintf("GetEnvironmentStrings() => 0\n");
2212     // return 0;
2213 }
2214
2215 static int WINAPI expGetStartupInfoA(STARTUPINFOA *s)
2216 {
2217     int i;
2218     dbgprintf("GetStartupInfoA(0x%x) => 1\n");
2219     memset(s, 0, sizeof(*s));
2220     s->cb=sizeof(*s);
2221     // s->lpReserved="Reserved";
2222     // s->lpDesktop="Desktop";
2223     // s->lpTitle="Title";
2224     // s->dwX=s->dwY=0;
2225     // s->dwXSize=s->dwYSize=200;
2226     s->dwFlags=s->wShowWindow=1;
2227     // s->hStdInput=s->hStdOutput=s->hStdError=0x1234;
2228     dbgprintf("  cb=%d\n", s->cb);
2229     dbgprintf("  lpReserved='%s'\n", s->lpReserved);
2230     dbgprintf("  lpDesktop='%s'\n", s->lpDesktop);
2231     dbgprintf("  lpTitle='%s'\n", s->lpTitle);
2232     dbgprintf("  dwX=%d dwY=%d dwXSize=%d dwYSize=%d\n",
2233               s->dwX, s->dwY, s->dwXSize, s->dwYSize);
2234     dbgprintf("  dwXCountChars=%d dwYCountChars=%d dwFillAttribute=%d\n",
2235               s->dwXCountChars, s->dwYCountChars, s->dwFillAttribute);
2236     dbgprintf("  dwFlags=0x%x wShowWindow=0x%x cbReserved2=0x%x\n",
2237               s->dwFlags, s->wShowWindow, s->cbReserved2);
2238     dbgprintf("  lpReserved2=0x%x hStdInput=0x%x hStdOutput=0x%x hStdError=0x%x\n",
2239               s->lpReserved2, s->hStdInput, s->hStdOutput, s->hStdError);
2240     return 1;
2241 }
2242
2243 static int WINAPI expGetStdHandle(int z)
2244 {
2245     dbgprintf("GetStdHandle(0x%x) => 0x%x\n", z+0x1234);
2246     return z+0x1234;
2247 }
2248
2249 #ifdef QTX
2250 #define FILE_HANDLE_quicktimeqts        ((HANDLE)0x444)
2251 #define FILE_HANDLE_quicktimeqtx        ((HANDLE)0x445)
2252 #endif
2253
2254 static int WINAPI expGetFileType(int handle)
2255 {
2256     dbgprintf("GetFileType(0x%x) => 0x3 = pipe\n", handle);
2257     return 0x3;
2258 }
2259 #ifdef QTX
2260 static int WINAPI expGetFileAttributesA(char *filename)
2261 {
2262     dbgprintf("GetFileAttributesA(%s) => FILE_ATTR_NORMAL\n", filename);
2263     if (strstr(filename, "QuickTime.qts"))
2264         return FILE_ATTRIBUTE_SYSTEM;
2265     return FILE_ATTRIBUTE_NORMAL;
2266 }
2267 #endif
2268 static int WINAPI expSetHandleCount(int count)
2269 {
2270     dbgprintf("SetHandleCount(0x%x) => 1\n", count);
2271     return 1;
2272 }
2273 static int WINAPI expGetACP(void)
2274 {
2275     dbgprintf("GetACP() => 0\n");
2276     return 0;
2277 }
2278 extern WINE_MODREF *MODULE32_LookupHMODULE(HMODULE m);
2279 static int WINAPI expGetModuleFileNameA(int module, char* s, int len)
2280 {
2281     WINE_MODREF *mr;
2282     int result;
2283     //printf("File name of module %X (%s) requested\n", module, s);
2284
2285     if (module == 0 && len >= 12)
2286     {
2287         /* return caller program name */
2288         strcpy(s, "aviplay.dll");
2289         result=1;
2290     }
2291     else if(s==0)
2292         result=0;
2293     else
2294         if(len<35)
2295             result=0;
2296         else
2297         {
2298             result=1;
2299             strcpy(s, "c:\\windows\\system\\");
2300             mr=MODULE32_LookupHMODULE(module);
2301             if(mr==0)//oops
2302                 strcat(s, "aviplay.dll");
2303             else
2304                 if(strrchr(mr->filename, '/')==NULL)
2305                     strcat(s, mr->filename);
2306                 else
2307                     strcat(s, strrchr(mr->filename, '/')+1);
2308         }
2309     if(!s)
2310         dbgprintf("GetModuleFileNameA(0x%x, 0x%x, %d) => %d\n",
2311                   module, s, len, result);
2312     else
2313         dbgprintf("GetModuleFileNameA(0x%x, 0x%x, %d) => %d ( '%s' )\n",
2314                   module, s, len, result, s);
2315     return result;
2316 }
2317
2318 static int WINAPI expSetUnhandledExceptionFilter(void* filter)
2319 {
2320     dbgprintf("SetUnhandledExceptionFilter(0x%x) => 1\n", filter);
2321     return 1;//unsupported and probably won't ever be supported
2322 }
2323
2324 static int WINAPI expLoadLibraryA(char* name)
2325 {
2326     int result = 0;
2327     char* lastbc;
2328     int i;
2329     if (!name)
2330         return -1;
2331     // we skip to the last backslash
2332     // this is effectively eliminating weird characters in
2333     // the text output windows
2334
2335     lastbc = strrchr(name, '\\');
2336     if (lastbc)
2337     {
2338         int i;
2339         lastbc++;
2340         for (i = 0; 1 ;i++)
2341         {
2342             name[i] = *lastbc++;
2343             if (!name[i])
2344                 break;
2345         }
2346     }
2347     if(strncmp(name, "c:\\windows\\", 11)==0) name += 11;
2348     if(strncmp(name, ".\\", 2)==0) name += 2;
2349
2350     dbgprintf("Entering LoadLibraryA(%s)\n", name);
2351
2352     // PIMJ and VIVO audio are loading  kernel32.dll
2353     if (strcasecmp(name, "kernel32.dll") == 0 || strcasecmp(name, "kernel32") == 0)
2354         return MODULE_HANDLE_kernel32;
2355 //      return ERROR_SUCCESS; /* yeah, we have also the kernel32 calls */
2356                               /* exported -> do not return failed! */
2357
2358     if (strcasecmp(name, "user32.dll") == 0 || strcasecmp(name, "user32") == 0)
2359 //      return MODULE_HANDLE_kernel32;
2360         return MODULE_HANDLE_user32;
2361
2362 #ifdef QTX
2363     if (strcasecmp(name, "wininet.dll") == 0 || strcasecmp(name, "wininet") == 0)
2364         return MODULE_HANDLE_wininet;
2365     if (strcasecmp(name, "ddraw.dll") == 0 || strcasecmp(name, "ddraw") == 0)
2366         return MODULE_HANDLE_ddraw;
2367     if (strcasecmp(name, "advapi32.dll") == 0 || strcasecmp(name, "advapi32") == 0)
2368         return MODULE_HANDLE_advapi32;
2369 #endif
2370
2371     if (strcasecmp(name, "comdlg32.dll") == 0 || strcasecmp(name, "comdlg32") == 0)
2372         return MODULE_HANDLE_comdlg32;
2373     if (strcasecmp(name, "msvcrt.dll") == 0 || strcasecmp(name, "msvcrt") == 0)
2374         return MODULE_HANDLE_msvcrt;
2375     if (strcasecmp(name, "ole32.dll") == 0 || strcasecmp(name, "ole32") == 0)
2376         return MODULE_HANDLE_ole32;
2377     if (strcasecmp(name, "winmm.dll") == 0 || strcasecmp(name, "winmm") == 0)
2378         return MODULE_HANDLE_winmm;
2379
2380     result=LoadLibraryA(name);
2381     dbgprintf("Returned LoadLibraryA(0x%x='%s'), def_path=%s => 0x%x\n", name, name, def_path, result);
2382
2383     return result;
2384 }
2385
2386 static int WINAPI expFreeLibrary(int module)
2387 {
2388 #ifdef QTX
2389     int result=0; /* FIXME:XXX: qtx svq3 frees up qt.qts */
2390 #else
2391     int result=FreeLibrary(module);
2392 #endif
2393     dbgprintf("FreeLibrary(0x%x) => %d\n", module, result);
2394     return result;
2395 }
2396
2397 static void* WINAPI expGetProcAddress(HMODULE mod, char* name)
2398 {
2399     void* result;
2400     switch(mod){
2401     case MODULE_HANDLE_kernel32:
2402         result=LookupExternalByName("kernel32.dll", name); break;
2403     case MODULE_HANDLE_user32:
2404         result=LookupExternalByName("user32.dll", name); break;
2405 #ifdef QTX
2406     case MODULE_HANDLE_wininet:
2407         result=LookupExternalByName("wininet.dll", name); break;
2408     case MODULE_HANDLE_ddraw:
2409         result=LookupExternalByName("ddraw.dll", name); break;
2410     case MODULE_HANDLE_advapi32:
2411         result=LookupExternalByName("advapi32.dll", name); break;
2412 #endif
2413     case MODULE_HANDLE_comdlg32:
2414         result=LookupExternalByName("comdlg32.dll", name); break;
2415     case MODULE_HANDLE_msvcrt:
2416         result=LookupExternalByName("msvcrt.dll", name); break;
2417     case MODULE_HANDLE_ole32:
2418         result=LookupExternalByName("ole32.dll", name); break;
2419     case MODULE_HANDLE_winmm:
2420         result=LookupExternalByName("winmm.dll", name); break;
2421     default:
2422         result=GetProcAddress(mod, name);
2423     }
2424     dbgprintf("GetProcAddress(0x%x, '%s') => 0x%x\n", mod, name, result);
2425     return result;
2426 }
2427
2428 static long WINAPI expCreateFileMappingA(int hFile, void* lpAttr,
2429                                          long flProtect, long dwMaxHigh,
2430                                          long dwMaxLow, const char* name)
2431 {
2432     long result=CreateFileMappingA(hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, name);
2433     if(!name)
2434         dbgprintf("CreateFileMappingA(file 0x%x, lpAttr 0x%x,"
2435                   "flProtect 0x%x, dwMaxHigh 0x%x, dwMaxLow 0x%x, name 0) => %d\n",
2436                   hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, result);
2437     else
2438         dbgprintf("CreateFileMappingA(file 0x%x, lpAttr 0x%x,"
2439                   "flProtect 0x%x, dwMaxHigh 0x%x, dwMaxLow 0x%x, name 0x%x='%s') => %d\n",
2440                   hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, name, name, result);
2441     return result;
2442 }
2443
2444 static long WINAPI expOpenFileMappingA(long hFile, long hz, const char* name)
2445 {
2446     long result=OpenFileMappingA(hFile, hz, name);
2447     if(!name)
2448         dbgprintf("OpenFileMappingA(0x%x, 0x%x, 0) => %d\n",
2449                   hFile, hz, result);
2450     else
2451         dbgprintf("OpenFileMappingA(0x%x, 0x%x, 0x%x='%s') => %d\n",
2452                   hFile, hz, name, name, result);
2453     return result;
2454 }
2455
2456 static void* WINAPI expMapViewOfFile(HANDLE file, DWORD mode, DWORD offHigh,
2457                                      DWORD offLow, DWORD size)
2458 {
2459     dbgprintf("MapViewOfFile(0x%x, 0x%x, 0x%x, 0x%x, size %d) => 0x%x\n",
2460               file,mode,offHigh,offLow,size,(char*)file+offLow);
2461     return (char*)file+offLow;
2462 }
2463
2464 static void* WINAPI expUnmapViewOfFile(void* view)
2465 {
2466     dbgprintf("UnmapViewOfFile(0x%x) => 0\n", view);
2467     return 0;
2468 }
2469
2470 static void* WINAPI expSleep(int time)
2471 {
2472 #if HAVE_NANOSLEEP
2473     /* solaris doesn't have thread safe usleep */
2474     struct timespec tsp;
2475     tsp.tv_sec  =  time / 1000000;
2476     tsp.tv_nsec = (time % 1000000) * 1000;
2477     nanosleep(&tsp, NULL);
2478 #else
2479     usleep(time);
2480 #endif
2481     dbgprintf("Sleep(%d) => 0\n", time);
2482     return 0;
2483 }
2484
2485 // why does IV32 codec want to call this? I don't know ...
2486 static int WINAPI expCreateCompatibleDC(int hdc)
2487 {
2488     int dc = 0;//0x81;
2489     //dbgprintf("CreateCompatibleDC(%d) => 0x81\n", hdc);
2490     dbgprintf("CreateCompatibleDC(%d) => %d\n", hdc, dc);
2491     return dc;
2492 }
2493
2494 static int WINAPI expGetDeviceCaps(int hdc, int unk)
2495 {
2496     dbgprintf("GetDeviceCaps(0x%x, %d) => 0\n", hdc, unk);
2497 #ifdef QTX
2498     #define BITSPIXEL 12
2499     #define PLANES    14
2500     if (unk == BITSPIXEL)
2501         return 24;
2502     if (unk == PLANES)
2503         return 1;
2504 #endif
2505     return 1;
2506 }
2507
2508 static WIN_BOOL WINAPI expDeleteDC(int hdc)
2509 {
2510     dbgprintf("DeleteDC(0x%x) => 0\n", hdc);
2511     if (hdc == 0x81)
2512         return 1;
2513     return 0;
2514 }
2515
2516 static WIN_BOOL WINAPI expDeleteObject(int hdc)
2517 {
2518     dbgprintf("DeleteObject(0x%x) => 1\n", hdc);
2519     /* FIXME - implement code here */
2520     return 1;
2521 }
2522
2523 /* btvvc32.drv wants this one */
2524 static void* WINAPI expGetWindowDC(int hdc)
2525 {
2526     dbgprintf("GetWindowDC(%d) => 0x0\n", hdc);
2527     return 0;
2528 }
2529
2530 #ifdef QTX
2531 static int WINAPI expGetWindowRect(HWND win, RECT *r)
2532 {
2533     dbgprintf("GetWindowRect(0x%x, 0x%x) => 1\n", win, r);
2534     /* (win == 0) => desktop */
2535     r->right = PSEUDO_SCREEN_WIDTH;
2536     r->left = 0;
2537     r->bottom = PSEUDO_SCREEN_HEIGHT;
2538     r->top = 0;
2539     return 1;
2540 }
2541
2542 static int WINAPI expMonitorFromWindow(HWND win, int flags)
2543 {
2544     dbgprintf("MonitorFromWindow(0x%x, 0x%x) => 0\n", win, flags);
2545     return 0;
2546 }
2547
2548 static int WINAPI expMonitorFromRect(RECT *r, int flags)
2549 {
2550     dbgprintf("MonitorFromRect(0x%x, 0x%x) => 0\n", r, flags);
2551     return 0;
2552 }
2553
2554 static int WINAPI expMonitorFromPoint(void *p, int flags)
2555 {
2556     dbgprintf("MonitorFromPoint(0x%x, 0x%x) => 0\n", p, flags);
2557     return 0;
2558 }
2559
2560 static int WINAPI expEnumDisplayMonitors(void *dc, RECT *r, 
2561     int WINAPI (*callback_proc)(), void *callback_param)
2562 {
2563     dbgprintf("EnumDisplayMonitors(0x%x, 0x%x, 0x%x, 0x%x) => ?\n",
2564         dc, r, callback_proc, callback_param);
2565     return callback_proc(0, dc, r, callback_param);
2566 }
2567
2568 #if 0
2569 typedef struct tagMONITORINFO {
2570     DWORD  cbSize; 
2571     RECT   rcMonitor; 
2572     RECT   rcWork; 
2573     DWORD  dwFlags; 
2574 } MONITORINFO, *LPMONITORINFO; 
2575 #endif
2576
2577 #define CCHDEVICENAME 8
2578 typedef struct tagMONITORINFOEX {  
2579     DWORD  cbSize; 
2580     RECT   rcMonitor; 
2581     RECT   rcWork; 
2582     DWORD  dwFlags; 
2583     TCHAR  szDevice[CCHDEVICENAME];
2584 } MONITORINFOEX, *LPMONITORINFOEX; 
2585
2586 static int WINAPI expGetMonitorInfoA(void *mon, LPMONITORINFO lpmi)
2587 {
2588     dbgprintf("GetMonitorInfoA(0x%x, 0x%x) => 1\n", mon, lpmi);
2589     
2590     lpmi->rcMonitor.right = lpmi->rcWork.right = PSEUDO_SCREEN_WIDTH;
2591     lpmi->rcMonitor.left = lpmi->rcWork.left = 0;
2592     lpmi->rcMonitor.bottom = lpmi->rcWork.bottom = PSEUDO_SCREEN_HEIGHT;
2593     lpmi->rcMonitor.top = lpmi->rcWork.top = 0;
2594
2595     lpmi->dwFlags = 1; /* primary monitor */
2596
2597     if (lpmi->cbSize == sizeof(MONITORINFOEX))
2598     {
2599         LPMONITORINFOEX lpmiex = (LPMONITORINFOEX)lpmi;
2600         dbgprintf("MONITORINFOEX!\n");
2601         strncpy(lpmiex->szDevice, "Monitor1", CCHDEVICENAME);
2602     }
2603     
2604     return 1;
2605 }
2606
2607 static int WINAPI expEnumDisplayDevicesA(const char *device, int devnum,
2608         void *dispdev, int flags)
2609 {
2610     dbgprintf("EnumDisplayDevicesA(0x%x = %s, %d, 0x%x, %x) => 1\n",
2611         device, device, devnum, dispdev, flags);
2612     return 1;
2613 }
2614
2615 static int WINAPI expIsWindowVisible(HWND win)
2616 {
2617     dbgprintf("IsWindowVisible(0x%x) => 1\n", win);
2618     return 1;
2619 }
2620
2621 static HWND WINAPI expGetActiveWindow(void)
2622 {
2623     dbgprintf("GetActiveWindow() => 0\n");
2624     return (HWND)0;
2625 }
2626
2627 static int WINAPI expGetClassNameA(HWND win, LPTSTR classname, int maxcount)
2628 {
2629     strncat(classname, "QuickTime", maxcount);
2630     dbgprintf("GetClassNameA(0x%x, 0x%x, %d) => %d\n",
2631         win, classname, maxcount, strlen(classname));
2632     return strlen(classname);
2633 }
2634
2635 #define LPWNDCLASS void *
2636 static int WINAPI expGetClassInfoA(HINSTANCE inst, LPCSTR classname, LPWNDCLASS wndclass)
2637 {
2638     dbgprintf("GetClassInfoA(0x%x, 0x%x = %s, 0x%x) => 1\n", inst,
2639         classname, classname, wndclass);
2640     return 1;
2641 }
2642
2643 static int WINAPI expGetWindowLongA(HWND win, int index)
2644 {
2645     dbgprintf("GetWindowLongA(0x%x, %d) => 0\n", win, index);
2646     return 1;
2647 }
2648
2649 static int WINAPI expGetObjectA(HGDIOBJ hobj, int objsize, LPVOID obj)
2650 {
2651     dbgprintf("GetObjectA(0x%x, %d, 0x%x) => %d\n", hobj, objsize, obj, objsize);
2652     return objsize;
2653 }
2654
2655 static int WINAPI expCreateRectRgn(int x, int y, int width, int height)
2656 {
2657     dbgprintf("CreateRectRgn(%d, %d, %d, %d) => 0\n", x, y, width, height);
2658     return 0;
2659 }
2660
2661 static int WINAPI expEnumWindows(int (*callback_func)(), void *callback_param)
2662 {
2663     int i, i2;
2664     dbgprintf("EnumWindows(0x%x, 0x%x) => 1\n", callback_func, callback_param);
2665     i = callback_func(0, callback_param);
2666     i2 = callback_func(1, callback_param);
2667     return i && i2;
2668 }
2669
2670 static int WINAPI expGetWindowThreadProcessId(HWND win, int *pid_data)
2671 {
2672     int tid = pthread_self();
2673     dbgprintf("GetWindowThreadProcessId(0x%x, 0x%x) => %d\n",
2674         win, pid_data, tid);
2675     if (pid_data)
2676         *(int*)pid_data = tid;
2677     return tid;
2678 }
2679
2680 //HWND      WINAPI CreateWindowExA(DWORD,LPCSTR,LPCSTR,DWORD,INT,INT,
2681 //                                INT,INT,HWND,HMENU,HINSTANCE,LPVOID);
2682
2683 static HWND WINAPI expCreateWindowExA(int exstyle, const char *classname,
2684     const char *winname, int style, int x, int y, int w, int h,
2685     HWND parent, HMENU menu, HINSTANCE inst, LPVOID param)
2686 {
2687     printf("CreateWindowEx() called\n");
2688     dbgprintf("CreateWindowEx(%d, 0x%x = %s, 0x%x = %s, %d, %d, %d, %d, %d, 0x%x, 0x%x, 0x%x, 0x%x) => 1\n",
2689         exstyle, classname, classname, winname, winname, style, x, y, w, h,
2690         parent, menu, inst, param);
2691     printf("CreateWindowEx() called okey\n");
2692     return 1;
2693 }
2694
2695 static int WINAPI expwaveOutGetNumDevs(void)
2696 {
2697     dbgprintf("waveOutGetNumDevs() => 0\n");
2698     return 0;
2699 }
2700 #endif
2701
2702 /*
2703  * Returns the number of milliseconds, modulo 2^32, since the start
2704  * of the wineserver.
2705  */
2706 static int WINAPI expGetTickCount(void)
2707 {
2708     static int tcstart = 0;
2709     struct timeval t;
2710     int tc;
2711     gettimeofday( &t, NULL );
2712     tc = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - tcstart;
2713     if (tcstart == 0)
2714     {
2715         tcstart = 0;
2716         tc = 0;
2717     }
2718     dbgprintf("GetTickCount() => %d\n", tc);
2719     return tc;
2720 }
2721
2722 static int WINAPI expCreateFontA(void)
2723 {
2724     dbgprintf("CreateFontA() => 0x0\n");
2725     return 1;
2726 }
2727
2728 /* tried to get pvmjpg work in a different way - no success */
2729 static int WINAPI expDrawTextA(int hDC, char* lpString, int nCount,
2730                                LPRECT lpRect, unsigned int uFormat)
2731 {
2732     dbgprintf("expDrawTextA(%p,...) => 8\n", hDC);
2733     return 8;
2734 }
2735
2736 static int WINAPI expGetPrivateProfileIntA(const char* appname,
2737                                            const char* keyname,
2738                                            int default_value,
2739                                            const char* filename)
2740 {
2741     int size=255;
2742     char buffer[256];
2743     char* fullname;
2744     int result;
2745
2746     buffer[255]=0;
2747     if(!(appname && keyname && filename) )
2748     {
2749         dbgprintf("GetPrivateProfileIntA('%s', '%s', %d, '%s') => %d\n", appname, keyname, default_value, filename, default_value );
2750         return default_value;
2751     }
2752     fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
2753     strcpy(fullname, "Software\\IniFileMapping\\");
2754     strcat(fullname, appname);
2755     strcat(fullname, "\\");
2756     strcat(fullname, keyname);
2757     strcat(fullname, "\\");
2758     strcat(fullname, filename);
2759     result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)buffer, &size);
2760     if((size>=0)&&(size<256))
2761         buffer[size]=0;
2762     //    printf("GetPrivateProfileIntA(%s, %s, %s) -> %s\n", appname, keyname, filename, buffer);
2763     free(fullname);
2764     if(result)
2765         result=default_value;
2766     else
2767         result=atoi(buffer);
2768     dbgprintf("GetPrivateProfileIntA('%s', '%s', %d, '%s') => %d\n", appname, keyname, default_value, filename, result);
2769     return result;
2770 }
2771 static int WINAPI expGetProfileIntA(const char* appname,
2772                                     const char* keyname,
2773                                     int default_value)
2774 {
2775     dbgprintf("GetProfileIntA -> ");
2776     return expGetPrivateProfileIntA(appname, keyname, default_value, "default");
2777 }
2778
2779 static int WINAPI expGetPrivateProfileStringA(const char* appname,
2780                                               const char* keyname,
2781                                               const char* def_val,
2782                                               char* dest, unsigned int len,
2783                                               const char* filename)
2784 {
2785     int result;
2786     int size;
2787     char* fullname;
2788     dbgprintf("GetPrivateProfileStringA('%s', '%s', def_val '%s', 0x%x, 0x%x, '%s')", appname, keyname, def_val, dest, len, filename );
2789     if(!(appname && keyname && filename) ) return 0;
2790     fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
2791     strcpy(fullname, "Software\\IniFileMapping\\");
2792     strcat(fullname, appname);
2793     strcat(fullname, "\\");
2794     strcat(fullname, keyname);
2795     strcat(fullname, "\\");
2796     strcat(fullname, filename);
2797     size=len;
2798     result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)dest, &size);
2799     free(fullname);
2800     if(result)
2801     {
2802         strncpy(dest, def_val, size);
2803         if (strlen(def_val)< size) size = strlen(def_val);
2804     }
2805     dbgprintf(" => %d ( '%s' )\n", size, dest);
2806     return size;
2807 }
2808 static int WINAPI expWritePrivateProfileStringA(const char* appname,
2809                                                 const char* keyname,
2810                                                 const char* string,
2811                                                 const char* filename)
2812 {
2813     int size=256;
2814     char* fullname;
2815     dbgprintf("WritePrivateProfileStringA('%s', '%s', '%s', '%s')", appname, keyname, string, filename );
2816     if(!(appname && keyname && filename) )
2817     {
2818         dbgprintf(" => -1\n");
2819         return -1;
2820     }
2821     fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename));
2822     strcpy(fullname, "Software\\IniFileMapping\\");
2823     strcat(fullname, appname);
2824     strcat(fullname, "\\");
2825     strcat(fullname, keyname);
2826     strcat(fullname, "\\");
2827     strcat(fullname, filename);
2828     RegSetValueExA(HKEY_LOCAL_MACHINE, fullname, 0, REG_SZ, (int*)string, strlen(string));
2829     //    printf("RegSetValueExA(%s,%d)\n", string, strlen(string));
2830     //    printf("WritePrivateProfileStringA(%s, %s, %s, %s)\n", appname, keyname, string, filename );
2831     free(fullname);
2832     dbgprintf(" => 0\n");
2833     return 0;
2834 }
2835
2836 unsigned int _GetPrivateProfileIntA(const char* appname, const char* keyname, INT default_value, const char* filename)
2837 {
2838     return expGetPrivateProfileIntA(appname, keyname, default_value, filename);
2839 }
2840 int _GetPrivateProfileStringA(const char* appname, const char* keyname,
2841                               const char* def_val, char* dest, unsigned int len, const char* filename)
2842 {
2843     return expGetPrivateProfileStringA(appname, keyname, def_val, dest, len, filename);
2844 }
2845 int _WritePrivateProfileStringA(const char* appname, const char* keyname,
2846                                 const char* string, const char* filename)
2847 {
2848     return expWritePrivateProfileStringA(appname, keyname, string, filename);
2849 }
2850
2851
2852
2853 static int WINAPI expDefDriverProc(int _private, int id, int msg, int arg1, int arg2)
2854 {
2855     dbgprintf("DefDriverProc(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) => 0\n", _private, id, msg, arg1, arg2);
2856     return 0;
2857 }
2858
2859 static int WINAPI expSizeofResource(int v1, int v2)
2860 {
2861     int result=SizeofResource(v1, v2);
2862     dbgprintf("SizeofResource(0x%x, 0x%x) => %d\n", v1, v2, result);
2863     return result;
2864 }
2865
2866 static int WINAPI expGetLastError()
2867 {
2868     int result=GetLastError();
2869     dbgprintf("GetLastError() => 0x%x\n", result);
2870     return result;
2871 }
2872
2873 static void WINAPI expSetLastError(int error)
2874 {
2875     dbgprintf("SetLastError(0x%x)\n", error);
2876     SetLastError(error);
2877 }
2878
2879 static int WINAPI expStringFromGUID2(GUID* guid, char* str, int cbMax)
2880 {
2881     int result=snprintf(str, cbMax, "%.8x-%.4x-%.4x-%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
2882                         guid->f1, guid->f2, guid->f3,
2883                         (unsigned char)guid->f4[0], (unsigned char)guid->f4[1],
2884                         (unsigned char)guid->f4[2], (unsigned char)guid->f4[3],
2885                         (unsigned char)guid->f4[4], (unsigned char)guid->f4[5],
2886                         (unsigned char)guid->f4[6], (unsigned char)guid->f4[7]);
2887     dbgprintf("StringFromGUID2(0x%x, 0x%x='%s', %d) => %d\n", guid, str, str, cbMax, result);
2888     return result;
2889 }
2890
2891
2892 static int WINAPI expGetFileVersionInfoSizeA(const char* name, int* lpHandle)
2893 {
2894     dbgprintf("GetFileVersionInfoSizeA(0x%x='%s', 0x%X) => 0\n", name, name, lpHandle);
2895     return 0;
2896 }
2897
2898 static int WINAPI expIsBadStringPtrW(const short* string, int nchars)
2899 {
2900     int result;
2901     if(string==0)result=1; else result=0;
2902     dbgprintf("IsBadStringPtrW(0x%x, %d) => %d", string, nchars, result);
2903     if(string)wch_print(string);
2904     return result;
2905 }
2906 static int WINAPI expIsBadStringPtrA(const char* string, int nchars)
2907 {
2908     return expIsBadStringPtrW((const short*)string, nchars);
2909 }
2910 static long WINAPI expInterlockedExchangeAdd( long* dest, long incr )
2911 {
2912     long ret;
2913     __asm__ __volatile__
2914         (
2915          "lock; xaddl %0,(%1)"
2916          : "=r" (ret)
2917          : "r" (dest), "0" (incr)
2918          : "memory"
2919         );
2920     return ret;
2921 }
2922
2923 static long WINAPI expInterlockedCompareExchange( unsigned long* dest, unsigned long exchange, unsigned long comperand)
2924 {
2925     unsigned long retval = *dest;
2926     if(*dest == comperand)
2927         *dest = exchange;
2928     return retval;
2929 }
2930
2931 static long WINAPI expInterlockedIncrement( long* dest )
2932 {
2933     long result=expInterlockedExchangeAdd( dest, 1 ) + 1;
2934     dbgprintf("InterlockedIncrement(0x%x => %d) => %d\n", dest, *dest, result);
2935     return result;
2936 }
2937 static long WINAPI expInterlockedDecrement( long* dest )
2938 {
2939     long result=expInterlockedExchangeAdd( dest, -1 ) - 1;
2940     dbgprintf("InterlockedDecrement(0x%x => %d) => %d\n", dest, *dest, result);
2941     return result;
2942 }
2943
2944 static void WINAPI expOutputDebugStringA( const char* string )
2945 {
2946     dbgprintf("OutputDebugStringA(0x%x='%s')\n", string);
2947     fprintf(stderr, "DEBUG: %s\n", string);
2948 }
2949
2950 static int WINAPI expGetDC(int hwnd)
2951 {
2952     dbgprintf("GetDC(0x%x) => 1\n", hwnd);
2953     return 1;
2954 }
2955
2956 static int WINAPI expReleaseDC(int hwnd, int hdc)
2957 {
2958     dbgprintf("ReleaseDC(0x%x, 0x%x) => 1\n", hwnd, hdc);
2959     return 1;
2960 }
2961
2962 static int WINAPI expGetDesktopWindow()
2963 {
2964     dbgprintf("GetDesktopWindow() => 0\n");
2965     return 0;
2966 }
2967
2968 static int cursor[100];
2969
2970 static int WINAPI expLoadCursorA(int handle,LPCSTR name)
2971 {
2972     dbgprintf("LoadCursorA(%d, 0x%x='%s') => 0x%x\n", handle, name, (int)&cursor[0]);
2973     return (int)&cursor[0];
2974 }
2975 static int WINAPI expSetCursor(void *cursor)
2976 {
2977     dbgprintf("SetCursor(0x%x) => 0x%x\n", cursor, cursor);
2978     return (int)cursor;
2979 }
2980 static int WINAPI expGetCursorPos(void *cursor)
2981 {
2982     dbgprintf("GetCursorPos(0x%x) => 0x%x\n", cursor, cursor);
2983     return 1;
2984 }
2985 #ifdef QTX
2986 static int show_cursor = 0;
2987 static int WINAPI expShowCursor(int show)
2988 {
2989     dbgprintf("ShowCursor(%d) => %d\n", show, show);
2990     if (show)
2991         show_cursor++;
2992     else
2993         show_cursor--;
2994     return show_cursor;
2995 }
2996 #endif
2997 static int WINAPI expRegisterWindowMessageA(char *message)
2998 {
2999     dbgprintf("RegisterWindowMessageA(%s)\n", message);
3000     return 1;
3001 }
3002 static int WINAPI expGetProcessVersion(int pid)
3003 {
3004     dbgprintf("GetProcessVersion(%d)\n", pid);
3005     return 1;
3006 }
3007 static int WINAPI expGetCurrentThread(void)
3008 {
3009 #warning FIXME!
3010     dbgprintf("GetCurrentThread() => %x\n", 0xcfcf9898);
3011     return 0xcfcf9898;
3012 }
3013 static int WINAPI expGetOEMCP(void)
3014 {
3015     dbgprintf("GetOEMCP()\n");
3016     return 1;
3017 }
3018 static int WINAPI expGetCPInfo(int cp,void *info)
3019 {
3020     dbgprintf("GetCPInfo()\n");
3021     return 0;
3022 }
3023 #ifdef QTX
3024 #define SM_CXSCREEN             0
3025 #define SM_CYSCREEN             1
3026 #define SM_XVIRTUALSCREEN       76
3027 #define SM_YVIRTUALSCREEN       77
3028 #define SM_CXVIRTUALSCREEN      78
3029 #define SM_CYVIRTUALSCREEN      79
3030 #define SM_CMONITORS            80
3031 #endif
3032 static int WINAPI expGetSystemMetrics(int index)
3033 {
3034     dbgprintf("GetSystemMetrics(%d)\n", index);
3035 #ifdef QTX
3036     switch(index)
3037     {
3038         case SM_XVIRTUALSCREEN:
3039         case SM_YVIRTUALSCREEN:
3040             return 0;
3041         case SM_CXSCREEN:
3042         case SM_CXVIRTUALSCREEN:
3043             return PSEUDO_SCREEN_WIDTH;
3044         case SM_CYSCREEN:
3045         case SM_CYVIRTUALSCREEN:
3046             return PSEUDO_SCREEN_HEIGHT;
3047         case SM_CMONITORS:
3048             return 1;
3049     }
3050 #endif
3051     return 1;
3052 }
3053 static int WINAPI expGetSysColor(int index)
3054 {
3055     dbgprintf("GetSysColor(%d) => 1\n", index);
3056     return 1;
3057 }
3058 static int WINAPI expGetSysColorBrush(int index)
3059 {
3060     dbgprintf("GetSysColorBrush(%d)\n", index);
3061     return 1;
3062 }
3063
3064
3065
3066 static int WINAPI expGetSystemPaletteEntries(int hdc, int iStartIndex, int nEntries, void* lppe)
3067 {
3068     dbgprintf("GetSystemPaletteEntries(0x%x, 0x%x, 0x%x, 0x%x) => 0\n",
3069               hdc, iStartIndex, nEntries, lppe);
3070     return 0;
3071 }
3072
3073 /*
3074  typedef struct _TIME_ZONE_INFORMATION {
3075  long Bias;
3076  char StandardName[32];
3077  SYSTEMTIME StandardDate;
3078  long StandardBias;
3079  char DaylightName[32];
3080  SYSTEMTIME DaylightDate;
3081  long DaylightBias;
3082  } TIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
3083  */
3084
3085 static int WINAPI expGetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
3086 {
3087     const short name[]={'C', 'e', 'n', 't', 'r', 'a', 'l', ' ', 'S', 't', 'a',
3088     'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e', 0};
3089     const short pname[]={'C', 'e', 'n', 't', 'r', 'a', 'l', ' ', 'D', 'a', 'y',
3090     'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e', 0};
3091     dbgprintf("GetTimeZoneInformation(0x%x) => TIME_ZONE_ID_STANDARD\n");
3092     memset(lpTimeZoneInformation, 0, sizeof(TIME_ZONE_INFORMATION));
3093     lpTimeZoneInformation->Bias=360;//GMT-6
3094     memcpy(lpTimeZoneInformation->StandardName, name, sizeof(name));
3095     lpTimeZoneInformation->StandardDate.wMonth=10;
3096     lpTimeZoneInformation->StandardDate.wDay=5;
3097     lpTimeZoneInformation->StandardDate.wHour=2;
3098     lpTimeZoneInformation->StandardBias=0;
3099     memcpy(lpTimeZoneInformation->DaylightName, pname, sizeof(pname));
3100     lpTimeZoneInformation->DaylightDate.wMonth=4;
3101     lpTimeZoneInformation->DaylightDate.wDay=1;
3102     lpTimeZoneInformation->DaylightDate.wHour=2;
3103     lpTimeZoneInformation->DaylightBias=-60;
3104     return TIME_ZONE_ID_STANDARD;
3105 }
3106
3107 static void WINAPI expGetLocalTime(SYSTEMTIME* systime)
3108 {
3109     time_t local_time;
3110     struct tm *local_tm;
3111     struct timeval tv;
3112
3113     dbgprintf("GetLocalTime(0x%x)\n");
3114     gettimeofday(&tv, NULL);
3115     local_time=tv.tv_sec;
3116     local_tm=localtime(&local_time);
3117
3118     systime->wYear = local_tm->tm_year + 1900;
3119     systime->wMonth = local_tm->tm_mon + 1;
3120     systime->wDayOfWeek = local_tm->tm_wday;
3121     systime->wDay = local_tm->tm_mday;
3122     systime->wHour = local_tm->tm_hour;
3123     systime->wMinute = local_tm->tm_min;
3124     systime->wSecond = local_tm->tm_sec;
3125     systime->wMilliseconds = (tv.tv_usec / 1000) % 1000;
3126     dbgprintf("  Year: %d\n  Month: %d\n  Day of week: %d\n"
3127               "  Day: %d\n  Hour: %d\n  Minute: %d\n  Second:  %d\n"
3128               "  Milliseconds: %d\n",
3129               systime->wYear, systime->wMonth, systime->wDayOfWeek, systime->wDay,
3130               systime->wHour, systime->wMinute, systime->wSecond, systime->wMilliseconds);
3131 }
3132
3133 static int WINAPI expGetSystemTime(SYSTEMTIME* systime)
3134 {
3135     time_t local_time;
3136     struct tm *local_tm;
3137     struct timeval tv;
3138
3139     dbgprintf("GetSystemTime(0x%x)\n", systime);
3140     gettimeofday(&tv, NULL);
3141     local_time=tv.tv_sec;
3142     local_tm=gmtime(&local_time);
3143
3144     systime->wYear = local_tm->tm_year + 1900;
3145     systime->wMonth = local_tm->tm_mon + 1;
3146     systime->wDayOfWeek = local_tm->tm_wday;
3147     systime->wDay = local_tm->tm_mday;
3148     systime->wHour = local_tm->tm_hour;
3149     systime->wMinute = local_tm->tm_min;
3150     systime->wSecond = local_tm->tm_sec;
3151     systime->wMilliseconds = (tv.tv_usec / 1000) % 1000;
3152     dbgprintf("  Year: %d\n  Month: %d\n  Day of week: %d\n"
3153               "  Day: %d\n  Hour: %d\n  Minute: %d\n  Second:  %d\n"
3154               "  Milliseconds: %d\n",
3155               systime->wYear, systime->wMonth, systime->wDayOfWeek, systime->wDay,
3156               systime->wHour, systime->wMinute, systime->wSecond, systime->wMilliseconds);
3157     return 0;
3158 }
3159
3160 #define SECS_1601_TO_1970  ((369 * 365 + 89) * 86400ULL)
3161 static void WINAPI expGetSystemTimeAsFileTime(FILETIME* systime)
3162 {
3163     struct tm *local_tm;
3164     struct timeval tv;
3165     unsigned long long secs;
3166
3167     dbgprintf("GetSystemTime(0x%x)\n", systime);
3168     gettimeofday(&tv, NULL);
3169     secs = (tv.tv_sec + SECS_1601_TO_1970) * 10000000;
3170     secs += tv.tv_usec * 10;
3171     systime->dwLowDateTime = secs & 0xffffffff;
3172     systime->dwHighDateTime = (secs >> 32);
3173 }
3174
3175 static int WINAPI expGetEnvironmentVariableA(const char* name, char* field, int size)
3176 {
3177     char *p;
3178     //    printf("%s %x %x\n", name, field, size);
3179     if(field)field[0]=0;
3180     /*
3181      p = getenv(name);
3182      if (p) strncpy(field,p,size);
3183      */
3184     if (strcmp(name,"__MSVCRT_HEAP_SELECT")==0)
3185         strcpy(field,"__GLOBAL_HEAP_SELECTED,1");
3186     dbgprintf("GetEnvironmentVariableA(0x%x='%s', 0x%x, %d) => %d\n", name, name, field, size, strlen(field));
3187     return strlen(field);
3188 }
3189
3190 static int WINAPI expSetEnvironmentVariableA(const char *name, const char *value)
3191 {
3192     dbgprintf("SetEnvironmentVariableA(%s, %s)\n", name, value);
3193     return 0;
3194 }
3195
3196 static void* WINAPI expCoTaskMemAlloc(ULONG cb)
3197 {
3198     return my_mreq(cb, 0);
3199 }
3200 static void WINAPI expCoTaskMemFree(void* cb)
3201 {
3202     my_release(cb);
3203 }
3204
3205
3206
3207
3208 void* CoTaskMemAlloc(unsigned long cb)
3209 {
3210     return expCoTaskMemAlloc(cb);
3211 }
3212 void CoTaskMemFree(void* cb)
3213 {
3214     expCoTaskMemFree(cb);
3215 }
3216
3217 struct COM_OBJECT_INFO
3218 {
3219     GUID clsid;
3220     long (*GetClassObject) (GUID* clsid, const GUID* iid, void** ppv);
3221 };
3222
3223 static struct COM_OBJECT_INFO* com_object_table=0;
3224 static int com_object_size=0;
3225 int RegisterComClass(const GUID* clsid, GETCLASSOBJECT gcs)
3226 {
3227     if(!clsid || !gcs)
3228         return -1;
3229     com_object_table=realloc(com_object_table, sizeof(struct COM_OBJECT_INFO)*(++com_object_size));
3230     com_object_table[com_object_size-1].clsid=*clsid;
3231     com_object_table[com_object_size-1].GetClassObject=gcs;
3232     return 0;
3233 }
3234
3235 int UnregisterComClass(const GUID* clsid, GETCLASSOBJECT gcs)
3236 {
3237     int found = 0;
3238     int i = 0;
3239     if(!clsid || !gcs)
3240         return -1;
3241
3242     if (com_object_table == 0)
3243         printf("Warning: UnregisterComClass() called without any registered class\n");
3244     while (i < com_object_size)
3245     {
3246         if (found && i > 0)
3247         {
3248             memcpy(&com_object_table[i - 1].clsid,
3249                    &com_object_table[i].clsid, sizeof(GUID));
3250             com_object_table[i - 1].GetClassObject =
3251                 com_object_table[i].GetClassObject;
3252         }
3253         else if (memcmp(&com_object_table[i].clsid, clsid, sizeof(GUID)) == 0
3254                  && com_object_table[i].GetClassObject == gcs)
3255         {
3256             found++;
3257         }
3258         i++;
3259     }
3260     if (found)
3261     {
3262         if (--com_object_size == 0)
3263         {
3264             free(com_object_table);
3265             com_object_table = 0;
3266         }
3267     }
3268     return 0;
3269 }
3270
3271
3272 const GUID IID_IUnknown =
3273 {
3274     0x00000000, 0x0000, 0x0000,
3275     {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
3276 };
3277 const GUID IID_IClassFactory =
3278 {
3279     0x00000001, 0x0000, 0x0000,
3280     {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
3281 };
3282
3283 static long WINAPI expCoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter,
3284                                        long dwClsContext, const GUID* riid, void** ppv)
3285 {
3286     int i;
3287     struct COM_OBJECT_INFO* ci=0;
3288     for(i=0; i<com_object_size; i++)
3289         if(!memcmp(rclsid, &com_object_table[i].clsid, sizeof(GUID)))
3290             ci=&com_object_table[i];
3291     if(!ci)return REGDB_E_CLASSNOTREG;
3292     // in 'real' world we should mess with IClassFactory here
3293     i=ci->GetClassObject(rclsid, riid, ppv);
3294     return i;
3295 }
3296
3297 long CoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter,
3298                       long dwClsContext, const GUID* riid, void** ppv)
3299 {
3300     return expCoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
3301 }
3302
3303 static int WINAPI expIsRectEmpty(CONST RECT *lprc)
3304 {
3305     int r = 0;
3306     int w,h;
3307 //trapbug();
3308     if (lprc)
3309     {
3310         w = lprc->right - lprc->left;
3311         h = lprc->bottom - lprc->top;
3312         if (w <= 0 || h <= 0)
3313             r = 1;
3314     }
3315     else
3316         r = 1;
3317
3318     dbgprintf("IsRectEmpty(%p) => %s\n", lprc, (r) ? "TRUE" : "FALSE");
3319     //printf("Rect: left: %d, top: %d, right: %d, bottom: %d\n", lprc->left, lprc->top, lprc->right, lprc->bottom);
3320 //    return 0; // wmv9?
3321     return r; // TM20
3322 }
3323
3324 static int _adjust_fdiv=0; //what's this? - used to adjust division
3325
3326
3327
3328
3329 static unsigned int WINAPI expGetTempPathA(unsigned int len, char* path)
3330 {
3331     dbgprintf("GetTempPathA(%d, 0x%x)", len, path);
3332     if(len<5)
3333     {
3334         dbgprintf(" => 0\n");
3335         return 0;
3336     }
3337     strcpy(path, "/tmp");
3338     dbgprintf(" => 5 ( '/tmp' )\n");
3339     return 5;
3340 }
3341 /*
3342  FYI:
3343  typedef struct
3344  {
3345  DWORD     dwFileAttributes;
3346  FILETIME  ftCreationTime;
3347  FILETIME  ftLastAccessTime;
3348  FILETIME  ftLastWriteTime;
3349  DWORD     nFileSizeHigh;
3350  DWORD     nFileSizeLow;
3351  DWORD     dwReserved0;
3352  DWORD     dwReserved1;
3353  CHAR      cFileName[260];
3354  CHAR      cAlternateFileName[14];
3355  } WIN32_FIND_DATAA, *LPWIN32_FIND_DATAA;
3356  */
3357
3358 static DIR* qtx_dir=NULL;
3359
3360 static WIN_BOOL WINAPI expFindNextFileA(HANDLE h,LPWIN32_FIND_DATAA lpfd)
3361 {
3362 #ifdef QTX
3363     dbgprintf("FindNextFileA(0x%x, 0x%x) => 0\n", h, lpfd);
3364     if(h==FILE_HANDLE_quicktimeqtx){
3365         struct dirent* d;
3366         if(!qtx_dir) return 0;
3367         while((d=readdir(qtx_dir))){
3368             char* x=strrchr(d->d_name,'.');
3369             if(!x) continue;
3370             if(strcmp(x,".qtx")) continue;
3371             strcpy(lpfd->cFileName,d->d_name);
3372 //          sprintf(lpfd->cAlternateFileName,"%-8s.qtx",d->d_name);
3373             strcpy(lpfd->cAlternateFileName,"foobar.qtx");
3374             printf("### FindNext: %s\n",lpfd->cFileName);
3375             return 1;
3376         }
3377         closedir(qtx_dir); qtx_dir=NULL;
3378         return 0;
3379     }
3380 #endif
3381     return 0;
3382 }
3383
3384 static HANDLE WINAPI expFindFirstFileA(LPCSTR s, LPWIN32_FIND_DATAA lpfd)
3385 {
3386     dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => 0\n", s, s, lpfd);
3387 //    printf("\n### FindFirstFileA('%s')...\n",s);
3388 #ifdef QTX
3389     if(strstr(s, "quicktime\\*.QTX")){
3390         dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => QTX\n", s, s, lpfd);
3391         printf("\n### Searching for QuickTime plugins (*.qtx) at %s...\n",def_path);
3392         qtx_dir=opendir(def_path);
3393         if(!qtx_dir) return (HANDLE)-1;
3394         memset(lpfd,0,sizeof(*lpfd));
3395         if(expFindNextFileA(FILE_HANDLE_quicktimeqtx,lpfd))
3396             return FILE_HANDLE_quicktimeqtx;
3397         printf("loader: Couldn't find the QuickTime plugins (.qtx files) at %s\n",def_path);
3398         return (HANDLE)-1;
3399     }
3400 #if 0
3401     if(strstr(s, "QuickTime.qts")){
3402         dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => QTS\n", s, s, lpfd);
3403 //      if(!strcmp(s,"C:\\windows\\QuickTime.qts\\QuickTime.qts\\*.QTX"))
3404 //          return (HANDLE)-1;
3405         strcpy(lpfd->cFileName, "QuickTime.qts");
3406         strcpy(lpfd->cAlternateFileName, "QuickT~1.qts");
3407         return FILE_HANDLE_quicktimeqts;
3408     }
3409 #endif
3410 #endif
3411     if(strstr(s, "*.vwp")){
3412         // hack for VoxWare codec plugins:
3413         strcpy(lpfd->cFileName, "msms001.vwp");
3414         strcpy(lpfd->cAlternateFileName, "msms001.vwp");
3415         return (HANDLE)0;
3416     }
3417     // return 'file not found'
3418     return (HANDLE)-1;
3419 }
3420
3421 static WIN_BOOL WINAPI expFindClose(HANDLE h)
3422 {
3423     dbgprintf("FindClose(0x%x) => 0\n", h);
3424 #ifdef QTX
3425 //    if(h==FILE_HANDLE_quicktimeqtx && qtx_dir){
3426 //      closedir(qtx_dir);
3427 //      qtx_dir=NULL;
3428 //    }
3429 #endif
3430     return 0;
3431 }
3432 static UINT WINAPI expSetErrorMode(UINT i)
3433 {
3434     dbgprintf("SetErrorMode(%d) => 0\n", i);
3435     return 0;
3436 }
3437 static UINT WINAPI expGetWindowsDirectoryA(LPSTR s,UINT c)
3438 {
3439     char windir[]="c:\\windows";
3440     int result;
3441     strncpy(s, windir, c);
3442     result=1+((c<strlen(windir))?c:strlen(windir));
3443     dbgprintf("GetWindowsDirectoryA(0x%x, %d) => %d\n", s, c, result);
3444     return result;
3445 }
3446 #ifdef QTX
3447 static UINT WINAPI expGetCurrentDirectoryA(UINT c, LPSTR s)
3448 {
3449     char curdir[]="c:\\";
3450     int result;
3451     strncpy(s, curdir, c);
3452     result=1+((c<strlen(curdir))?c:strlen(curdir));
3453     dbgprintf("GetCurrentDirectoryA(0x%x, %d) => %d\n", s, c, result);
3454     return result;
3455 }
3456
3457 static int WINAPI expSetCurrentDirectoryA(const char *pathname)
3458 {
3459     dbgprintf("SetCurrentDirectoryA(0x%x = %s) => 1\n", pathname, pathname);
3460 #if 0
3461     if (strrchr(pathname, '\\'))
3462         chdir(strcat(strrchr(pathname, '\\')+1, '/'));
3463     else
3464         chdir(pathname);
3465 #endif
3466     return 1;
3467 }
3468
3469 static int WINAPI expCreateDirectoryA(const char *pathname, void *sa)
3470 {
3471     dbgprintf("CreateDirectory(0x%x = %s, 0x%x) => 1\n",
3472         pathname, pathname, sa);
3473 #if 0
3474     p = strrchr(pathname, '\\')+1;
3475     strcpy(&buf[0], p); /* should be strncpy */
3476     if (!strlen(p))
3477     {
3478         buf[0] = '.';
3479         buf[1] = 0;
3480     }
3481 #if 0    
3482     if (strrchr(pathname, '\\'))
3483         mkdir(strcat(strrchr(pathname, '\\')+1, '/'), 666);
3484     else
3485         mkdir(pathname, 666);
3486 #endif
3487     mkdir(&buf);
3488 #endif
3489     return 1;
3490 }
3491 #endif
3492 static WIN_BOOL  WINAPI expDeleteFileA(LPCSTR s)
3493 {
3494     dbgprintf("DeleteFileA(0x%x='%s') => 0\n", s, s);
3495     return 0;
3496 }
3497 static WIN_BOOL  WINAPI expFileTimeToLocalFileTime(const FILETIME* cpf, LPFILETIME pf)
3498 {
3499     dbgprintf("FileTimeToLocalFileTime(0x%x, 0x%x) => 0\n", cpf, pf);
3500     return 0;
3501 }
3502
3503 static UINT WINAPI expGetTempFileNameA(LPCSTR cs1,LPCSTR cs2,UINT i,LPSTR ps)
3504 {
3505     char mask[16]="/tmp/AP_XXXXXX";
3506     int result;
3507     dbgprintf("GetTempFileNameA(0x%x='%s', 0x%x='%s', %d, 0x%x)", cs1, cs1, cs2, cs2, i, ps);
3508     if(i && i<10)
3509     {
3510         dbgprintf(" => -1\n");
3511         return -1;
3512     }
3513     result=mkstemp(mask);
3514     sprintf(ps, "AP%d", result);
3515     dbgprintf(" => %d\n", strlen(ps));
3516     return strlen(ps);
3517 }
3518 //
3519 // This func might need proper implementation if we want AngelPotion codec.
3520 // They try to open APmpeg4v1.apl with it.
3521 // DLL will close opened file with CloseHandle().
3522 //
3523 static HANDLE WINAPI expCreateFileA(LPCSTR cs1,DWORD i1,DWORD i2,
3524                                     LPSECURITY_ATTRIBUTES p1, DWORD i3,DWORD i4,HANDLE i5)
3525 {
3526     dbgprintf("CreateFileA(0x%x='%s', %d, %d, 0x%x, %d, %d, 0x%x)\n", cs1, cs1, i1,
3527               i2, p1, i3, i4, i5);
3528     if((!cs1) || (strlen(cs1)<2))return -1;
3529
3530 #ifdef QTX
3531     if(strstr(cs1, "QuickTime.qts"))
3532     {
3533         int result;
3534         char* tmp=(char*)malloc(strlen(def_path)+50);
3535         strcpy(tmp, def_path);
3536         strcat(tmp, "/");
3537         strcat(tmp, "QuickTime.qts");
3538         result=open(tmp, O_RDONLY);
3539         free(tmp);
3540         return result;
3541     }
3542     if(strstr(cs1, ".qtx"))
3543     {
3544         int result;
3545         char* tmp=(char*)malloc(strlen(def_path)+250);
3546         char* x=strrchr(cs1,'\\');
3547         sprintf(tmp,"%s/%s",def_path,x?(x+1):cs1);
3548 //      printf("### Open: %s -> %s\n",cs1,tmp);
3549         result=open(tmp, O_RDONLY);
3550         free(tmp);
3551         return result;
3552     }
3553 #endif
3554
3555     if(strncmp(cs1, "AP", 2) == 0)
3556     {
3557         int result;
3558         char* tmp=(char*)malloc(strlen(def_path)+50);
3559         strcpy(tmp, def_path);
3560         strcat(tmp, "/");
3561         strcat(tmp, "APmpg4v1.apl");
3562         result=open(tmp, O_RDONLY);
3563         free(tmp);
3564         return result;
3565     }
3566     if (strstr(cs1, "vp3"))
3567     {
3568         int r;
3569         int flg = 0;
3570         char* tmp=(char*)malloc(20 + strlen(cs1));
3571         strcpy(tmp, "/tmp/");
3572         strcat(tmp, cs1);
3573         r = 4;
3574         while (tmp[r])
3575         {
3576             if (tmp[r] == ':' || tmp[r] == '\\')
3577                 tmp[r] = '_';
3578             r++;
3579         }
3580         if (GENERIC_READ & i1)
3581             flg |= O_RDONLY;
3582         else if (GENERIC_WRITE & i1)
3583         {
3584             flg |= O_WRONLY;
3585             printf("Warning: openning filename %s  %d (flags; 0x%x) for write\n", tmp, r, flg);
3586         }
3587         r=open(tmp, flg);
3588         free(tmp);
3589         return r;
3590     }
3591
3592     // Needed by wnvplay1.dll
3593     if (strstr(cs1, "WINNOV.bmp"))
3594     {
3595         int r;
3596         r=open("/dev/null", 0);
3597         return r;
3598     }
3599
3600 #if 0
3601     /* we need this for some virtualdub filters */
3602     {
3603         int r;
3604         int flg = 0;
3605         if (GENERIC_READ & i1)
3606             flg |= O_RDONLY;
3607         else if (GENERIC_WRITE & i1)
3608         {
3609             flg |= O_WRONLY;
3610             printf("Warning: openning filename %s  %d (flags; 0x%x) for write\n", cs1, r, flg);
3611         }
3612         r=open(cs1, flg);
3613         return r;
3614     }
3615 #endif
3616
3617     return atoi(cs1+2);
3618 }
3619 static UINT WINAPI expGetSystemDirectoryA(
3620   char* lpBuffer,  // address of buffer for system directory
3621   UINT uSize        // size of directory buffer
3622 ){
3623     dbgprintf("GetSystemDirectoryA(%p,%d)\n", lpBuffer,uSize);
3624     if(!lpBuffer) strcpy(lpBuffer,".");
3625     return 1;
3626 }
3627 /*
3628 static char sysdir[]=".";
3629 static LPCSTR WINAPI expGetSystemDirectoryA()
3630 {
3631     dbgprintf("GetSystemDirectoryA() => 0x%x='%s'\n", sysdir, sysdir);
3632     return sysdir;
3633 }
3634 */
3635 static DWORD WINAPI expGetFullPathNameA
3636 (
3637         LPCTSTR lpFileName,
3638         DWORD nBufferLength,
3639         LPTSTR lpBuffer,
3640         LPTSTR lpFilePart
3641 ){
3642     if(!lpFileName) return 0;
3643     dbgprintf("GetFullPathNameA('%s',%d,%p,%p)\n",lpFileName,nBufferLength,
3644         lpBuffer, lpFilePart);
3645 #if 0
3646 #ifdef QTX
3647     strcpy(lpFilePart, "Quick123.qts");
3648 #else
3649     strcpy(lpFilePart, lpFileName);
3650 #endif
3651 #else
3652     if (strrchr(lpFileName, '\\'))
3653         lpFilePart = strrchr(lpFileName, '\\');
3654     else
3655         lpFilePart = (LPTSTR)lpFileName;
3656 #endif
3657     strcpy(lpBuffer, lpFileName);
3658 //    strncpy(lpBuffer, lpFileName, rindex(lpFileName, '\\')-lpFileName);
3659     return strlen(lpBuffer);
3660 }
3661
3662 static DWORD WINAPI expGetShortPathNameA
3663 (
3664         LPCSTR longpath,
3665         LPSTR shortpath,
3666         DWORD shortlen
3667 ){
3668     if(!longpath) return 0;
3669     dbgprintf("GetShortPathNameA('%s',%p,%d)\n",longpath,shortpath,shortlen);
3670     strcpy(shortpath,longpath);
3671     return strlen(shortpath);
3672 }
3673
3674 static WIN_BOOL WINAPI expReadFile(HANDLE h,LPVOID pv,DWORD size,LPDWORD rd,LPOVERLAPPED unused)
3675 {
3676     int result;
3677     dbgprintf("ReadFile(%d, 0x%x, %d -> 0x%x)\n", h, pv, size, rd);
3678     result=read(h, pv, size);
3679     if(rd)*rd=result;
3680     if(!result)return 0;
3681     return 1;
3682 }
3683
3684 static WIN_BOOL WINAPI expWriteFile(HANDLE h,LPCVOID pv,DWORD size,LPDWORD wr,LPOVERLAPPED unused)
3685 {
3686     int result;
3687     dbgprintf("WriteFile(%d, 0x%x, %d -> 0x%x)\n", h, pv, size, wr);
3688     if(h==1234)h=1;
3689     result=write(h, pv, size);
3690     if(wr)*wr=result;
3691     if(!result)return 0;
3692     return 1;
3693 }
3694 static DWORD  WINAPI expSetFilePointer(HANDLE h, LONG val, LPLONG ext, DWORD whence)
3695 {
3696     int wh;
3697     dbgprintf("SetFilePointer(%d, 0x%x, 0x%x = %d, %d)\n", h, val, ext, *ext, whence);
3698     //why would DLL want temporary file with >2Gb size?
3699     switch(whence)
3700     {
3701     case FILE_BEGIN:
3702         wh=SEEK_SET;break;
3703     case FILE_END:
3704         wh=SEEK_END;break;
3705     case FILE_CURRENT:
3706         wh=SEEK_CUR;break;
3707     default:
3708         return -1;
3709     }
3710 #ifdef QTX
3711     if (val == 0 && ext != 0)
3712         val = val&(*ext);
3713 #endif
3714     return lseek(h, val, wh);
3715 }
3716
3717 static HDRVR WINAPI expOpenDriverA(LPCSTR szDriverName, LPCSTR szSectionName,
3718                                    LPARAM lParam2)
3719 {
3720     dbgprintf("OpenDriverA(0x%x='%s', 0x%x='%s', 0x%x) => -1\n", szDriverName,  szDriverName, szSectionName, szSectionName, lParam2);
3721     return -1;
3722 }
3723 static HDRVR WINAPI expOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName,
3724                                   LPARAM lParam2)
3725 {
3726     dbgprintf("OpenDriver(0x%x='%s', 0x%x='%s', 0x%x) => -1\n", szDriverName, szDriverName, szSectionName, szSectionName, lParam2);
3727     return -1;
3728 }
3729
3730
3731 static WIN_BOOL WINAPI expGetProcessAffinityMask(HANDLE hProcess,
3732                                                  LPDWORD lpProcessAffinityMask,
3733                                                  LPDWORD lpSystemAffinityMask)
3734 {
3735     dbgprintf("GetProcessAffinityMask(0x%x, 0x%x, 0x%x) => 1\n",
3736               hProcess, lpProcessAffinityMask, lpSystemAffinityMask);
3737     if(lpProcessAffinityMask)*lpProcessAffinityMask=1;
3738     if(lpSystemAffinityMask)*lpSystemAffinityMask=1;
3739     return 1;
3740 }
3741
3742 static int WINAPI expMulDiv(int nNumber, int nNumerator, int nDenominator)
3743 {
3744     static const long long max_int=0x7FFFFFFFLL;
3745     static const long long min_int=-0x80000000LL;
3746     long long tmp=(long long)nNumber*(long long)nNumerator;
3747     dbgprintf("expMulDiv %d * %d / %d\n", nNumber, nNumerator, nDenominator);
3748     if(!nDenominator)return 1;
3749     tmp/=nDenominator;
3750     if(tmp<min_int) return 1;
3751     if(tmp>max_int) return 1;
3752     return (int)tmp;
3753 }
3754
3755 static LONG WINAPI explstrcmpiA(const char* str1, const char* str2)
3756 {
3757     LONG result=strcasecmp(str1, str2);
3758     dbgprintf("strcmpi(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result);
3759     return result;
3760 }
3761
3762 static LONG WINAPI explstrlenA(const char* str1)
3763 {
3764     LONG result=strlen(str1);
3765     dbgprintf("strlen(0x%x='%.50s') => %d\n", str1, str1, result);
3766     return result;
3767 }
3768
3769 static LONG WINAPI explstrcpyA(char* str1, const char* str2)
3770 {
3771     int result= (int) strcpy(str1, str2);
3772     dbgprintf("strcpy(0x%.50x, 0x%.50x='%.50s') => %d\n", str1, str2, str2, result);
3773     return result;
3774 }
3775 static LONG WINAPI explstrcpynA(char* str1, const char* str2,int len)
3776 {
3777     int result;
3778     if (strlen(str2)>len)
3779         result = (int) strncpy(str1, str2,len);
3780     else
3781         result = (int) strcpy(str1,str2);
3782     dbgprintf("strncpy(0x%x, 0x%x='%s' len %d strlen %d) => %x\n", str1, str2, str2,len, strlen(str2),result);
3783     return result;
3784 }
3785 static LONG WINAPI explstrcatA(char* str1, const char* str2)
3786 {
3787     int result= (int) strcat(str1, str2);
3788     dbgprintf("strcat(0x%x, 0x%x='%s') => %d\n", str1, str2, str2, result);
3789     return result;
3790 }
3791
3792
3793 static LONG WINAPI expInterlockedExchange(long *dest, long l)
3794 {
3795     long retval = *dest;
3796     *dest = l;
3797     return retval;
3798 }
3799
3800 static void WINAPI expInitCommonControls(void)
3801 {
3802     dbgprintf("InitCommonControls called!\n");
3803     return;
3804 }
3805
3806 #ifdef QTX
3807 /* needed by QuickTime.qts */
3808 static HWND WINAPI expCreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
3809               HWND parent, INT id, HINSTANCE inst,
3810               HWND buddy, INT maxVal, INT minVal, INT curVal)
3811 {
3812     dbgprintf("CreateUpDownControl(...)\n");
3813     return 0;
3814 }
3815 #endif
3816
3817 /* alex: implement this call! needed for 3ivx */
3818 static HRESULT WINAPI expCoCreateFreeThreadedMarshaler(void *pUnkOuter, void **ppUnkInner)
3819 {
3820     dbgprintf("CoCreateFreeThreadedMarshaler(%p, %p) called!\n",
3821            pUnkOuter, ppUnkInner);
3822 //    return 0;
3823     return ERROR_CALL_NOT_IMPLEMENTED;
3824 }
3825
3826
3827 static int WINAPI expDuplicateHandle(HANDLE hSourceProcessHandle,  // handle to source process
3828                                      HANDLE hSourceHandle,         // handle to duplicate
3829                                      HANDLE hTargetProcessHandle,  // handle to target process
3830                                      HANDLE* lpTargetHandle,      // duplicate handle
3831                                      DWORD dwDesiredAccess,        // requested access
3832                                      int bInheritHandle,          // handle inheritance option
3833                                      DWORD dwOptions               // optional actions
3834                                     )
3835 {
3836     dbgprintf("DuplicateHandle(%p, %p, %p, %p, 0x%x, %d, %d) called\n",
3837               hSourceProcessHandle, hSourceHandle, hTargetProcessHandle,
3838               lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
3839     *lpTargetHandle = hSourceHandle;
3840     return 1;
3841 }
3842
3843 // required by PIM1 codec (used by win98 PCTV Studio capture sw)
3844 static HRESULT WINAPI expCoInitialize(
3845                                       LPVOID lpReserved /* [in] pointer to win32 malloc interface
3846                                       (obsolete, should be NULL) */
3847                                      )
3848 {
3849     /*
3850      * Just delegate to the newer method.
3851      */
3852     return 0; //CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
3853 }
3854
3855 static DWORD WINAPI expSetThreadAffinityMask
3856 (
3857         HANDLE hThread,
3858         DWORD dwThreadAffinityMask
3859 ){
3860     return 0;
3861 };
3862
3863 /*
3864  * no WINAPI functions - CDECL
3865  */
3866 static void* expmalloc(int size)
3867 {
3868     //printf("malloc");
3869     //    return malloc(size);
3870     void* result=my_mreq(size,0);
3871     dbgprintf("malloc(0x%x) => 0x%x\n", size,result);
3872     if(result==0)
3873         printf("WARNING: malloc() failed\n");
3874     return result;
3875 }
3876 static void expfree(void* mem)
3877 {
3878     //    return free(mem);
3879     dbgprintf("free(%p)\n", mem);
3880     my_release(mem);
3881 }
3882 /* needed by atrac3.acm */
3883 static void *expcalloc(int num, int size)
3884 {
3885     void* result=my_mreq(num*size,1);
3886     dbgprintf("calloc(%d,%d) => %p\n", num,size,result);
3887     if(result==0)
3888         printf("WARNING: calloc() failed\n");
3889     return result;
3890 }
3891 static void* expnew(int size)
3892 {
3893     //    printf("NEW:: Call from address %08x\n STACK DUMP:\n", *(-1+(int*)&size));
3894     //    printf("%08x %08x %08x %08x\n",
3895     //    size, *(1+(int*)&size),
3896     //    *(2+(int*)&size),*(3+(int*)&size));
3897     void* result;
3898     assert(size >= 0);
3899
3900     result=my_mreq(size,0);
3901     dbgprintf("new(%d) => %p\n", size, result);
3902     if (result==0)
3903         printf("WARNING: new() failed\n");
3904     return result;
3905
3906 }
3907 static int expdelete(void* memory)
3908 {
3909     dbgprintf("delete(%p)\n", memory);
3910     my_release(memory);
3911     return 0;
3912 }
3913
3914 /*
3915  * local definition - we need only the last two members at this point
3916  * otherwice we would have to introduce here GUIDs and some more types..
3917  */
3918 typedef struct __attribute__((__packed__))
3919 {
3920     char hay[0x40];
3921     unsigned long cbFormat;             //0x40
3922     char*       pbFormat;               //0x44
3923 } MY_MEDIA_TYPE;
3924 static HRESULT WINAPI expMoCopyMediaType(MY_MEDIA_TYPE* dest, const MY_MEDIA_TYPE* src)
3925 {
3926     if (!dest || !src)
3927         return E_POINTER;
3928     memcpy(dest, src, sizeof(MY_MEDIA_TYPE));
3929     if (dest->cbFormat)
3930     {
3931         dest->pbFormat = (char*) my_mreq(dest->cbFormat, 0);
3932         if (!dest->pbFormat)
3933             return E_OUTOFMEMORY;
3934         memcpy(dest->pbFormat, src->pbFormat, dest->cbFormat);
3935     }
3936     return S_OK;
3937 }
3938 static HRESULT WINAPI expMoInitMediaType(MY_MEDIA_TYPE* dest, DWORD cbFormat)
3939 {
3940     if (!dest)
3941         return E_POINTER;
3942     memset(dest, 0, sizeof(MY_MEDIA_TYPE));
3943     if (cbFormat)
3944     {
3945         dest->pbFormat = (char*) my_mreq(cbFormat, 0);
3946         if (!dest->pbFormat)
3947             return E_OUTOFMEMORY;
3948     }
3949     return S_OK;
3950 }
3951 static HRESULT WINAPI expMoCreateMediaType(MY_MEDIA_TYPE** dest, DWORD cbFormat)
3952 {
3953     if (!dest)
3954         return E_POINTER;
3955     *dest = my_mreq(sizeof(MY_MEDIA_TYPE), 0);
3956     return expMoInitMediaType(*dest, cbFormat);
3957 }
3958 static HRESULT WINAPI expMoDuplicateMediaType(MY_MEDIA_TYPE** dest, const void* src)
3959 {
3960     if (!dest)
3961         return E_POINTER;
3962     *dest = my_mreq(sizeof(MY_MEDIA_TYPE), 0);
3963     return expMoCopyMediaType(*dest, src);
3964 }
3965 static HRESULT WINAPI expMoFreeMediaType(MY_MEDIA_TYPE* dest)
3966 {
3967     if (!dest)
3968         return E_POINTER;
3969     if (dest->pbFormat)
3970     {
3971         my_release(dest->pbFormat);
3972         dest->pbFormat = 0;
3973         dest->cbFormat = 0;
3974     }
3975     return S_OK;
3976 }
3977 static HRESULT WINAPI expMoDeleteMediaType(MY_MEDIA_TYPE* dest)
3978 {
3979     if (!dest)
3980         return E_POINTER;
3981     expMoFreeMediaType(dest);
3982     my_release(dest);
3983     return S_OK;
3984 }
3985
3986 static int exp_snprintf( char *str, int size, const char *format, ... )
3987 {
3988       int x;
3989       va_list va;
3990       va_start(va, format);
3991       x=snprintf(str,size,format,va);
3992       dbgprintf("_snprintf( 0x%x, %d, %s, ... ) => %d\n",str,size,format,x);
3993       va_end(va);
3994       return x;
3995 }
3996
3997 #if 0
3998 static int exp_initterm(int v1, int v2)
3999 {
4000     dbgprintf("_initterm(0x%x, 0x%x) => 0\n", v1, v2);
4001     return 0;
4002 }
4003 #else
4004 /* merged from wine - 2002.04.21 */
4005 typedef void (*_INITTERMFUNC)();
4006 static int exp_initterm(_INITTERMFUNC *start, _INITTERMFUNC *end)
4007 {
4008     dbgprintf("_initterm(0x%x, 0x%x) %p\n", start, end, *start);
4009     while (start < end)
4010     {
4011         if (*start)
4012         {
4013             //printf("call _initfunc: from: %p %d\n", *start);
4014             // ok this trick with push/pop is necessary as otherwice
4015             // edi/esi registers are being trashed
4016             void* p = *start;
4017             __asm__ __volatile__
4018                 (
4019                  "pushl %%ebx           \n\t"
4020                  "pushl %%ecx           \n\t"
4021                  "pushl %%edx           \n\t"
4022                  "pushl %%edi           \n\t"
4023                  "pushl %%esi           \n\t"
4024                  "call  *%%eax          \n\t"
4025                  "popl  %%esi           \n\t"
4026                  "popl  %%edi           \n\t"
4027                  "popl  %%edx           \n\t"
4028                  "popl  %%ecx           \n\t"
4029                  "popl  %%ebx           \n\t"
4030                  :
4031                  : "a"(p)
4032                  : "memory"
4033                 );
4034             //printf("done  %p  %d:%d\n", end);
4035         }
4036         start++;
4037     }
4038     return 0;
4039 }
4040 #endif
4041
4042 static void* exp__dllonexit()
4043 {
4044     // FIXME extract from WINE
4045     return NULL;
4046 }
4047
4048 static int expwsprintfA(char* string, const char* format, ...)
4049 {
4050     va_list va;
4051     int result;
4052     va_start(va, format);
4053     result = vsprintf(string, format, va);
4054     dbgprintf("wsprintfA(0x%x, '%s', ...) => %d\n", string, format, result);
4055     va_end(va);
4056     return result;
4057 }
4058
4059 static int expsprintf(char* str, const char* format, ...)
4060 {
4061     va_list args;
4062     int r;
4063     dbgprintf("sprintf(0x%x, %s)\n", str, format);
4064     va_start(args, format);
4065     r = vsprintf(str, format, args);
4066     va_end(args);
4067     return r;
4068 }
4069 static int expsscanf(const char* str, const char* format, ...)
4070 {
4071     va_list args;
4072     int r;
4073     dbgprintf("sscanf(%s, %s)\n", str, format);
4074     va_start(args, format);
4075     r = vsscanf(str, format, args);
4076     va_end(args);
4077     return r;
4078 }
4079 static void* expfopen(const char* path, const char* mode)
4080 {
4081     printf("fopen: \"%s\"  mode:%s\n", path, mode);
4082     //return fopen(path, mode);
4083     return fdopen(0, mode); // everything on screen
4084 }
4085 static int expfprintf(void* stream, const char* format, ...)
4086 {
4087     va_list args;
4088     int r = 0;
4089     dbgprintf("fprintf(%p, %s, ...)\n", stream, format);
4090 #if 1
4091     va_start(args, format);
4092     r = vfprintf((FILE*) stream, format, args);
4093     va_end(args);
4094 #endif
4095     return r;
4096 }
4097
4098 static int expprintf(const char* format, ...)
4099 {
4100     va_list args;
4101     int r;
4102     dbgprintf("printf(%s, ...)\n", format);
4103     va_start(args, format);
4104     r = vprintf(format, args);
4105     va_end(args);
4106     return r;
4107 }
4108
4109 static char* expgetenv(const char* varname)
4110 {
4111     char* v = getenv(varname);
4112     dbgprintf("getenv(%s) => %s\n", varname, v);
4113     return v;
4114 }
4115
4116 static void* expwcscpy(WCHAR* dst, const WCHAR* src)
4117 {
4118     WCHAR* p = dst;
4119     while ((*p++ = *src++))
4120         ;
4121     return dst;
4122 }
4123
4124 static char* expstrrchr(char* string, int value)
4125 {
4126     char* result=strrchr(string, value);
4127     if(result)
4128         dbgprintf("strrchr(0x%x='%s', %d) => 0x%x='%s'", string, string, value, result, result);
4129     else
4130         dbgprintf("strrchr(0x%x='%s', %d) => 0", string, string, value);
4131     return result;
4132 }
4133
4134 static char* expstrchr(char* string, int value)
4135 {
4136     char* result=strchr(string, value);
4137     if(result)
4138         dbgprintf("strchr(0x%x='%s', %d) => 0x%x='%s'", string, string, value, result, result);
4139     else
4140         dbgprintf("strchr(0x%x='%s', %d) => 0", string, string, value);
4141     return result;
4142 }
4143 static int expstrlen(char* str)
4144 {
4145     int result=strlen(str);
4146     dbgprintf("strlen(0x%x='%s') => %d\n", str, str, result);
4147     return result;
4148 }
4149 static char* expstrcpy(char* str1, const char* str2)
4150 {
4151     char* result= strcpy(str1, str2);
4152     dbgprintf("strcpy(0x%x, 0x%x='%s') => %p\n", str1, str2, str2, result);
4153     return result;
4154 }
4155 static char* expstrncpy(char* str1, const char* str2, size_t count)
4156 {
4157     char* result= strncpy(str1, str2, count);
4158     dbgprintf("strncpy(0x%x, 0x%x='%s', %d) => %p\n", str1, str2, str2, count, result);
4159     return result;
4160 }
4161 static int expstrcmp(const char* str1, const char* str2)
4162 {
4163     int result=strcmp(str1, str2);
4164     dbgprintf("strcmp(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result);
4165     return result;
4166 }
4167 static int expstrncmp(const char* str1, const char* str2,int x)
4168 {
4169     int result=strncmp(str1, str2,x);
4170     dbgprintf("strcmp(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result);
4171     return result;
4172 }
4173 static char* expstrcat(char* str1, const char* str2)
4174 {
4175     char* result = strcat(str1, str2);
4176     dbgprintf("strcat(0x%x='%s', 0x%x='%s') => %p\n", str1, str1, str2, str2, result);
4177     return result;
4178 }
4179 static char* exp_strdup(const char* str1)
4180 {
4181     int l = strlen(str1);
4182     char* result = (char*) my_mreq(l + 1,0);
4183     if (result)
4184         strcpy(result, str1);
4185     dbgprintf("_strdup(0x%x='%s') => %p\n", str1, str1, result);
4186     return result;
4187 }
4188 static int expisalnum(int c)
4189 {
4190     int result= (int) isalnum(c);
4191     dbgprintf("isalnum(0x%x='%c' => %d\n", c, c, result);
4192     return result;
4193 }
4194 static int expisspace(int c)
4195 {
4196     int result= (int) isspace(c);
4197     dbgprintf("isspace(0x%x='%c' => %d\n", c, c, result);
4198     return result;
4199 }
4200 static int expisalpha(int c)
4201 {
4202     int result= (int) isalpha(c);
4203     dbgprintf("isalpha(0x%x='%c' => %d\n", c, c, result);
4204     return result;
4205 }
4206 static int expisdigit(int c)
4207 {
4208     int result= (int) isdigit(c);
4209     dbgprintf("isdigit(0x%x='%c' => %d\n", c, c, result);
4210     return result;
4211 }
4212 static void* expmemmove(void* dest, void* src, int n)
4213 {
4214     void* result = memmove(dest, src, n);
4215     dbgprintf("memmove(0x%x, 0x%x, %d) => %p\n", dest, src, n, result);
4216     return result;
4217 }
4218 static int expmemcmp(void* dest, void* src, int n)
4219 {
4220     int result = memcmp(dest, src, n);
4221     dbgprintf("memcmp(0x%x, 0x%x, %d) => %d\n", dest, src, n, result);
4222     return result;
4223 }
4224 static void* expmemcpy(void* dest, void* src, int n)
4225 {
4226     void *result = memcpy(dest, src, n);
4227     dbgprintf("memcpy(0x%x, 0x%x, %d) => %p\n", dest, src, n, result);
4228     return result;
4229 }
4230 static void* expmemset(void* dest, int c, size_t n)
4231 {
4232     void *result = memset(dest, c, n);
4233     dbgprintf("memset(0x%x, %d, %d) => %p\n", dest, c, n, result);
4234     return result;
4235 }
4236 static time_t exptime(time_t* t)
4237 {
4238     time_t result = time(t);
4239     dbgprintf("time(0x%x) => %d\n", t, result);
4240     return result;
4241 }
4242
4243 static int exprand(void)
4244 {
4245     return rand();
4246 }
4247
4248 static void expsrand(int seed)
4249 {
4250     srand(seed);
4251 }
4252
4253 #if 1
4254
4255 // prefered compilation with  -O2 -ffast-math !
4256
4257 static double explog10(double x)
4258 {
4259     /*printf("Log10 %f => %f    0x%Lx\n", x, log10(x), *((int64_t*)&x));*/
4260     return log10(x);
4261 }
4262
4263 static double expcos(double x)
4264 {
4265     /*printf("Cos %f => %f  0x%Lx\n", x, cos(x), *((int64_t*)&x));*/
4266     return cos(x);
4267 }
4268
4269 /* doens't work */
4270 static long exp_ftol_wrong(double x)
4271 {
4272     return (long) x;
4273 }
4274
4275 #else
4276
4277 static void explog10(void)
4278 {
4279     __asm__ __volatile__
4280         (
4281          "fldl 8(%esp)  \n\t"
4282          "fldln2        \n\t"
4283          "fxch %st(1)   \n\t"
4284          "fyl2x         \n\t"
4285         );
4286 }
4287
4288 static void expcos(void)
4289 {
4290     __asm__ __volatile__
4291         (
4292          "fldl 8(%esp)  \n\t"
4293          "fcos          \n\t"
4294         );
4295 }
4296
4297 #endif
4298
4299 // this seem to be the only how to make this function working properly
4300 // ok - I've spent tremendous amount of time (many many many hours
4301 // of debuging fixing & testing - it's almost unimaginable - kabi
4302
4303 // _ftol - operated on the float value which is already on the FPU stack
4304
4305 static void exp_ftol(void)
4306 {
4307     __asm__ __volatile__
4308         (
4309          "sub $12, %esp         \n\t"
4310          "fstcw   -2(%ebp)      \n\t"
4311          "wait                  \n\t"
4312          "movw    -2(%ebp), %ax \n\t"
4313          "orb    $0x0C, %ah     \n\t"
4314          "movw    %ax, -4(%ebp) \n\t"
4315          "fldcw   -4(%ebp)      \n\t"
4316          "fistpl -12(%ebp)      \n\t"
4317          "fldcw   -2(%ebp)      \n\t"
4318          "movl   -12(%ebp), %eax \n\t"
4319          //Note: gcc 3.03 does not do the following op if it
4320          //      knows that ebp=esp
4321          "movl %ebp, %esp       \n\t"
4322         );
4323 }
4324
4325 #define FPU_DOUBLES(var1,var2) double var1,var2; \
4326   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
4327   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
4328
4329 static double exp_CIpow(void)
4330 {
4331     FPU_DOUBLES(x,y);
4332
4333     dbgprintf("_CIpow(%lf, %lf)\n", x, y);
4334     return pow(x, y);
4335 }
4336
4337 static double exppow(double x, double y)
4338 {
4339     /*printf("Pow %f  %f    0x%Lx  0x%Lx  => %f\n", x, y, *((int64_t*)&x), *((int64_t*)&y), pow(x, y));*/
4340     return pow(x, y);
4341 }
4342
4343 static double expldexp(double x, int expo)
4344 {
4345     /*printf("Cos %f => %f  0x%Lx\n", x, cos(x), *((int64_t*)&x));*/
4346     return ldexp(x, expo);
4347 }
4348
4349 static double expfrexp(double x, int* expo)
4350 {
4351     /*printf("Cos %f => %f  0x%Lx\n", x, cos(x), *((int64_t*)&x));*/
4352     return frexp(x, expo);
4353 }
4354
4355
4356
4357 static int exp_stricmp(const char* s1, const char* s2)
4358 {
4359     return strcasecmp(s1, s2);
4360 }
4361
4362 /* from declaration taken from Wine sources - this fountion seems to be
4363  * undocumented in any M$ doc */
4364 static int exp_setjmp3(void* jmpbuf, int x)
4365 {
4366     //dbgprintf("!!!!UNIMPLEMENTED: setjmp3(%p, %d) => 0\n", jmpbuf, x);
4367     //return 0;
4368     __asm__ __volatile__
4369         (
4370          //"mov 4(%%esp), %%edx \n\t"
4371          "mov (%%esp), %%eax   \n\t"
4372          "mov %%eax, (%%edx)    \n\t" // store ebp
4373
4374          //"mov %%ebp, (%%edx)  \n\t"
4375          "mov %%ebx, 4(%%edx)   \n\t"
4376          "mov %%edi, 8(%%edx)   \n\t"
4377          "mov %%esi, 12(%%edx)  \n\t"
4378          "mov %%esp, 16(%%edx)  \n\t"
4379
4380          "mov 4(%%esp), %%eax   \n\t"
4381          "mov %%eax, 20(%%edx)  \n\t"
4382
4383          "movl $0x56433230, 32(%%edx)   \n\t" // VC20 ??
4384          "movl $0, 36(%%edx)    \n\t"
4385          : // output
4386          : "d"(jmpbuf) // input
4387          : "eax"
4388         );
4389 #if 1
4390     __asm__ __volatile__
4391         (
4392          "mov %%fs:0, %%eax     \n\t" // unsure
4393          "mov %%eax, 24(%%edx)  \n\t"
4394          "cmp $0xffffffff, %%eax \n\t"
4395          "jnz l1                \n\t"
4396          "mov %%eax, 28(%%edx)  \n\t"
4397          "l1:                   \n\t"
4398          :
4399          :
4400          : "eax"
4401         );
4402 #endif
4403
4404         return 0;
4405 }
4406
4407 static DWORD WINAPI expGetCurrentProcessId(void)
4408 {
4409     dbgprintf("GetCurrentProcessId(void) => %d\n", getpid());
4410     return getpid(); //(DWORD)NtCurrentTeb()->pid;
4411 }
4412
4413
4414 typedef struct {
4415     UINT        wPeriodMin;
4416     UINT        wPeriodMax;
4417 } TIMECAPS, *LPTIMECAPS;
4418
4419 static MMRESULT WINAPI exptimeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize)
4420 {
4421     dbgprintf("timeGetDevCaps(%p, %u) !\n", lpCaps, wSize);
4422
4423     lpCaps->wPeriodMin = 1;
4424     lpCaps->wPeriodMax = 65535;
4425     return 0;
4426 }
4427
4428 static MMRESULT WINAPI exptimeBeginPeriod(UINT wPeriod)
4429 {
4430     dbgprintf("timeBeginPeriod(%u) !\n", wPeriod);
4431
4432     if (wPeriod < 1 || wPeriod > 65535) return 96+1; //TIMERR_NOCANDO;
4433     return 0;
4434 }
4435
4436 #ifdef QTX
4437 static MMRESULT WINAPI exptimeEndPeriod(UINT wPeriod)
4438 {
4439     dbgprintf("timeEndPeriod(%u) !\n", wPeriod);
4440
4441     if (wPeriod < 1 || wPeriod > 65535) return 96+1; //TIMERR_NOCANDO;
4442     return 0;
4443 }
4444 #endif
4445
4446 static void WINAPI expGlobalMemoryStatus(
4447             LPMEMORYSTATUS lpmem
4448 ) {
4449     static MEMORYSTATUS cached_memstatus;
4450     static int cache_lastchecked = 0;
4451     SYSTEM_INFO si;
4452     FILE *f;
4453
4454     if (time(NULL)==cache_lastchecked) {
4455         memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
4456         return;
4457     }
4458
4459 #if 1
4460     f = fopen( "/proc/meminfo", "r" );
4461     if (f)
4462     {
4463         char buffer[256];
4464         int total, used, free, shared, buffers, cached;
4465
4466         lpmem->dwLength = sizeof(MEMORYSTATUS);
4467         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
4468         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
4469         while (fgets( buffer, sizeof(buffer), f ))
4470         {
4471             /* old style /proc/meminfo ... */
4472             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
4473             {
4474                 lpmem->dwTotalPhys += total;
4475                 lpmem->dwAvailPhys += free + buffers + cached;
4476             }
4477             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
4478             {
4479                 lpmem->dwTotalPageFile += total;
4480                 lpmem->dwAvailPageFile += free;
4481             }
4482
4483             /* new style /proc/meminfo ... */
4484             if (sscanf(buffer, "MemTotal: %d", &total))
4485                 lpmem->dwTotalPhys = total*1024;
4486             if (sscanf(buffer, "MemFree: %d", &free))
4487                 lpmem->dwAvailPhys = free*1024;
4488             if (sscanf(buffer, "SwapTotal: %d", &total))
4489                 lpmem->dwTotalPageFile = total*1024;
4490             if (sscanf(buffer, "SwapFree: %d", &free))
4491                 lpmem->dwAvailPageFile = free*1024;
4492             if (sscanf(buffer, "Buffers: %d", &buffers))
4493                 lpmem->dwAvailPhys += buffers*1024;
4494             if (sscanf(buffer, "Cached: %d", &cached))
4495                 lpmem->dwAvailPhys += cached*1024;
4496         }
4497         fclose( f );
4498
4499         if (lpmem->dwTotalPhys)
4500         {
4501             DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
4502             DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
4503             lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical)
4504                                       / (TotalPhysical / 100);
4505         }
4506     } else
4507 #endif
4508     {
4509         /* FIXME: should do something for other systems */
4510         lpmem->dwMemoryLoad    = 0;
4511         lpmem->dwTotalPhys     = 16*1024*1024;
4512         lpmem->dwAvailPhys     = 16*1024*1024;
4513         lpmem->dwTotalPageFile = 16*1024*1024;
4514         lpmem->dwAvailPageFile = 16*1024*1024;
4515     }
4516     expGetSystemInfo(&si);
4517     lpmem->dwTotalVirtual  = si.lpMaximumApplicationAddress-si.lpMinimumApplicationAddress;
4518     /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
4519     lpmem->dwAvailVirtual  = lpmem->dwTotalVirtual-64*1024;
4520     memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
4521     cache_lastchecked = time(NULL);
4522
4523     /* it appears some memory display programs want to divide by these values */
4524     if(lpmem->dwTotalPageFile==0)
4525         lpmem->dwTotalPageFile++;
4526
4527     if(lpmem->dwAvailPageFile==0)
4528         lpmem->dwAvailPageFile++;
4529 }
4530
4531 /**********************************************************************
4532  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
4533  *
4534  * RETURNS
4535  *    Success: TRUE
4536  *    Failure: FALSE
4537  */
4538 static WIN_BOOL WINAPI expSetThreadPriority(
4539     HANDLE hthread, /* [in] Handle to thread */
4540     INT priority)   /* [in] Thread priority level */
4541 {
4542     dbgprintf("SetThreadPriority(%p,%d)\n",hthread,priority);
4543     return TRUE;
4544 }
4545
4546 static void WINAPI expExitProcess( DWORD status )
4547 {
4548     printf("EXIT - code %ld\n",status);
4549     exit(status);
4550 }
4551
4552 static INT WINAPI expMessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type){
4553     printf("MSGBOX '%s' '%s' (%d)\n",text,title,type);
4554 #ifdef QTX
4555     if (type == MB_ICONHAND && !strlen(text) && !strlen(title))
4556         return IDIGNORE;
4557 #endif
4558     return IDOK;
4559 }
4560
4561 /* these are needed for mss1 */
4562
4563 /* defined in stubs.s */
4564 void exp_EH_prolog(void);
4565
4566 #include <netinet/in.h>
4567 static WINAPI inline unsigned long int exphtonl(unsigned long int hostlong)
4568 {
4569 //    dbgprintf("htonl(%x) => %x\n", hostlong, htonl(hostlong));
4570     return htonl(hostlong);
4571 }
4572
4573 static WINAPI inline unsigned long int expntohl(unsigned long int netlong)
4574 {
4575 //    dbgprintf("ntohl(%x) => %x\n", netlong, ntohl(netlong));
4576     return ntohl(netlong);
4577 }
4578 static void WINAPI expVariantInit(void* p)
4579 {
4580     printf("InitCommonControls called!\n");
4581     return;
4582 }
4583
4584 static int WINAPI expRegisterClassA(const void/*WNDCLASSA*/ *wc)
4585 {
4586     dbgprintf("RegisterClassA(%p) => random id\n", wc);
4587     return time(NULL); /* be precise ! */
4588 }
4589
4590 static int WINAPI expUnregisterClassA(const char *className, HINSTANCE hInstance)
4591 {
4592     dbgprintf("UnregisterClassA(%s, %p) => 0\n", className, hInstance);
4593     return 0;
4594 }
4595
4596 #ifdef QTX
4597 /* should be fixed bcs it's not fully strlen equivalent */
4598 static int expSysStringByteLen(void *str)
4599 {
4600     dbgprintf("SysStringByteLen(%p) => %d\n", str, strlen(str));
4601     return strlen(str);
4602 }
4603
4604 static int expDirectDrawCreate(void)
4605 {
4606     dbgprintf("DirectDrawCreate(...) => NULL\n");
4607     return 0;
4608 }
4609
4610 #if 1
4611 typedef struct tagPALETTEENTRY { 
4612     BYTE peRed; 
4613     BYTE peGreen; 
4614     BYTE peBlue; 
4615     BYTE peFlags; 
4616 } PALETTEENTRY; 
4617
4618 /* reversed the first 2 entries */
4619 typedef struct tagLOGPALETTE { 
4620     WORD         palNumEntries; 
4621     WORD         palVersion; 
4622     PALETTEENTRY palPalEntry[1]; 
4623 } LOGPALETTE; 
4624
4625 static HPALETTE WINAPI expCreatePalette(CONST LOGPALETTE *lpgpl)
4626 {
4627     HPALETTE test;
4628     int i;
4629     
4630     dbgprintf("CreatePalette(%x) => NULL\n", lpgpl);
4631
4632     i = sizeof(LOGPALETTE)+((lpgpl->palNumEntries-1)*sizeof(PALETTEENTRY));
4633     test = (HPALETTE)malloc(i);
4634     memcpy((void *)test, lpgpl, i);
4635
4636     return test;
4637 }
4638 #else
4639 static int expCreatePalette(void)
4640 {
4641     dbgprintf("CreatePalette(...) => NULL\n");
4642     return NULL;
4643 }
4644 #endif
4645
4646 static int WINAPI expGetClientRect(HWND win, RECT *r)
4647 {
4648     dbgprintf("GetClientRect(0x%x, 0x%x) => 1\n", win, r);
4649     r->right = PSEUDO_SCREEN_WIDTH;
4650     r->left = 0;
4651     r->bottom = PSEUDO_SCREEN_HEIGHT;
4652     r->top = 0;
4653     return 1;
4654 }
4655
4656 #if 0
4657 typedef struct tagPOINT { 
4658     LONG x; 
4659     LONG y; 
4660 } POINT, *PPOINT; 
4661 #endif
4662
4663 static int WINAPI expClientToScreen(HWND win, POINT *p)
4664 {
4665     dbgprintf("ClientToScreen(0x%x, 0x%x = %d,%d) => 1\n", win, p, p->x, p->y);
4666     p->x = 0;
4667     p->y = 0;
4668     return 1;
4669 }
4670 #endif
4671
4672 /* for m3jpeg */
4673 static int WINAPI expSetThreadIdealProcessor(HANDLE thread, int proc)
4674 {
4675     dbgprintf("SetThreadIdealProcessor(0x%x, %x) => 0\n", thread, proc);
4676     return 0;
4677 }
4678
4679 static int WINAPI expMessageBeep(int type)
4680 {
4681     dbgprintf("MessageBeep(%d) => 1\n", type);
4682     return 1;
4683 }
4684
4685 static int WINAPI expDialogBoxParamA(void *inst, const char *name,
4686     HWND parent, void *dialog_func, void *init_param)
4687 {
4688     dbgprintf("DialogBoxParamA(0x%x, 0x%x = %s, 0x%x, 0x%x, 0x%x) => 0x42424242\n",
4689         inst, name, name, parent, dialog_func, init_param);
4690     return 0x42424242;
4691 }
4692
4693 /* needed by imagepower mjpeg2k */
4694 static void *exprealloc(void *ptr, size_t size)
4695 {
4696     dbgprintf("realloc(0x%x, %x)\n", ptr, size);
4697     if (!ptr)
4698         return my_mreq(size,0);
4699     else
4700         return my_realloc(ptr, size);        
4701 }
4702
4703 /* Fake GetOpenFileNameA from comdlg32.dll for ViVD codec */
4704 static WIN_BOOL WINAPI expGetOpenFileNameA(/*LPOPENFILENAMEA*/ void* lpfn)
4705 {
4706     return 1;
4707 }
4708
4709 static double expfloor(double x)
4710 {
4711     dbgprintf("floor(%lf)\n", x);
4712     return floor(x);
4713 }
4714
4715 #define FPU_DOUBLE(var) double var; \
4716   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
4717
4718 static double exp_CIcos(void)
4719 {
4720     FPU_DOUBLE(x);
4721
4722     dbgprintf("_CIcos(%lf)\n", x);
4723     return cos(x);
4724 }
4725
4726 static double exp_CIsin(void)
4727 {
4728     FPU_DOUBLE(x);
4729
4730     dbgprintf("_CIsin(%lf)\n", x);
4731     return sin(x);
4732 }
4733
4734 struct exports
4735 {
4736     char name[64];
4737     int id;
4738     void* func;
4739 };
4740 struct libs
4741 {
4742     char name[64];
4743     int length;
4744     struct exports* exps;
4745 };
4746
4747 #define FF(X,Y) \
4748     {#X, Y, (void*)exp##X},
4749
4750 struct exports exp_kernel32[]=
4751 {
4752     FF(GetVolumeInformationA,-1)
4753     FF(GetDriveTypeA,-1)
4754     FF(GetLogicalDriveStringsA,-1)
4755     FF(IsBadWritePtr, 357)
4756     FF(IsBadReadPtr, 354)
4757     FF(IsBadStringPtrW, -1)
4758     FF(IsBadStringPtrA, -1)
4759     FF(DisableThreadLibraryCalls, -1)
4760     FF(CreateThread, -1)
4761     FF(CreateEventA, -1)
4762     FF(SetEvent, -1)
4763     FF(ResetEvent, -1)
4764     FF(WaitForSingleObject, -1)
4765 #ifdef QTX
4766     FF(WaitForMultipleObjects, -1)
4767     FF(ExitThread, -1)
4768     FF(CreateMutexA,-1)
4769     FF(ReleaseMutex,-1)
4770 #endif
4771     FF(GetSystemInfo, -1)
4772     FF(GetVersion, 332)
4773     FF(HeapCreate, 461)
4774     FF(HeapAlloc, -1)
4775     FF(HeapDestroy, -1)
4776     FF(HeapFree, -1)
4777     FF(HeapSize, -1)
4778     FF(HeapReAlloc,-1)
4779     FF(GetProcessHeap, -1)
4780     FF(VirtualAlloc, -1)
4781     FF(VirtualFree, -1)
4782     FF(InitializeCriticalSection, -1)
4783     FF(EnterCriticalSection, -1)
4784     FF(LeaveCriticalSection, -1)
4785     FF(DeleteCriticalSection, -1)
4786     FF(TlsAlloc, -1)
4787     FF(TlsFree, -1)
4788     FF(TlsGetValue, -1)
4789     FF(TlsSetValue, -1)
4790     FF(GetCurrentThreadId, -1)
4791     FF(GetCurrentProcess, -1)
4792     FF(LocalAlloc, -1)
4793     FF(LocalReAlloc,-1)
4794     FF(LocalLock, -1)
4795     FF(GlobalAlloc, -1)
4796     FF(GlobalReAlloc, -1)
4797     FF(GlobalLock, -1)
4798     FF(GlobalSize, -1)
4799     FF(MultiByteToWideChar, 427)
4800     FF(WideCharToMultiByte, -1)
4801     FF(GetVersionExA, -1)
4802     FF(CreateSemaphoreA, -1)
4803     FF(QueryPerformanceCounter, -1)
4804     FF(QueryPerformanceFrequency, -1)
4805     FF(LocalHandle, -1)
4806     FF(LocalUnlock, -1)
4807     FF(LocalFree, -1)
4808     FF(GlobalHandle, -1)
4809     FF(GlobalUnlock, -1)
4810     FF(GlobalFree, -1)
4811     FF(LoadResource, -1)
4812     FF(ReleaseSemaphore, -1)
4813     FF(FindResourceA, -1)
4814     FF(LockResource, -1)
4815     FF(FreeResource, -1)
4816     FF(SizeofResource, -1)
4817     FF(CloseHandle, -1)
4818     FF(GetCommandLineA, -1)
4819     FF(GetEnvironmentStringsW, -1)
4820     FF(FreeEnvironmentStringsW, -1)
4821     FF(FreeEnvironmentStringsA, -1)
4822     FF(GetEnvironmentStrings, -1)
4823     FF(GetStartupInfoA, -1)
4824     FF(GetStdHandle, -1)
4825     FF(GetFileType, -1)
4826 #ifdef QTX
4827     FF(GetFileAttributesA, -1)
4828 #endif
4829     FF(SetHandleCount, -1)
4830     FF(GetACP, -1)
4831     FF(GetModuleFileNameA, -1)
4832     FF(SetUnhandledExceptionFilter, -1)
4833     FF(LoadLibraryA, -1)
4834     FF(GetProcAddress, -1)
4835     FF(FreeLibrary, -1)
4836     FF(CreateFileMappingA, -1)
4837     FF(OpenFileMappingA, -1)
4838     FF(MapViewOfFile, -1)
4839     FF(UnmapViewOfFile, -1)
4840     FF(Sleep, -1)
4841     FF(GetModuleHandleA, -1)
4842     FF(GetProfileIntA, -1)
4843     FF(GetPrivateProfileIntA, -1)
4844     FF(GetPrivateProfileStringA, -1)
4845     FF(WritePrivateProfileStringA, -1)
4846     FF(GetLastError, -1)
4847     FF(SetLastError, -1)
4848     FF(InterlockedIncrement, -1)
4849     FF(InterlockedDecrement, -1)
4850     FF(GetTimeZoneInformation, -1)
4851     FF(OutputDebugStringA, -1)
4852     FF(GetLocalTime, -1)
4853     FF(GetSystemTime, -1)
4854     FF(GetSystemTimeAsFileTime, -1)
4855     FF(GetEnvironmentVariableA, -1)
4856     FF(SetEnvironmentVariableA, -1)
4857     FF(RtlZeroMemory,-1)
4858     FF(RtlMoveMemory,-1)
4859     FF(RtlFillMemory,-1)
4860     FF(GetTempPathA,-1)
4861     FF(FindFirstFileA,-1)
4862     FF(FindNextFileA,-1)
4863     FF(FindClose,-1)
4864     FF(FileTimeToLocalFileTime,-1)
4865     FF(DeleteFileA,-1)
4866     FF(ReadFile,-1)
4867     FF(WriteFile,-1)
4868     FF(SetFilePointer,-1)
4869     FF(GetTempFileNameA,-1)
4870     FF(CreateFileA,-1)
4871     FF(GetSystemDirectoryA,-1)
4872     FF(GetWindowsDirectoryA,-1)
4873 #ifdef QTX
4874     FF(GetCurrentDirectoryA,-1)
4875     FF(SetCurrentDirectoryA,-1)
4876     FF(CreateDirectoryA,-1)
4877 #endif
4878     FF(GetShortPathNameA,-1)
4879     FF(GetFullPathNameA,-1)
4880     FF(SetErrorMode, -1)
4881     FF(IsProcessorFeaturePresent, -1)
4882     FF(GetProcessAffinityMask, -1)
4883     FF(InterlockedExchange, -1)
4884     FF(InterlockedCompareExchange, -1)
4885     FF(MulDiv, -1)
4886     FF(lstrcmpiA, -1)
4887     FF(lstrlenA, -1)
4888     FF(lstrcpyA, -1)
4889     FF(lstrcatA, -1)
4890     FF(lstrcpynA,-1)
4891     FF(GetProcessVersion,-1)
4892     FF(GetCurrentThread,-1)
4893     FF(GetOEMCP,-1)
4894     FF(GetCPInfo,-1)
4895     FF(DuplicateHandle,-1)
4896     FF(GetTickCount, -1)
4897     FF(SetThreadAffinityMask,-1)
4898     FF(GetCurrentProcessId,-1)
4899     FF(GlobalMemoryStatus,-1)
4900     FF(SetThreadPriority,-1)
4901     FF(ExitProcess,-1)
4902     {"LoadLibraryExA", -1, (void*)&LoadLibraryExA},
4903     FF(SetThreadIdealProcessor,-1)
4904 };
4905
4906 struct exports exp_msvcrt[]={
4907     FF(malloc, -1)
4908     FF(_initterm, -1)
4909     FF(__dllonexit, -1)
4910     FF(_snprintf,-1)
4911     FF(free, -1)
4912     {"??3@YAXPAX@Z", -1, expdelete},
4913     {"??2@YAPAXI@Z", -1, expnew},
4914     {"_adjust_fdiv", -1, (void*)&_adjust_fdiv},
4915     FF(strrchr, -1)
4916     FF(strchr, -1)
4917     FF(strlen, -1)
4918     FF(strcpy, -1)
4919     FF(strncpy, -1)
4920     FF(wcscpy, -1)
4921     FF(strcmp, -1)
4922     FF(strncmp, -1)
4923     FF(strcat, -1)
4924     FF(_stricmp,-1)
4925     FF(_strdup,-1)
4926     FF(_setjmp3,-1)
4927     FF(isalnum, -1)
4928     FF(isspace, -1)
4929     FF(isalpha, -1)
4930     FF(isdigit, -1)
4931     FF(memmove, -1)
4932     FF(memcmp, -1)
4933     FF(memset, -1)
4934     FF(memcpy, -1)
4935     FF(time, -1)
4936     FF(rand, -1)
4937     FF(srand, -1)
4938     FF(log10, -1)
4939     FF(pow, -1)
4940     FF(cos, -1)
4941     FF(_ftol,-1)
4942     FF(_CIpow,-1)
4943     FF(_CIcos,-1)
4944     FF(_CIsin,-1)
4945     FF(ldexp,-1)
4946     FF(frexp,-1)
4947     FF(sprintf,-1)
4948     FF(sscanf,-1)
4949     FF(fopen,-1)
4950     FF(fprintf,-1)
4951     FF(printf,-1)
4952     FF(getenv,-1)
4953     FF(floor,-1)
4954 /* needed by frapsvid.dll */
4955     {"strstr",-1,(char *)&strstr},
4956     {"qsort",-1,(void *)&qsort},
4957 #ifdef MPLAYER
4958     FF(_EH_prolog,-1)
4959 #endif
4960     FF(calloc,-1)
4961     {"ceil",-1,(void*)&ceil},
4962 /* needed by imagepower mjpeg2k */
4963     {"clock",-1,(void*)&clock},
4964     {"memchr",-1,(void*)&memchr},
4965     {"vfprintf",-1,(void*)&vfprintf},
4966 //    {"realloc",-1,(void*)&realloc},
4967     FF(realloc,-1)
4968     {"puts",-1,(void*)&puts}
4969 };
4970 struct exports exp_winmm[]={
4971     FF(GetDriverModuleHandle, -1)
4972     FF(timeGetTime, -1)
4973     FF(DefDriverProc, -1)
4974     FF(OpenDriverA, -1)
4975     FF(OpenDriver, -1)
4976     FF(timeGetDevCaps, -1)
4977     FF(timeBeginPeriod, -1)
4978 #ifdef QTX
4979     FF(timeEndPeriod, -1)
4980     FF(waveOutGetNumDevs, -1)
4981 #endif
4982 };
4983 struct exports exp_user32[]={
4984     FF(LoadIconA,-1)
4985     FF(LoadStringA, -1)
4986     FF(wsprintfA, -1)
4987     FF(GetDC, -1)
4988     FF(GetDesktopWindow, -1)
4989     FF(ReleaseDC, -1)
4990     FF(IsRectEmpty, -1)
4991     FF(LoadCursorA,-1)
4992     FF(SetCursor,-1)
4993     FF(GetCursorPos,-1)
4994 #ifdef QTX
4995     FF(ShowCursor,-1)
4996 #endif
4997     FF(RegisterWindowMessageA,-1)
4998     FF(GetSystemMetrics,-1)
4999     FF(GetSysColor,-1)
5000     FF(GetSysColorBrush,-1)
5001     FF(GetWindowDC, -1)
5002     FF(DrawTextA, -1)
5003     FF(MessageBoxA, -1)
5004     FF(RegisterClassA, -1)
5005     FF(UnregisterClassA, -1)
5006 #ifdef QTX
5007     FF(GetWindowRect, -1)
5008     FF(MonitorFromWindow, -1)
5009     FF(MonitorFromRect, -1)
5010     FF(MonitorFromPoint, -1)
5011     FF(EnumDisplayMonitors, -1)
5012     FF(GetMonitorInfoA, -1)
5013     FF(EnumDisplayDevicesA, -1)
5014     FF(GetClientRect, -1)
5015     FF(ClientToScreen, -1)
5016     FF(IsWindowVisible, -1)
5017     FF(GetActiveWindow, -1)
5018     FF(GetClassNameA, -1)
5019     FF(GetClassInfoA, -1)
5020     FF(GetWindowLongA, -1)
5021     FF(EnumWindows, -1)
5022     FF(GetWindowThreadProcessId, -1)
5023     FF(CreateWindowExA, -1)
5024 #endif
5025     FF(MessageBeep, -1)
5026     FF(DialogBoxParamA, -1)
5027 };
5028 struct exports exp_advapi32[]={
5029     FF(RegCloseKey, -1)
5030     FF(RegCreateKeyA, -1)
5031     FF(RegCreateKeyExA, -1)
5032     FF(RegEnumKeyExA, -1)
5033     FF(RegEnumValueA, -1)
5034     FF(RegOpenKeyA, -1)
5035     FF(RegOpenKeyExA, -1)
5036     FF(RegQueryValueExA, -1)
5037     FF(RegSetValueExA, -1)
5038     FF(RegQueryInfoKeyA, -1)
5039 };
5040 struct exports exp_gdi32[]={
5041     FF(CreateCompatibleDC, -1)
5042     FF(CreateFontA, -1)
5043     FF(DeleteDC, -1)
5044     FF(DeleteObject, -1)
5045     FF(GetDeviceCaps, -1)
5046     FF(GetSystemPaletteEntries, -1)
5047 #ifdef QTX
5048     FF(CreatePalette, -1)
5049     FF(GetObjectA, -1)
5050     FF(CreateRectRgn, -1)
5051 #endif
5052 };
5053 struct exports exp_version[]={
5054     FF(GetFileVersionInfoSizeA, -1)
5055 };
5056 struct exports exp_ole32[]={
5057     FF(CoCreateFreeThreadedMarshaler,-1)
5058     FF(CoCreateInstance, -1)
5059     FF(CoInitialize, -1)
5060     FF(CoTaskMemAlloc, -1)
5061     FF(CoTaskMemFree, -1)
5062     FF(StringFromGUID2, -1)
5063 };
5064 // do we really need crtdll ???
5065 // msvcrt is the correct place probably...
5066 struct exports exp_crtdll[]={
5067     FF(memcpy, -1)
5068     FF(wcscpy, -1)
5069 };
5070 struct exports exp_comctl32[]={
5071     FF(StringFromGUID2, -1)
5072     FF(InitCommonControls, 17)
5073 #ifdef QTX
5074     FF(CreateUpDownControl, 16)
5075 #endif
5076 };
5077 struct exports exp_wsock32[]={
5078     FF(htonl,8)
5079     FF(ntohl,14)
5080 };
5081 struct exports exp_msdmo[]={
5082     FF(memcpy, -1) // just test
5083     FF(MoCopyMediaType, -1)
5084     FF(MoCreateMediaType, -1)
5085     FF(MoDeleteMediaType, -1)
5086     FF(MoDuplicateMediaType, -1)
5087     FF(MoFreeMediaType, -1)
5088     FF(MoInitMediaType, -1)
5089 };
5090 struct exports exp_oleaut32[]={
5091     FF(VariantInit, 8)
5092 #ifdef QTX
5093     FF(SysStringByteLen, 149)
5094 #endif
5095 };
5096
5097 /*  realplayer8:
5098         DLL Name: PNCRT.dll
5099         vma:  Hint/Ord Member-Name
5100         22ff4     615  free
5101         2302e     250  _ftol
5102         22fea     666  malloc
5103         2303e     609  fprintf
5104         2305e     167  _adjust_fdiv
5105         23052     280  _initterm
5106
5107         22ffc     176  _beginthreadex
5108         23036     284  _iob
5109         2300e      85  __CxxFrameHandler
5110         23022     411  _purecall
5111 */
5112 #ifdef REALPLAYER
5113 struct exports exp_pncrt[]={
5114     FF(malloc, -1) // just test
5115     FF(free, -1) // just test
5116     FF(fprintf, -1) // just test
5117     {"_adjust_fdiv", -1, (void*)&_adjust_fdiv},
5118     FF(_ftol,-1)
5119     FF(_initterm, -1)
5120     {"??3@YAXPAX@Z", -1, expdelete},
5121     {"??2@YAPAXI@Z", -1, expnew},
5122     FF(__dllonexit, -1)
5123     FF(strncpy, -1)
5124     FF(_CIpow,-1)
5125     FF(calloc,-1)
5126     FF(memmove, -1)
5127 };
5128 #endif
5129
5130 #ifdef QTX
5131 struct exports exp_ddraw[]={
5132     FF(DirectDrawCreate, -1)
5133 };
5134 #endif
5135
5136 struct exports exp_comdlg32[]={
5137     FF(GetOpenFileNameA, -1)
5138 };
5139
5140 #define LL(X) \
5141     {#X".dll", sizeof(exp_##X)/sizeof(struct exports), exp_##X},
5142
5143 struct libs libraries[]={
5144     LL(kernel32)
5145     LL(msvcrt)
5146     LL(winmm)
5147     LL(user32)
5148     LL(advapi32)
5149     LL(gdi32)
5150     LL(version)
5151     LL(ole32)
5152     LL(oleaut32)
5153     LL(crtdll)
5154     LL(comctl32)
5155     LL(wsock32)
5156     LL(msdmo)
5157 #ifdef REALPLAYER
5158     LL(pncrt)
5159 #endif
5160 #ifdef QTX
5161     LL(ddraw)
5162 #endif
5163     LL(comdlg32)
5164 };
5165
5166 static void ext_stubs(void)
5167 {
5168     // expects:
5169     //  ax  position index
5170     //  cx  address of printf function
5171 #if 1
5172     __asm__ __volatile__
5173         (
5174          "push %%edx            \n\t"
5175          "movl $0xdeadbeef, %%eax \n\t"
5176          "movl $0xdeadbeef, %%edx \n\t"
5177          "shl $5, %%eax         \n\t"                   // ax * 32
5178          "addl $0xdeadbeef, %%eax \n\t"                 // overwrite export_names
5179          "pushl %%eax           \n\t"
5180          "pushl $0xdeadbeef     \n\t"                   // overwrite called_unk
5181          "call *%%edx           \n\t"                   // printf (via dx)
5182          "addl $8, %%esp        \n\t"
5183          "xorl %%eax, %%eax     \n\t"
5184          "pop %%edx             \n\t"
5185          :
5186          :
5187          : "eax"
5188         );
5189 #else
5190     __asm__ __volatile__
5191         (
5192          "push %%edx            \n\t"
5193          "movl $0, %%eax        \n\t"
5194          "movl $0, %%edx        \n\t"
5195          "shl $5, %%eax         \n\t"                   // ax * 32
5196          "addl %0, %%eax        \n\t"
5197          "pushl %%eax           \n\t"
5198          "pushl %1              \n\t"
5199          "call *%%edx           \n\t"                   // printf (via dx)
5200          "addl $8, %%esp        \n\t"
5201          "xorl %%eax, %%eax     \n\t"
5202          "pop %%edx             \n\t"
5203          ::"m"(*export_names), "m"(*called_unk)
5204         : "memory", "edx", "eax"
5205         );
5206 #endif
5207
5208 }
5209
5210 //static void add_stub(int pos)
5211
5212 extern int unk_exp1;
5213 static int pos=0;
5214 static char extcode[20000];// place for 200 unresolved exports
5215 static const char* called_unk = "Called unk_%s\n";
5216
5217 static void* add_stub(void)
5218 {
5219     // generated code in runtime!
5220     char* answ = (char*)extcode+pos*0x30;
5221 #if 0
5222     memcpy(answ, &unk_exp1, 0x64);
5223     *(int*)(answ+9)=pos;
5224     *(int*)(answ+47)-=((int)answ-(int)&unk_exp1);
5225 #endif
5226     memcpy(answ, ext_stubs, 0x2f); // 0x2c is current size
5227     //answ[4] = 0xb8; // movl $0, eax  (0xb8 0x00000000)
5228     *((int*) (answ + 5)) = pos;
5229     //answ[9] = 0xba; // movl $0, edx  (0xba 0x00000000)
5230     *((long*) (answ + 10)) = (long)printf;
5231     //answ[17] = 0x05; // addl $0, eax  (0x05 0x00000000)
5232     *((long*) (answ + 18)) = (long)export_names;
5233     //answ[23] = 0x68; // pushl $0  (0x68 0x00000000)
5234     *((long*) (answ + 24)) = (long)called_unk;
5235     pos++;
5236     return (void*)answ;
5237 }
5238
5239 void* LookupExternal(const char* library, int ordinal)
5240 {
5241     int i,j;
5242     if(library==0)
5243     {
5244         printf("ERROR: library=0\n");
5245         return (void*)ext_unknown;
5246     }
5247     //    printf("%x %x\n", &unk_exp1, &unk_exp2);
5248
5249     dbgprintf("External func %s:%d\n", library, ordinal);
5250
5251     for(i=0; i<sizeof(libraries)/sizeof(struct libs); i++)
5252     {
5253         if(strcasecmp(library, libraries[i].name))
5254             continue;
5255         for(j=0; j<libraries[i].length; j++)
5256         {
5257             if(ordinal!=libraries[i].exps[j].id)
5258                 continue;
5259             //printf("Hit: 0x%p\n", libraries[i].exps[j].func);
5260             return libraries[i].exps[j].func;
5261         }
5262     }
5263
5264 #ifndef LOADLIB_TRY_NATIVE
5265   /* hack for truespeech and vssh264*/
5266   if (!strcmp(library, "tsd32.dll") || !strcmp(library,"vssh264dec.dll") || !strcmp(library,"LCMW2.dll") || !strcmp(library,"VDODEC32.dll"))
5267 #endif
5268     /* ok, this is a hack, and a big memory leak. should be fixed. - alex */
5269     {
5270         int hand;
5271         WINE_MODREF *wm;
5272         void *func;
5273
5274         hand = LoadLibraryA(library);
5275         if (!hand)
5276             goto no_dll;
5277         wm = MODULE32_LookupHMODULE(hand);
5278         if (!wm)
5279         {
5280             FreeLibrary(hand);
5281             goto no_dll;
5282         }
5283         func = PE_FindExportedFunction(wm, (LPCSTR) ordinal, 0);
5284         if (!func)
5285         {
5286             printf("No such ordinal in external dll\n");
5287             FreeLibrary((int)hand);
5288             goto no_dll;
5289         }
5290
5291         printf("External dll loaded (offset: 0x%x, func: %p)\n",
5292                hand, func);
5293         return func;
5294     }
5295
5296 no_dll:
5297     if(pos>150)return 0;
5298     sprintf(export_names[pos], "%s:%d", library, ordinal);
5299     return add_stub();
5300 }
5301
5302 void* LookupExternalByName(const char* library, const char* name)
5303 {
5304     char* answ;
5305     int i,j;
5306     //   return (void*)ext_unknown;
5307     if(library==0)
5308     {
5309         printf("ERROR: library=0\n");
5310         return (void*)ext_unknown;
5311     }
5312     if(name==0)
5313     {
5314         printf("ERROR: name=0\n");
5315         return (void*)ext_unknown;
5316     }
5317     dbgprintf("External func %s:%s\n", library, name);
5318     for(i=0; i<sizeof(libraries)/sizeof(struct libs); i++)
5319     {
5320         if(strcasecmp(library, libraries[i].name))
5321             continue;
5322         for(j=0; j<libraries[i].length; j++)
5323         {
5324             if(strcmp(name, libraries[i].exps[j].name))
5325                 continue;
5326             //      printf("Hit: 0x%08X\n", libraries[i].exps[j].func);
5327             return libraries[i].exps[j].func;
5328         }
5329     }
5330
5331 #ifndef LOADLIB_TRY_NATIVE
5332   /* hack for vss h264 */
5333   if (!strcmp(library,"vssh264core.dll"))
5334 #endif
5335     /* ok, this is a hack, and a big memory leak. should be fixed. - alex */
5336     {
5337         int hand;
5338         WINE_MODREF *wm;
5339         void *func;
5340
5341         hand = LoadLibraryA(library);
5342         if (!hand)
5343             goto no_dll_byname;
5344         wm = MODULE32_LookupHMODULE(hand);
5345         if (!wm)
5346         {
5347             FreeLibrary(hand);
5348             goto no_dll_byname;
5349         }
5350         func = PE_FindExportedFunction(wm, name, 0);
5351         if (!func)
5352         {
5353             printf("No such name in external dll\n");
5354             FreeLibrary((int)hand);
5355             goto no_dll_byname;
5356         }
5357
5358         printf("External dll loaded (offset: 0x%x, func: %p)\n",
5359                hand, func);
5360         return func;
5361     }
5362
5363 no_dll_byname:
5364     if(pos>150)return 0;// to many symbols
5365     strcpy(export_names[pos], name);
5366     return add_stub();
5367 }
5368
5369 void my_garbagecollection(void)
5370 {
5371 #ifdef GARBAGE
5372     int unfree = 0, unfreecnt = 0;
5373
5374     int max_fatal = 8;
5375     free_registry();
5376     while (last_alloc)
5377     {
5378         alloc_header* mem = last_alloc + 1;
5379         unfree += my_size(mem);
5380         unfreecnt++;
5381         if (my_release(mem) != 0)
5382             // avoid endless loop when memory is trashed
5383             if (--max_fatal < 0)
5384                 break;
5385     }
5386     dbgprintf("Total Unfree %d bytes cnt %d [%p,%d]\n",unfree, unfreecnt, last_alloc, alccnt);
5387 #endif
5388     g_tls = NULL;
5389     list = NULL;
5390 }