vkCreateWin32SurfaceKHR not writing to surface - graphics

I'm trying to get a simple test of Vulkan working. I've been following the LunarG tutorials, but ran into the problem that vkCreateWin32SurfaceKHR seems to do nothing. Namely, surface is not being written to. The function vkCreateWin32SurfaceKHR returns 0, so it isn't reporting a failure. Any help is appreciated.
// create window
sdlWindow = SDL_CreateWindow(APP_SHORT_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0);
struct SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(sdlWindow, &wmInfo);
hWnd = wmInfo.info.win.window;
hInstance = GetModuleHandle(NULL);
// create a surface attached to the window
VkWin32SurfaceCreateInfoKHR surface_info = {};
surface_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surface_info.pNext = NULL;
surface_info.hinstance = hInstance;
surface_info.hwnd = hWnd;
sanity(!vkCreateWin32SurfaceKHR(inst, &surface_info, NULL, &surface));

Sascha Willems correctly identified that I was not requesting the extensions necessary to create a surface. I changed my code to request extensions as shown below, and now everything works as expected.
// create an instance
vector<char*> enabledInstanceExtensions;
enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#ifdef VALIDATE_VULKAN
enabledInstanceExtensions.push_back("VK_EXT_debug_report");
#endif
vector<char*> enabledInstanceLayers;
#ifdef VALIDATE_VULKAN
enabledInstanceLayers.push_back("VK_LAYER_LUNARG_standard_validation");
#endif
VkInstanceCreateInfo inst_info = {};
inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
inst_info.pNext = NULL;
inst_info.flags = 0;
inst_info.pApplicationInfo = &app_info;
inst_info.enabledExtensionCount = (uint32_t)enabledInstanceExtensions.size();
inst_info.ppEnabledExtensionNames = enabledInstanceExtensions.data();
inst_info.enabledLayerCount = (uint32_t)enabledInstanceLayers.size();
inst_info.ppEnabledLayerNames = enabledInstanceLayers.data();
sanity(!vkCreateInstance(&inst_info, NULL, &instance));

