1/*
2 * tkWin32Dll.c --
3 *
4 *	This file contains a stub dll entry point.
5 *
6 * Copyright (c) 1995 Sun Microsystems, Inc.
7 *
8 * See the file "license.terms" for information on usage and redistribution of
9 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 *
11 * RCS: @(#) $Id$
12 */
13
14#include "tkWinInt.h"
15#ifndef STATIC_BUILD
16
17#ifdef HAVE_NO_SEH
18
19/*
20 * Unlike Borland and Microsoft, we don't register exception handlers by
21 * pushing registration records onto the runtime stack. Instead, we register
22 * them by creating an EXCEPTION_REGISTRATION within the activation record.
23 */
24
25typedef struct EXCEPTION_REGISTRATION {
26    struct EXCEPTION_REGISTRATION *link;
27    EXCEPTION_DISPOSITION (*handler)(
28	    struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
29    void *ebp;
30    void *esp;
31    int status;
32} EXCEPTION_REGISTRATION;
33
34/*
35 * Need to add noinline flag to DllMain declaration so that gcc -O3 does not
36 * inline asm code into DllEntryPoint and cause a compile time error because
37 * of redefined local labels.
38 */
39
40BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason,
41			    LPVOID reserved) __attribute__ ((noinline));
42
43#else /* !HAVE_NO_SEH */
44
45/*
46 * The following declaration is for the VC++ DLL entry point.
47 */
48
49BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason,
50			    LPVOID reserved);
51#endif /* HAVE_NO_SEH */
52
53/*
54 *----------------------------------------------------------------------
55 *
56 * DllEntryPoint --
57 *
58 *	This wrapper function is used by Borland to invoke the initialization
59 *	code for Tk. It simply calls the DllMain routine.
60 *
61 * Results:
62 *	See DllMain.
63 *
64 * Side effects:
65 *	See DllMain.
66 *
67 *----------------------------------------------------------------------
68 */
69
70BOOL APIENTRY
71DllEntryPoint(
72    HINSTANCE hInst,		/* Library instance handle. */
73    DWORD reason,		/* Reason this function is being called. */
74    LPVOID reserved)		/* Not used. */
75{
76    return DllMain(hInst, reason, reserved);
77}
78
79/*
80 *----------------------------------------------------------------------
81 *
82 * DllMain --
83 *
84 *	DLL entry point. It is only necessary to specify our dll here so that
85 *	resources are found correctly. Otherwise Tk will initialize and clean
86 *	up after itself through other methods, in order to be consistent
87 *	whether the build is static or dynamic.
88 *
89 * Results:
90 *	Always TRUE.
91 *
92 * Side effects:
93 *	This might call some sycronization functions, but MSDN documentation
94 *	states: "Waiting on synchronization objects in DllMain can cause a
95 *	deadlock."
96 *
97 *----------------------------------------------------------------------
98 */
99
100BOOL APIENTRY
101DllMain(
102    HINSTANCE hInstance,
103    DWORD reason,
104    LPVOID reserved)
105{
106#ifdef HAVE_NO_SEH
107    EXCEPTION_REGISTRATION registration;
108#endif
109
110    /*
111     * If we are attaching to the DLL from a new process, tell Tk about the
112     * hInstance to use.
113     */
114
115    switch (reason) {
116    case DLL_PROCESS_ATTACH:
117	DisableThreadLibraryCalls(hInstance);
118	TkWinSetHINSTANCE(hInstance);
119	break;
120
121    case DLL_PROCESS_DETACH:
122	/*
123	 * Protect the call to TkFinalize in an SEH block. We can't be
124	 * guarenteed Tk is always being unloaded from a stable condition.
125	 */
126
127#ifdef HAVE_NO_SEH
128	__asm__ __volatile__ (
129
130	    /*
131	     * Construct an EXCEPTION_REGISTRATION to protect the call to
132	     * TkFinalize
133	     */
134
135	    "leal	%[registration], %%edx"		"\n\t"
136	    "movl	%%fs:0,		%%eax"		"\n\t"
137	    "movl	%%eax,		0x0(%%edx)"	"\n\t" /* link */
138	    "leal	1f,		%%eax"		"\n\t"
139	    "movl	%%eax,		0x4(%%edx)"	"\n\t" /* handler */
140	    "movl	%%ebp,		0x8(%%edx)"	"\n\t" /* ebp */
141	    "movl	%%esp,		0xc(%%edx)"	"\n\t" /* esp */
142	    "movl	%[error],	0x10(%%edx)"	"\n\t" /* status */
143
144	    /*
145	     * Link the EXCEPTION_REGISTRATION on the chain
146	     */
147
148	    "movl	%%edx,		%%fs:0"		"\n\t"
149
150	    /*
151	     * Call TkFinalize
152	     */
153
154	    "movl	$0x0,		0x0(%%esp)"		"\n\t"
155	    "call	_TkFinalize"			"\n\t"
156
157	    /*
158	     * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
159	     * and store a TCL_OK status
160	     */
161
162	    "movl	%%fs:0,		%%edx"		"\n\t"
163	    "movl	%[ok],		%%eax"		"\n\t"
164	    "movl	%%eax,		0x10(%%edx)"	"\n\t"
165	    "jmp	2f"				"\n"
166
167	    /*
168	     * Come here on an exception. Get the EXCEPTION_REGISTRATION that
169	     * we previously put on the chain.
170	     */
171
172	    "1:"					"\t"
173	    "movl	%%fs:0,		%%edx"		"\n\t"
174	    "movl	0x8(%%edx),	%%edx"		"\n"
175
176
177	    /*
178	     * Come here however we exited. Restore context from the
179	     * EXCEPTION_REGISTRATION in case the stack is unbalanced.
180	     */
181
182	    "2:"					"\t"
183	    "movl	0xc(%%edx),	%%esp"		"\n\t"
184	    "movl	0x8(%%edx),	%%ebp"		"\n\t"
185	    "movl	0x0(%%edx),	%%eax"		"\n\t"
186	    "movl	%%eax,		%%fs:0"		"\n\t"
187
188	    :
189	    /* No outputs */
190	    :
191	    [registration]	"m"	(registration),
192	    [ok]		"i"	(TCL_OK),
193	    [error]		"i"	(TCL_ERROR)
194	    :
195	    "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
196	    );
197
198#else /* HAVE_NO_SEH */
199	__try {
200	    /*
201	     * Run and remove our exit handlers, if they haven't already been
202	     * run. Just in case we are being unloaded prior to Tcl (it can
203	     * happen), we won't leave any dangling pointers hanging around
204	     * for when Tcl gets unloaded later.
205	     */
206
207	    TkFinalize(NULL);
208	} __except (EXCEPTION_EXECUTE_HANDLER) {
209	    /* empty handler body. */
210	}
211#endif
212
213	break;
214    }
215    return TRUE;
216}
217
218#endif /* !STATIC_BUILD */
219
220/*
221 * Local Variables:
222 * mode: c
223 * c-basic-offset: 4
224 * fill-column: 78
225 * End:
226 */
227