gdi32/tests: Add D3DKMTCloseAdapter tests.
[wine.git] / dlls / atlthunk / atlthunk.c
blobcd37b75f040a0762d244ea953ca2b587e82b6f9a
1 /*
2 * Copyright 2019 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "windows.h"
20 #include "atlthunk.h"
21 #include "wine/debug.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(atlthunk);
25 #if defined(__i386__) || defined(__x86_64__)
27 struct AtlThunkData_t {
28 struct thunk_pool *pool;
29 WNDPROC proc;
30 SIZE_T arg;
33 /* Thunk replaces the first argument and jumps to provided proc. */
34 #include "pshpack1.h"
35 struct thunk_code
37 #if defined(__x86_64__)
38 BYTE mov_rip_rcx[3]; /* mov mov_offset(%rip), %rcx */
39 DWORD mov_offset;
40 WORD jmp_rip; /* jmp *jmp_offset(%rip) */
41 DWORD jmp_offset;
42 #elif defined(__i386__)
43 BYTE mov_data_addr_eax; /* movl data_addr, %eax */
44 DWORD data_addr;
45 DWORD mov_eax_esp; /* movl %eax, 4(%esp) */
46 WORD jmp;
47 DWORD jmp_addr; /* jmp *jmp_addr */
48 #endif
50 #include "poppack.h"
52 #define THUNK_POOL_SIZE (4096 / sizeof(struct thunk_code))
54 struct thunk_pool
56 struct thunk_code thunks[THUNK_POOL_SIZE];
57 LONG first_free;
58 LONG free_count;
59 AtlThunkData_t data[THUNK_POOL_SIZE];
62 C_ASSERT(FIELD_OFFSET(struct thunk_pool, first_free) == 4096);
64 static struct thunk_pool *alloc_thunk_pool(void)
66 struct thunk_pool *thunks;
67 DWORD old_protect;
68 unsigned i;
70 if (!(thunks = VirtualAlloc(NULL, sizeof(*thunks), MEM_COMMIT, PAGE_READWRITE)))
71 return NULL;
73 for (i = 0; i < ARRAY_SIZE(thunks->thunks); i++)
75 struct thunk_code *thunk = &thunks->thunks[i];
76 #if defined(__x86_64__)
77 thunk->mov_rip_rcx[0] = 0x48; /* mov mov_offset(%rip), %rcx */
78 thunk->mov_rip_rcx[1] = 0x8b;
79 thunk->mov_rip_rcx[2] = 0x0d;
80 thunk->mov_offset = (const BYTE *)&thunks->data[i].arg - (const BYTE *)(&thunk->mov_offset + 1);
81 thunk->jmp_rip = 0x25ff; /* jmp *jmp_offset(%rip) */
82 thunk->jmp_offset = (const BYTE *)&thunks->data[i].proc - (const BYTE *)(&thunk->jmp_offset + 1);
83 #elif defined(__i386__)
84 thunk->mov_data_addr_eax = 0xa1; /* movl data_addr, %eax */
85 thunk->data_addr = (DWORD)&thunks->data[i].arg;
86 thunk->mov_eax_esp = 0x04244489; /* movl %eax, 4(%esp) */
87 thunk->jmp = 0x25ff; /* jmp *jmp_addr */
88 thunk->jmp_addr = (DWORD)&thunks->data[i].proc;
89 #endif
91 VirtualProtect(thunks->thunks, FIELD_OFFSET(struct thunk_pool, first_free), PAGE_EXECUTE_READ, &old_protect);
92 thunks->first_free = 0;
93 thunks->free_count = 0;
94 return thunks;
97 static struct thunk_pool *current_pool;
99 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
101 switch (reason)
103 case DLL_PROCESS_ATTACH:
104 DisableThreadLibraryCalls(instance);
105 break;
106 case DLL_PROCESS_DETACH:
107 if (reserved) break;
108 if (current_pool && current_pool->free_count == current_pool->first_free)
109 VirtualFree(current_pool, sizeof(*current_pool), MEM_RELEASE);
110 break;
112 return TRUE;
115 static CRITICAL_SECTION thunk_alloc_cs;
116 static CRITICAL_SECTION_DEBUG thunk_alloc_cs_debug = {
117 0, 0, &thunk_alloc_cs,
118 { &thunk_alloc_cs_debug.ProcessLocksList,
119 &thunk_alloc_cs_debug.ProcessLocksList },
120 0, 0, { (DWORD_PTR)(__FILE__ ": thunk_alloc_cs") }
122 static CRITICAL_SECTION thunk_alloc_cs = { &thunk_alloc_cs_debug, -1, 0, 0, 0, 0 };
124 AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
126 AtlThunkData_t *thunk = NULL;
128 EnterCriticalSection(&thunk_alloc_cs);
130 if (!current_pool) current_pool = alloc_thunk_pool();
131 if (current_pool)
133 thunk = &current_pool->data[current_pool->first_free];
134 thunk->pool = current_pool;
135 thunk->proc = NULL;
136 thunk->arg = 0;
137 if (++current_pool->first_free == ARRAY_SIZE(current_pool->data))
138 current_pool = NULL;
141 LeaveCriticalSection(&thunk_alloc_cs);
142 return thunk;
145 WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
147 WNDPROC code = (WNDPROC)&thunk->pool->thunks[thunk - thunk->pool->data];
148 TRACE("(%p) -> %p\n", thunk, code);
149 return code;
152 void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
154 if (InterlockedIncrement(&thunk->pool->free_count) == ARRAY_SIZE(thunk->pool->thunks))
155 VirtualFree(thunk->pool, sizeof(*thunk->pool), MEM_RELEASE);
158 void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
160 thunk->proc = proc;
161 thunk->arg = arg;
164 #else /* __i386__ || __x86_64__ */
166 AtlThunkData_t* WINAPI AtlThunk_AllocateData(void)
168 FIXME("Unsupported architecture.\n");
169 return NULL;
172 WNDPROC WINAPI AtlThunk_DataToCode(AtlThunkData_t *thunk)
174 return NULL;
177 void WINAPI AtlThunk_FreeData(AtlThunkData_t *thunk)
181 void WINAPI AtlThunk_InitData(AtlThunkData_t *thunk, void *proc, SIZE_T arg)
185 #endif /* __i386__ || __x86_64__ */