Beside what Joe added in his answer, I will also say that the call to vkCreateWin32SurfaceKHR() if provided invalid arguments does not fail and return VK_SUCCESS. I`m not sure about other platforms if this is still the case.
When I say invalid arguments I am referring to the two most important hinstance and hwnd of the vulkan structure VkWin32SurfaceCreateInfoKHR.
So pay close attention to those two arguments, it tricked me few times.
Not sure tough why is returning VK_SUCCESS while providing invalid arguments, there may be some internal related things that god know why.

Related

ReadProcessMemory invalid handle

I'm trying to read a value from another process using Python.
I came across this answer, though it doesn't seem to work.
My code:
from ctypes import *
from ctypes.wintypes import *
OpenProcess = windll.kernel32.OpenProcess
ReadProcessMemory = windll.kernel32.ReadProcessMemory
CloseHandle = windll.kernel32.CloseHandle
PROCESS_ALL_ACCESS = 0x1F0FFF
pid = 4580
address = 0x04782FF8
buffer = c_uint()
bufferSize = sizeof(buffer)
bytesRead = c_ulong(0)
processHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if ReadProcessMemory(processHandle, address, buffer, bufferSize, byref(bytesRead)):
print("Success:", buffer)
else:
print("Failed.")
CloseHandle(processHandle)
GetLastError() seems to return 6, which means the handle is invalid.
Though, OpenProcess() returns a nonzero value, and GetLastError() doesn't show anything about it.
I've tried editing the first argument passed in OpenProcess() (which I made 0x0010), but still no results.
The process ID was dec, and not hex, which broke a few things.
I also had to replace c_uint() with create_string_buffer(4) for the buffer.
Seems to work fine now!

How to get pixels from window using Direct2D

My problem is getting the pixels in a window. I can't find a way to do this. I using standard windows functions and Direct2D (not DirectDraw).
I am using standard initialization of new window:
WNDCLASS wc;
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(6);
wc.lpszMenuName = 0;
wc.lpszClassName = L"WINDOW"; RegisterClass(&wc);
hWnd = CreateWindow(L"WINDOW", L"Game", WS_OVERLAPPEDWINDOW,100,100,1024,768,NULL,NULL,hInstance,NULL);
Then I create a D2D1factory object and draw the bitmap in the window:
HWND hWnd = NULL;
srand((unsigned int)time((time_t)NULL));
ID2D1Factory* factory = NULL;
ID2D1HwndRenderTarget* rt = NULL;
CoInitializeEx(NULL,COINIT_MULTITHREADED);
My_CreateWindow(&hWnd, hInstance);
My_CreateFactory(&hWnd, factory, rt);
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&factory);
factory->CreateHwndRenderTarget(RenderTargetProperties(), HwndRenderTargetProperties(hWnd,SizeU(800,600)), &rt);
// tons of code
rt->BeginDraw(); rt->DrawBitmap(background[0], RectF(0,0,800,600));
rt->DrawBitmap(GIFHorse[(int)iterator],
RectF(0+MyX-100,0+MyY-100,100+MyX,100+MyY));
rt->DrawBitmap(Star[(int)iterator], RectF(0 + starX, 0 + starY, 50 + starX, 50+starY)); rt->EndDraw();
I need to calculate the hits (I am trying to make simple game). So that's why I need access to all pixels in window.
I'm thinking about using other algorithms, but they're harder to make and I want to start with something easier.
I know about the GetPixel() function, but I cant understand what I should use for HDC.
There is no simple and easy way to get to D2D pixels.
A simple collision detection can be implemented using geometries. If you have outlines of your objects in ID2D1Geometry objects you can compare them using ID2D1Geometry::CompareWithGeometry.
If you insist on the pixels, a way to access them is from the DC obtainable via IDXGISurface1::GetDC
In this case you need to use the DXGI surface render target and the swap chain instead of the hwnd render target.
Step by step:
D3D11CreateDeviceAndSwapChain gives you the swap chain.
IDXGISwapChain::GetBuffer gives you the DXGI surface.
ID2D1Factory::CreateDxgiSurfaceRenderTarget gives you the render target.
IDXGISurface1::GetDC gives you the DC. Read the remarks on this page!

How to wrap the IO functions in Lua to prevent the user from leaving X directory

How could you wrap the IO functions in Lua to prevent someone from leaving your top level directory.
You place them in "MyDoc" and they have full IO access to everything sub of MyDoc but couldn't for example .. back into the C drive or anywhere else.
open up liolib.c. head over to these 3 functions
static void opencheck (lua_State *L, const char *fname, const char *mode) {
LStream *p = newfile(L);
p->f = fopen(fname, mode);
if (p->f == NULL)
luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
}
static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
p->f = lua_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
these are the functions you want to edit.
the first one receives the file name as the parameter fname, the second and the third
pop it out of the lua stack as the local variable filename.
now all you need to do is
1) get your own process path
2) canonize the given file path
3) compare them so that they are the same up until the last slash on both
4) if they are not the same then in opencheck use luaL_error(L,"access denied to %s", fname);
in the other two return luaL_fileresult(L,0,filename);
Presumably you have sandboxed your user environment, so for instance they can't use the builtin "require" or "dofile" or "setatable"? Basically you have to limit the functions they can call to only what you want, and create your own versions of anything you want to control. There are several ways to do this and they each have their pros and cons and nothing is unbreakable, all you can do is up the bar of experience, effort and time required to break your "jail".
This means you have to work at the C API level, but I would not recommend modifying the source unless you are very familiar with it and can easily determine that your modifications aren't easiy breakable. By staying at the C API level, at least other Lua users can help validate the solidity of the sandbox.
You have to figure out a way to enable your code to call Lua builtin without allowing the user to call the builtin. I believe you can store tables in the lua registry, where only the C code can look. It's been a while. Or maybe if you don't put getmetable in user environment, that allows you to call the builtins via metatable but user can't get to them.
For example, from C
you load the builtins such as io module and save the functions you will wrap (such as open) in a (meta)table table;
delete the builtin table io from _G so user only has access to the version you created; you've saved the functions you will need for later
create a global table called io and set its metatable to what you created in step 1, so it defines only functions you want to give access to, such as a function called "open".
In that function you do whatever filtering you need, before calling the builtin you saved.
The details will make a big difference, and implementation will be different if you use Lua 5.1 vs 5.2, but there are several good articles on sandboxing in Lua on the web (sorry no time to find), take a look and come up with something, then maybe post on Lua user mailing list or SO for pros/cons. ;)

Can't get MFC worker thread to pass hWnd or MDI window pointer to thread

For some reason passing an hWnd or a pointer of a newly created MDI window cannot be recasted into its original value in the worker thread. I've tried creating the thread from the App class, Document class and View class. All have the same effect. I'm using a global function for the worker thread. Funny thing is I'm using the same code I used to do the same thing in an MFC MDI back in 1998 and it worked great back then but doesn't seem to work now.
Perhaps I'm just not seeing the problem. What is going on here? What I want to do is simple, create a new View window, capture it's hWnd and pass that hWnd to the worker thread so the worker thread can send messages to the window to print strings and so forth. I'd like to launch the thread from the Document class. The compiler is VS2010 and it's being run in Debug.
After reading this: http://msdn.microsoft.com/en-us/library/h14y172e%28v=VS.100%29.aspx, I realize that you probably can't pass a pointer to the view class around to worker threads. So I'm focusing on the hWnds. In the OnTestConnect block, a valid hWnd is returned as is a valid pointer to the new View window.
Here's the code (from the App class):
struct THREADPARMS
{
HWND hWndView;
int test;
};
(note, I've tried defining the struct as typedef and with a variable name, all have same result)
UINT Starter( LPVOID pParms )
{
THREADPARMS* pThreadParms = (THREADPARMS* )pParms;
//This step shouldn't be necesarry but I tried it anyway. Should
//be able to use pThreadParms->hWndView without casting.
//The hWnd value does not come across as valid. It is valid before sending.
HWND hWnd = (HWND)pThreadParms->hWndView;
//The int comes across fine
int iNum = pThreadParms->test;
CHFTAppBView* pView = (CHFTAppBView*) CHFTAppBView::FromHandle(hWnd);
//This bombs with a debug error becuase pView ptr is invalid (though it was
//valid before sending over
pView->SendMessage( ID_FILE_PRINT, 0, 0 );
return 0;
}
void CHFTAppBApp::OnTestConnect()
{
THREADPARMS* pThreadParms = new THREADPARMS;
//Create the window
AfxGetApp()->OnCmdMsg( ID_FILE_NEW, 0, NULL, NULL );
CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd* pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
CHFTAppBView* pView = (CHFTAppBView*)pChild->GetActiveView();
pThreadParms->hWndView = pView->m_hWnd;
pThreadParms->test = 10;
AfxBeginThread( Starter, pThreadParms );
}
Part 2
//Create the window
AfxGetApp()->OnCmdMsg( ID_FILE_NEW, 0, NULL, NULL );
CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd* pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
CHFTAppBView* pView = (CHFTAppBView*)pChild->GetActiveView();
HWND h = pView->m_hWnd;
SendMessage( h, ID_FILE_PRINT, 0, 0 );
I'm trying to determine if the hWnd is valid. The pView is valid. Stepping through the code and looking at the pointer stats in the Debugger Watch shows a helathy pointer that references the CView class. But it does not return a healthy hWnd. Then Debugger Watch says 'can't evaluate' hWnd memory address and says 'unused=0'. Running it past IsWindow returns true, however. Go figure. Trying to send a CView message to the CView window with that handle just gets ignored. Why would the GetAvtiveView return a valid pointer but the hWnd in that class return garbage?
Part 3
After some more digging, turns out the HWND is valid though the hwnd variable displays 'unused=???' in the Watch window. I assume it's valid because the hWnd received in the thread code matches the hWnd attached to the pView pointer in the main code. The pView pointer the hWnd is taken from is valid as well because Watch recognizes it as a valid CView class pointer by returning the name of the CView class it represents. There are still two problems however. One is that even though the system sends a valid hWnd back to a CView window (pView->m_hWnd), a SendMessage(pView->m_hWnd, ID_FILE_PRINT_PREVIEW, 0, 0,) refuses to work. The system ignores it. I expected the FilePrintPreview command in the newly created view window to run. Second is that FromHandle returns a CWnd object and casting it to a CView fails using all of these methods:
UINT ThreadTest1( LPVOID pParms )
{
THREADPARMS* pThreadParms = (THREADPARMS* )pParms;
//Returns a CWnd even though the handle is to a valid CView
CHFTAppBView* pView2 = (CHFTAppBView*) CHFTAppBView::FromHandle(hWnd);
//Doesn't seem to do anything. Still returns a hWnd that the system recognizes as
//a CWnd. That's what reports in the Watch window.
CHFTAppBView* pView = reinterpret_cast<CHFTAppBView*>(CHFTAppBView::FromHandle(hWnd));
//Doesn't appear to do anything
DYNAMIC_DOWNCAST( CHFTAppBView, pView2 );
//Confirms what watch window says -- it's a CWnd not a CView.
if ( !pView->IsKindOf( RUNTIME_CLASS(CHFTAppBView) ) )
AfxMessageBox( "Not CView" );
::SendMessage( hWnd, ID_FILE_PRINT, 0, 0 );
return 0;
}
void CHFTAppBDoc::Main()
{
AfxGetApp()->OnCmdMsg( ID_FILE_NEW, 0, NULL, NULL );
THREADPARMS* pThreadParms = new THREADPARMS;
CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd* pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
CHFTAppBView* pView = (CHFTAppBView*)pChild->GetActiveView();
pThreadParms->hWndView = pView->m_hWnd;
AfxBeginThread( ThreadTest1, pThreadParms );
SendMessage( pView->m_hWnd, ID_FILE_PRINT, 0, 0 );
//Or
::SendMessage( pView->m_hWnd, ID_FILE_PRINT, 0, 0 );
}
So the questions is how can the hWnd be converted to a the correct window pointer in the thread code? Why can't the system cast it to a CView?
Part 4
Probem solved (for now). Lessons:
Cannot pass a CView window pointer to a worker thread. See link above about this.
Use SendMessage to communicate between theads and windows
//This works from the worker thread now
THREADPARMS* pThreadParms = (THREADPARMS* )pParms;
HWND hWnd = static_cast(pThreadParms->hWndView);
LRESULT lRst = ::SendMessage( pThreadParms->hWnd, WM_GGG, 0, 0 );
//Or just
LRESULT lRst = ::SendMessage( pThreadParms->hWnd, WM_GGG, 0, 0 );
//As well as this from the CDoc method that creates the thread:
CHFTAppBView* pView = (CHFTAppBView*)pChild->GetActiveView();
LRESULT lRst = ::SendMessage( pView->m_hWnd, WM_GGG, 0, 0 );
CView's message map...
ON_MESSAGE( WM_GGG, kk )
Pass HWNDs to worker threads to identify CView windows
Cannot cast from CWnd to a lower derrived class (and excpet it to work right).
Use ON_MESSAGE in view's message map to capture commands sent with SendMessage (be sure to include the method declaraion as afx_msg in the View's .h file)
All pretty straight forward but for those looking for answers (when faced with a myriad of possible causes) this summary may help...
I still don't completely undertstand why casting FromHandle to a CView worked in my old MFC app and not now. Perhaps it has something to do with where the code is located. In the old MFC app it was located in the CView window and in this code in the CDoc class. CDocument is not derrived from CWnd but CView is.
Anyway, that wraps this problem up. A BIG thank you to all who offered advice -- Nik, Scott, Ulrich and Mark. Your sage advice was very helpful.
You can call CHFTAppBView::FromHandle(hWnd) but what you get back isn't a pointer to a CHFTAppBView; it's a pointer to a CWnd. By casting it, you're telling the compiler "trust me, this is really a pointer to a CHFTAppBView. Except it really isn't and you shouldn't treat it as such or pretend that it is.
After all, if a recipe calls for orange juice, then you don't take a lemon, paint it orange, juice it and call it orange juice. Do you?
So what to do? Well, if all you want to do is send the ID_FILE_PRINT message, you don't even need a CWnd as such. You could just just do:
::SendMessage(hWnd, ID_FILE_PRINT, 0, 0);
Of course, that's also likely to be wrong. What you probably meant to do was this:
::SendMessage(hWnd, WM_COMMAND, ID_FILE_PRINT, 0);
Update:
Again, you CANNOT do what you are trying to do. Let's go step by step, shall we?
//Returns a CWnd even though the handle is to a valid CView
CHFTAppBView* pView2 = (CHFTAppBView*) CHFTAppBView::FromHandle(hWnd);
Right. CWnd::FromHandle returns a pointer to a CWnd, not to anything else. It is NOT giving you back a pointer to your original CHFTAppBView. It's giving you a NEW CWnd which is attached to that same HWND. It is NOT VALID to cast that to a CHFTAppBView because this new CWnd is not a CHFTAppBView.
//Doesn't seem to do anything. Still returns a hWnd that the system recognizes as
//a CWnd. That's what reports in the Watch window.
CHFTAppBView* pView = reinterpret_cast<CHFTAppBView*>(CHFTAppBView::FromHandle(hWnd));
Again, CWnd::FromHandle returns a pointer to a new CWnd which knows nothing about CHFTAppBView. You are telling the compiler "trust me, this pointer is to a CHFTAppBView object!" Except it is NOT. It is a pointer to a CWnd attached to a HWND that is a CHFTAppBView.
//Doesn't appear to do anything
DYNAMIC_DOWNCAST( CHFTAppBView, pView );
This STILL wouldn't do anything. First of all, DYNAMIC_DOWNCAST returns a pointer to CHFTAppBView so right there, you're calling the MFC RTTI functions but not doing anything with the result. But even if you did save the result, it wouldn't help. You would be trying to convert a generic CWnd into something it is not.
I'll try to explain this one more time: When you create your view, MFC creates a CHFTAppBView object which is associated with the HWND of the view. When you call CWnd::FromHandle passing in the HWND of the view, MFC creates a NEW and distinct CWnd instance which points to that same HWND - that second CWnd is NOT CHFTAppBView and the HWND knows nothing about your MFC classes, views, documents or anything else.
You are trying to take the CWnd * that CWnd::FromHandle returns and hammer it into a CHFTAppBView *. No matter how hard you try, this will not work. All you can ever get will be a CWnd * and nothing else.
As a sidenote, you also cannot pass MFC objects from one thread to another, so passing the original CHFTAppBView * will cause weird issues to crop up, and may lead to hard to track errors.
Update 2:
You ask "Why can't a CWnd object be cast to a window class that derrives from CWnd?"
Let's start from CWnd::FromHandle shall we?
CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);
#ifndef _AFX_NO_OCC_SUPPORT
pWnd->AttachControlSite(pMap);
#endif
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
return pWnd;
}
This leads us to CHandleMap::FromHandle. The code for that is a bit complicated and posting it here won't help, so let's not clutter things up. But here is what the function does, conceptually:
If a handle is found in the map, it returns it; otherwise, it creates a new CWnd and makes that CWnd point to the HWND you passed in. It then returns a pointer to that CWnd to you. But notice, this is ONLY a CWnd. Nothiong else. So you see, you cannot just convert that returned CWnd to something else - even if the something else is derived from a CWnd - because what you have is just a CWnd and nothing more.
Let's say you have a wife. She is very beautiful and you love her very much. You carry a picture of her in your wallet. Now, when you meet someone and they ask if you are married, you take out your wallet and proudly show them her picture. The person to who you're talking do doesn't think that you are married to the picture. And you don't think that you can magically "convert" the picture into your wife.
The situation here is somewhat similar. CWnd::FromHandle gives you a "picture" of sorts. It's good for showing around, but not good for much else. You are asking "why can't I transform the picture to my wife?" The answer is because that's not how pictures work.

Freetype2 failing under WoW64

I built a tff to D3D texture function using freetype2(2.3.9) to generate grayscale maps from the fonts. it works great under native win32, however, on WoW64 it just explodes (well, FT_Done and FT_Load_Glyph do). from some debugging, it seems to be a problem with HeapFree as called by free from FT_Free.
I know it should work, as games like WCIII, which to the best of my knowledge use freetype2, run fine, this is my code, stripped of the D3D code(which causes no problems on its own):
FT_Face pFace = NULL;
FT_Error nError = 0;
FT_Byte* pFont = static_cast<FT_Byte*>(ARCHIVE_LoadFile(pBuffer,&nSize));
if((nError = FT_New_Memory_Face(pLibrary,pFont,nSize,0,&pFace)) == 0)
{
FT_Set_Char_Size(pFace,nSize << 6,nSize << 6,96,96);
for(unsigned char c = 0; c < 95; c++)
{
if(!FT_Load_Glyph(pFace,FT_Get_Char_Index(pFace,c + 32),FT_LOAD_RENDER))
{
FT_Glyph pGlyph;
if(!FT_Get_Glyph(pFace->glyph,&pGlyph))
{
LOG("GET: %c",c + 32);
FT_Glyph_To_Bitmap(&pGlyph,FT_RENDER_MODE_NORMAL,0,1);
FT_BitmapGlyph pGlyphMap = reinterpret_cast<FT_BitmapGlyph>(pGlyph);
FT_Bitmap* pBitmap = &pGlyphMap->bitmap;
const size_t nWidth = pBitmap->width;
const size_t nHeight = pBitmap->rows;
//add to texture atlas
}
}
}
}
else
{
FT_Done_Face(pFace);
delete pFont;
return FALSE;
}
FT_Done_Face(pFace);
delete pFont;
return TRUE;
}
ARCHIVE_LoadFile returns blocks allocated with new.
As a secondary question, I would like to render a font using pixel sizes, I came across FT_Set_Pixel_Sizes, but I'm unsure as to whether this stretches the font to fit the size, or bounds it to a size. what I would like to do is render all the glyphs at say 24px (MS Word size here), then turn it into a signed distance field in a 32px area.
Update
After much fiddling, I got a test app to work, which leads me to think the problems are arising from threading, as my code is running in a secondary thread. I have compiled freetype into a static lib using the multithread DLL, my app uses the multithreaded libs. gonna see if i can set up a multithreaded test.
Also updated to 2.4.4, to see if the problem was a known but fixed bug, didn't help however.
Update 2
After some more fiddling, it turns out I wasn't using the correct lib for 2.4.4 -.- after fixing that, the test app works 100%, but the main app still crashes when FT_Done_Face is called, still seems to be a crash in the memory heap management of windows. is it possible that there is a bug in freetype2 that makes it blow up under user threads?

Resources