Added more support for buddy windows in the updown control.
[wine/testsucceed.git] / if1632 / relay.c
bloba47d2e9b6487356d4e3c6c9a9b3dc98c80978406
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
4 */
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "wine/winbase16.h"
10 #include "winnt.h"
11 #include "global.h"
12 #include "heap.h"
13 #include "module.h"
14 #include "stackframe.h"
15 #include "task.h"
16 #include "syslevel.h"
17 #include "debugstr.h"
18 #include "debugtools.h"
19 #include "main.h"
21 DEFAULT_DEBUG_CHANNEL(relay)
24 /***********************************************************************
25 * RELAY_Init
27 BOOL RELAY_Init(void)
29 WORD codesel;
31 /* Allocate the code selector for CallTo16 routines */
33 extern void Call16_Ret_Start(), Call16_Ret_End();
34 extern void CallTo16_Ret();
35 extern void CALL32_CBClient_Ret();
36 extern void CALL32_CBClientEx_Ret();
37 extern DWORD CallTo16_RetAddr;
38 extern DWORD CALL32_CBClient_RetAddr;
39 extern DWORD CALL32_CBClientEx_RetAddr;
41 codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)Call16_Ret_Start,
42 (int)Call16_Ret_End - (int)Call16_Ret_Start,
43 0, TRUE, TRUE, FALSE, NULL );
44 if (!codesel) return FALSE;
46 /* Patch the return addresses for CallTo16 routines */
48 CallTo16_RetAddr =
49 MAKELONG( (int)CallTo16_Ret -(int)Call16_Ret_Start, codesel );
50 CALL32_CBClient_RetAddr =
51 MAKELONG( (int)CALL32_CBClient_Ret -(int)Call16_Ret_Start, codesel );
52 CALL32_CBClientEx_RetAddr =
53 MAKELONG( (int)CALL32_CBClientEx_Ret -(int)Call16_Ret_Start, codesel );
55 /* Create built-in modules */
56 if (!BUILTIN_Init()) return FALSE;
58 /* Initialize thunking */
59 return THUNK_Init();
63 /* from relay32/relay386.c */
64 extern char **debug_relay_excludelist,**debug_relay_includelist;
66 /***********************************************************************
67 * RELAY_DebugCallFrom16
69 void RELAY_DebugCallFrom16( CONTEXT86 *context )
71 STACK16FRAME *frame;
72 WORD ordinal;
73 char *args16, funstr[80];
74 const char *args;
75 int i, usecdecl, reg_func;
77 if (!TRACE_ON(relay)) return;
79 frame = CURRENT_STACK16;
80 args = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,funstr,&ordinal);
81 if (!args) return; /* happens for the two snoop register relays */
82 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
83 DPRINTF( "Call %s(",funstr);
84 VA_START16( args16 );
86 usecdecl = ( *args == 'c' );
87 args += 2;
88 reg_func = ( memcmp( args, "regs_", 5 ) == 0
89 || memcmp( args, "intr_", 5 ) == 0 );
90 args += 5;
92 if (usecdecl)
94 while (*args)
96 switch(*args)
98 case 'w':
99 case 's':
100 DPRINTF( "0x%04x", *(WORD *)args16 );
101 args16 += 2;
102 break;
103 case 'l':
104 DPRINTF( "0x%08x", *(int *)args16 );
105 args16 += 4;
106 break;
107 case 't':
108 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
109 if (HIWORD(*(SEGPTR *)args16))
110 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
111 args16 += 4;
112 break;
113 case 'p':
114 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
115 args16 += 4;
116 break;
117 case 'T':
118 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
119 if (HIWORD( *(SEGPTR *)args16 ))
120 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
121 args16 += 4;
122 break;
124 args++;
125 if (*args) DPRINTF( "," );
128 else /* not cdecl */
130 /* Start with the last arg */
131 for (i = 0; args[i]; i++)
133 switch(args[i])
135 case 'w':
136 case 's':
137 args16 += 2;
138 break;
139 case 'l':
140 case 'p':
141 case 't':
142 case 'T':
143 args16 += 4;
144 break;
148 while (*args)
150 switch(*args)
152 case 'w':
153 case 's':
154 args16 -= 2;
155 DPRINTF( "0x%04x", *(WORD *)args16 );
156 break;
157 case 'l':
158 args16 -= 4;
159 DPRINTF( "0x%08x", *(int *)args16 );
160 break;
161 case 't':
162 args16 -= 4;
163 DPRINTF( "0x%08x", *(int *)args16 );
164 if (HIWORD(*(SEGPTR *)args16))
165 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
166 break;
167 case 'p':
168 args16 -= 4;
169 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
170 break;
171 case 'T':
172 args16 -= 4;
173 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
174 if (HIWORD( *(SEGPTR *)args16 ))
175 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
176 break;
178 args++;
179 if (*args) DPRINTF( "," );
183 DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
184 VA_END16( args16 );
186 if (reg_func)
187 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
188 AX_reg(context), BX_reg(context), CX_reg(context),
189 DX_reg(context), SI_reg(context), DI_reg(context),
190 (WORD)ES_reg(context), EFL_reg(context) );
192 SYSLEVEL_CheckNotLevel( 2 );
196 /***********************************************************************
197 * RELAY_DebugCallFrom16Ret
199 void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
201 STACK16FRAME *frame;
202 WORD ordinal;
203 char funstr[80];
204 const char *args;
206 if (!TRACE_ON(relay)) return;
207 frame = CURRENT_STACK16;
208 args = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,funstr,&ordinal);
209 if (!args) return;
210 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
211 DPRINTF( "Ret %s() ",funstr);
213 if ( memcmp( args+2, "long_", 5 ) == 0 )
215 DPRINTF( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
216 ret_val, frame->cs, frame->ip, frame->ds );
218 else if ( memcmp( args+2, "word_", 5 ) == 0 )
220 DPRINTF( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
221 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
223 else if ( memcmp( args+2, "regs_", 5 ) == 0
224 || memcmp( args+2, "intr_", 5 ) == 0 )
226 DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
227 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
228 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
229 AX_reg(context), BX_reg(context), CX_reg(context),
230 DX_reg(context), SI_reg(context), DI_reg(context),
231 (WORD)ES_reg(context), EFL_reg(context) );
234 SYSLEVEL_CheckNotLevel( 2 );
238 /***********************************************************************
239 * RELAY_Unimplemented16
241 * This function is called for unimplemented 16-bit entry points (declared
242 * as 'stub' in the spec file).
244 void RELAY_Unimplemented16(void)
246 WORD ordinal;
247 char name[80];
248 STACK16FRAME *frame = CURRENT_STACK16;
249 BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,name,&ordinal);
250 MESSAGE("No handler for Win16 routine %s (called from %04x:%04x)\n",
251 name, frame->cs, frame->ip );
252 ExitProcess(1);
256 /***********************************************************************
257 * RELAY_DebugCallTo16
259 * 'stack' points to the called function address on the 32-bit stack.
260 * Stack layout:
261 * ... ...
262 * (stack+8) arg2
263 * (stack+4) arg1
264 * (stack) func to call
266 void RELAY_DebugCallTo16( int* stack, int nb_args )
268 TEB *teb;
270 if (!TRACE_ON(relay)) return;
271 teb = NtCurrentTeb();
273 if (nb_args == -1) /* Register function */
275 CONTEXT86 *context = (CONTEXT86 *)stack[0];
276 WORD *stack16 = (WORD *)THREAD_STACK16(teb);
277 DPRINTF("CallTo16(func=%04lx:%04x,ds=%04lx",
278 CS_reg(context), IP_reg(context), DS_reg(context) );
279 nb_args = stack[1] / sizeof(WORD);
280 while (nb_args--) {
281 --stack16;
282 DPRINTF( ",0x%04x", *stack16 );
284 DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack),
285 OFFSETOF(teb->cur_stack) );
286 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x FS=%04x\n",
287 AX_reg(context), BX_reg(context), CX_reg(context),
288 DX_reg(context), SI_reg(context), DI_reg(context),
289 BP_reg(context), (WORD)ES_reg(context), (WORD)FS_reg(context) );
291 else
293 DPRINTF("CallTo16(func=%04x:%04x,ds=%04x",
294 HIWORD(stack[0]), LOWORD(stack[0]),
295 SELECTOROF(teb->cur_stack) );
296 stack++;
297 while (nb_args--) {
298 DPRINTF(",0x%04x", *stack );
299 stack++;
301 DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack),
302 OFFSETOF(teb->cur_stack) );
305 SYSLEVEL_CheckNotLevel( 2 );
309 /***********************************************************************
310 * RELAY_DebugCallTo16Ret
312 void RELAY_DebugCallTo16Ret( int ret_val )
314 if (!TRACE_ON(relay)) return;
316 DPRINTF("CallTo16() ss:sp=%04x:%04x retval=0x%08x\n",
317 SELECTOROF(NtCurrentTeb()->cur_stack),
318 OFFSETOF(NtCurrentTeb()->cur_stack), ret_val);
319 SYSLEVEL_CheckNotLevel( 2 );
323 /**********************************************************************
324 * Catch (KERNEL.55)
326 * Real prototype is:
327 * INT16 WINAPI Catch( LPCATCHBUF lpbuf );
329 void WINAPI Catch16( LPCATCHBUF lpbuf, CONTEXT86 *context )
331 /* Note: we don't save the current ss, as the catch buffer is */
332 /* only 9 words long. Hopefully no one will have the silly */
333 /* idea to change the current stack before calling Throw()... */
335 /* Windows uses:
336 * lpbuf[0] = ip
337 * lpbuf[1] = cs
338 * lpbuf[2] = sp
339 * lpbuf[3] = bp
340 * lpbuf[4] = si
341 * lpbuf[5] = di
342 * lpbuf[6] = ds
343 * lpbuf[7] = unused
344 * lpbuf[8] = ss
347 lpbuf[0] = IP_reg(context);
348 lpbuf[1] = CS_reg(context);
349 /* Windows pushes 4 more words before saving sp */
350 lpbuf[2] = SP_reg(context) - 4 * sizeof(WORD);
351 lpbuf[3] = BP_reg(context);
352 lpbuf[4] = SI_reg(context);
353 lpbuf[5] = DI_reg(context);
354 lpbuf[6] = DS_reg(context);
355 lpbuf[7] = 0;
356 lpbuf[8] = SS_reg(context);
357 AX_reg(context) = 0; /* Return 0 */
361 /**********************************************************************
362 * Throw (KERNEL.56)
364 * Real prototype is:
365 * INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
367 void WINAPI Throw16( LPCATCHBUF lpbuf, INT16 retval, CONTEXT86 *context )
369 STACK16FRAME *pFrame;
370 STACK32FRAME *frame32;
371 TEB *teb = NtCurrentTeb();
373 AX_reg(context) = retval;
375 /* Find the frame32 corresponding to the frame16 we are jumping to */
376 pFrame = THREAD_STACK16(teb);
377 frame32 = pFrame->frame32;
378 while (frame32 && frame32->frame16)
380 if (OFFSETOF(frame32->frame16) < OFFSETOF(teb->cur_stack))
381 break; /* Something strange is going on */
382 if (OFFSETOF(frame32->frame16) > lpbuf[2])
384 /* We found the right frame */
385 pFrame->frame32 = frame32;
386 break;
388 frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32;
391 IP_reg(context) = lpbuf[0];
392 CS_reg(context) = lpbuf[1];
393 SP_reg(context) = lpbuf[2] + 4 * sizeof(WORD) - sizeof(WORD) /*extra arg*/;
394 BP_reg(context) = lpbuf[3];
395 SI_reg(context) = lpbuf[4];
396 DI_reg(context) = lpbuf[5];
397 DS_reg(context) = lpbuf[6];
399 if (lpbuf[8] != SS_reg(context))
400 ERR("Switching stack segment with Throw() not supported; expect crash now\n" );
402 if (TRACE_ON(relay)) /* Make sure we have a valid entry point address */
404 static FARPROC16 entryPoint = NULL;
406 if (!entryPoint) /* Get entry point for Throw() */
407 entryPoint = NE_GetEntryPoint( GetModuleHandle16("KERNEL"), 56 );
408 pFrame->entry_cs = SELECTOROF(entryPoint);
409 pFrame->entry_ip = OFFSETOF(entryPoint);
414 /**********************************************************************
415 * RELAY_CallProc32W
417 * Helper for CallProc[Ex]32W
419 static DWORD RELAY_CallProc32W(int Ex)
421 DWORD nrofargs, argconvmask;
422 FARPROC proc32;
423 DWORD *args, ret;
424 VA_LIST16 valist;
425 int i;
426 int aix;
427 dbg_decl_str(relay, 1024);
429 SYSLEVEL_ReleaseWin16Lock();
431 VA_START16( valist );
432 nrofargs = VA_ARG16( valist, DWORD );
433 argconvmask = VA_ARG16( valist, DWORD );
434 proc32 = VA_ARG16( valist, FARPROC );
435 dsprintf(relay, "CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
436 args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0,
437 sizeof(DWORD)*nrofargs );
438 /* CallProcEx doesn't need its args reversed */
439 for (i=0;i<nrofargs;i++) {
440 if (Ex) {
441 aix = i;
442 } else {
443 aix = nrofargs - i - 1;
445 if (argconvmask & (1<<i))
447 SEGPTR ptr = VA_ARG16( valist, SEGPTR );
448 args[aix] = (DWORD)PTR_SEG_TO_LIN(ptr);
449 dsprintf(relay,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
451 else
453 args[aix] = VA_ARG16( valist, DWORD );
454 dsprintf(relay,"%ld,",args[aix]);
457 dsprintf(relay,"])");
458 VA_END16( valist );
460 if (!proc32) ret = 0;
461 else switch (nrofargs)
463 case 0: ret = proc32();
464 break;
465 case 1: ret = proc32(args[0]);
466 break;
467 case 2: ret = proc32(args[0],args[1]);
468 break;
469 case 3: ret = proc32(args[0],args[1],args[2]);
470 break;
471 case 4: ret = proc32(args[0],args[1],args[2],args[3]);
472 break;
473 case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
474 break;
475 case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
476 break;
477 case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
478 break;
479 case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
480 break;
481 case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
482 break;
483 case 10: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
484 break;
485 case 11: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
486 break;
487 default:
488 /* FIXME: should go up to 32 arguments */
489 ERR("Unsupported number of arguments %ld, please report.\n",nrofargs);
490 ret = 0;
491 break;
493 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
494 if (!Ex) STACK16_POP( NtCurrentTeb(), (3 + nrofargs) * sizeof(DWORD) );
496 TRACE("%s - returns %08lx\n",dbg_str(relay),ret);
497 HeapFree( GetProcessHeap(), 0, args );
499 SYSLEVEL_RestoreWin16Lock();
501 return ret;
505 /**********************************************************************
506 * CallProc32W (KERNEL.517)
508 DWORD WINAPI CallProc32W_16()
510 return RELAY_CallProc32W(0);
514 /**********************************************************************
515 * CallProcEx32W() (KERNEL.518)
517 * C - style linkage to CallProc32W - caller pops stack.
519 DWORD WINAPI CallProcEx32W_16()
521 return RELAY_CallProc32W(TRUE);