BizHawk/libmupen64plus/mupen64plus-video-jabo/main.cpp

583 lines
18 KiB
C++

/* Mupen64plus-video-jabo */
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_types.h"
#include "m64p_plugin.h"
#include "m64p_common.h"
#include "m64p_config.h"
#include "main.h"
#include "typedefs.h"
#include "Config.h"
#define LOG(x) { std::ofstream myfile; myfile.open ("jabo_wrapper_log.txt", std::ios::app); myfile << x << "\n"; myfile.close(); }
namespace OldAPI
{
#include "jabo_api.h"
ptr_InitiateGFX InitiateGFX = NULL;
ptr_ProcessDList ProcessDList = NULL;
ptr_ProcessRDPList ProcessRDPList = NULL;
ptr_ShowCFB ShowCFB = NULL;
ptr_ViStatusChanged ViStatusChanged = NULL;
ptr_ViWidthChanged ViWidthChanged = NULL;
ptr_RomOpen RomOpen = NULL;
ptr_RomClosed RomClosed = NULL;
ptr_CloseDLL CloseDLL = NULL;
ptr_DrawScreen DrawScreen = NULL;
ptr_MoveScreen MoveScreen = NULL;
ptr_UpdateScreen UpdateScreen = NULL;
ptr_DllConfig DllConfig = NULL;
ptr_GetDllInfo GetDllInfo = NULL;
}
ptr_ConfigOpenSection ConfigOpenSection = NULL;
ptr_ConfigSetParameter ConfigSetParameter = NULL;
ptr_ConfigGetParameter ConfigGetParameter = NULL;
ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
ptr_ConfigGetParamString ConfigGetParamString = NULL;
/* local variables */
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
static void *l_DebugCallContext = NULL;
static int l_PluginInit = 0;
HMODULE JaboDLL;
HWND hWnd_jabo;
HANDLE window_thread = NULL;
HMODULE D3D8Dll;
typedef void (*ptr_D3D8_SetRenderingCallback)(void (*callback)(int));
ptr_D3D8_SetRenderingCallback D3D8_SetRenderingCallback = NULL;
typedef void (*ptr_D3D8_ReadScreen)(void *dest, int *width, int *height);
ptr_D3D8_ReadScreen D3D8_ReadScreen = NULL;
typedef void (*ptr_D3D8_CloseDLL)();
ptr_D3D8_CloseDLL D3D8_CloseDLL = NULL;
DWORD old_options;
DWORD old_initflags;
void setup_jabo_functions()
{
JaboDLL = LoadLibrary("Jabotard_Direct3D8.dll");
if (JaboDLL != NULL)
{
OldAPI::InitiateGFX = (OldAPI::ptr_InitiateGFX)GetProcAddress(JaboDLL,"InitiateGFX");
OldAPI::ProcessDList = (OldAPI::ptr_ProcessDList)GetProcAddress(JaboDLL,"ProcessDList");
OldAPI::ProcessRDPList = (OldAPI::ptr_ProcessRDPList)GetProcAddress(JaboDLL,"ProcessRDPList");
OldAPI::ShowCFB = (OldAPI::ptr_ShowCFB)GetProcAddress(JaboDLL,"ShowCFB");
OldAPI::ViStatusChanged = (OldAPI::ptr_ViStatusChanged)GetProcAddress(JaboDLL,"ViStatusChanged");
OldAPI::ViWidthChanged = (OldAPI::ptr_ViWidthChanged)GetProcAddress(JaboDLL,"ViWidthChanged");
OldAPI::RomOpen = (OldAPI::ptr_RomOpen)GetProcAddress(JaboDLL,"RomOpen");
OldAPI::RomClosed = (OldAPI::ptr_RomClosed)GetProcAddress(JaboDLL,"RomClosed");
OldAPI::CloseDLL = (OldAPI::ptr_CloseDLL)GetProcAddress(JaboDLL,"CloseDLL");
OldAPI::DrawScreen = (OldAPI::ptr_DrawScreen)GetProcAddress(JaboDLL,"DrawScreen");
OldAPI::MoveScreen = (OldAPI::ptr_MoveScreen)GetProcAddress(JaboDLL,"MoveScreen");
OldAPI::UpdateScreen = (OldAPI::ptr_UpdateScreen)GetProcAddress(JaboDLL,"UpdateScreen");
OldAPI::DllConfig = (OldAPI::ptr_DllConfig)GetProcAddress(JaboDLL,"DllConfig");
OldAPI::GetDllInfo = (OldAPI::ptr_GetDllInfo)GetProcAddress(JaboDLL,"GetDllInfo");
}
D3D8Dll = LoadLibrary("D3D8.dll");
if (D3D8Dll != NULL)
{
D3D8_SetRenderingCallback = (ptr_D3D8_SetRenderingCallback)GetProcAddress(D3D8Dll,"SetRenderingCallback");
D3D8_ReadScreen = (ptr_D3D8_ReadScreen)GetProcAddress(D3D8Dll,"ReadScreen");
D3D8_CloseDLL = (ptr_D3D8_CloseDLL)GetProcAddress(D3D8Dll,"CloseDLL");
}
}
BOOL readOptionsInitflags (DWORD* options_val, DWORD* initflags_val)
{
HKEY mainkey;
if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\JaboSoft\\Project64 DLL\\Direct3D8 1.6.1",0,KEY_READ,&mainkey) != ERROR_SUCCESS)
{
// key doesn't exist, so we need to create it first
if (RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\JaboSoft\\Project64 DLL\\Direct3D8 1.6.1",NULL,NULL,NULL,KEY_READ,NULL,&mainkey,NULL) != ERROR_SUCCESS)
{
// Couldn't create the key
return (FALSE);
}
}
// Key exists, try to find the Options Value
DWORD type;
DWORD cbData;
int options_value;
LSTATUS result = RegQueryValueEx(mainkey, "Options", NULL, &type, (LPBYTE)&options_value, &cbData);
if (result != ERROR_SUCCESS)
{
options_value = 0;
}
*options_val = options_value;
// Try to find the Direct3D init flags subkey Value
int initflags_value;
result = RegQueryValueEx(mainkey, "Direct3D8.InitFlags", NULL, &type, (LPBYTE)&initflags_value, &cbData);
if (result != ERROR_SUCCESS)
{
initflags_value = 0x00e00000;
}
*initflags_val = initflags_value;
RegCloseKey(mainkey);
return(TRUE);
}
BOOL writeOptionsInitflags(DWORD options_val, DWORD initflags_val)
{
// Open the key for writing
HKEY mainkey;
if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\JaboSoft\\Project64 DLL\\Direct3D8 1.6.1",0,KEY_WRITE,&mainkey) != ERROR_SUCCESS)
{
//LOG("Failure to open key for write");
return (FALSE);
}
// Store our options value
DWORD new_val = options_val;
if (RegSetValueEx(mainkey, "Options", NULL, REG_DWORD, (BYTE *)&new_val, 4) != ERROR_SUCCESS)
{
//LOG("Couldn't write options value");
}
// Store our init flags value
new_val = initflags_val;
if (RegSetValueEx(mainkey, "Direct3D8.InitFlags", NULL, REG_DWORD, (BYTE *)&new_val, 4) != ERROR_SUCCESS)
{
//LOG("Couldn't write init flags value");
}
RegCloseKey(mainkey);
return(TRUE);
}
/* Global functions */
static void DebugMessage(int level, const char *message, ...)
{
char msgbuf[1024];
va_list args;
if (l_DebugCallback == NULL)
return;
va_start(args, message);
vsprintf(msgbuf, message, args);
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
va_end(args);
}
#pragma region (De-)Initialization
/* Mupen64Plus plugin functions */
// TODO
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
void (*DebugCallback)(void *, int, const char *))
{
LOG("API WRAPPER:\t PluginStartup")
setup_jabo_functions();
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
if (l_PluginInit)
return M64ERR_ALREADY_INIT;
/* first thing is to set the callback function for debug info */
l_DebugCallback = DebugCallback;
l_DebugCallContext = Context;
/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) GetProcAddress(CoreLibHandle, "CoreGetAPIVersions");
if (CoreAPIVersionFunc == NULL)
{
DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
return M64ERR_INCOMPATIBLE;
}
(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
{
DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
return M64ERR_INCOMPATIBLE;
}
ConfigOpenSection = (ptr_ConfigOpenSection) GetProcAddress(CoreLibHandle, "ConfigOpenSection");
ConfigSetParameter = (ptr_ConfigSetParameter) GetProcAddress(CoreLibHandle, "ConfigSetParameter");
ConfigGetParameter = (ptr_ConfigGetParameter) GetProcAddress(CoreLibHandle, "ConfigGetParameter");
ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) GetProcAddress(CoreLibHandle, "ConfigSetDefaultInt");
ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) GetProcAddress(CoreLibHandle, "ConfigSetDefaultFloat");
ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) GetProcAddress(CoreLibHandle, "ConfigSetDefaultBool");
ConfigSetDefaultString = (ptr_ConfigSetDefaultString) GetProcAddress(CoreLibHandle, "ConfigSetDefaultString");
ConfigGetParamInt = (ptr_ConfigGetParamInt) GetProcAddress(CoreLibHandle, "ConfigGetParamInt");
ConfigGetParamFloat = (ptr_ConfigGetParamFloat) GetProcAddress(CoreLibHandle, "ConfigGetParamFloat");
ConfigGetParamBool = (ptr_ConfigGetParamBool) GetProcAddress(CoreLibHandle, "ConfigGetParamBool");
ConfigGetParamString = (ptr_ConfigGetParamString) GetProcAddress(CoreLibHandle, "ConfigGetParamString");
l_PluginInit = 1;
return M64ERR_SUCCESS;
}
// TODO
EXPORT m64p_error CALL PluginShutdown(void)
{
LOG("API WRAPPER:\t PluginShutdown")
OldAPI::CloseDLL();
TerminateThread(window_thread,0);
D3D8_CloseDLL();
FreeLibrary(D3D8Dll);
FreeLibrary(JaboDLL);
writeOptionsInitflags(old_options,old_initflags);
if (!l_PluginInit)
return M64ERR_NOT_INIT;
/* reset some local variables */
l_DebugCallback = NULL;
l_DebugCallContext = NULL;
l_PluginInit = 0;
return M64ERR_SUCCESS;
}
// TODO
EXPORT int CALL RomOpen(void)
{
LOG("API WRAPPER:\t RomOpen")
OldAPI::RomOpen();
if (!l_PluginInit)
return 0;
return 1;
}
// TODO
EXPORT void CALL RomClosed( void )
{
LOG("API WRAPPER:\t RomClosed")
OldAPI::RomClosed();
if (!l_PluginInit)
return;
}
#pragma endregion
#pragma region Pluginversion
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
{
LOG("API WRAPPER:\t PluginGetVersion")
OldAPI::PLUGIN_INFO info;
OldAPI::GetDllInfo(&info);
/* set version info */
if (PluginType != NULL)
*PluginType = M64PLUGIN_GFX;
if (PluginVersion != NULL)
*PluginVersion = PLUGIN_VERSION;
if (APIVersion != NULL)
*APIVersion = VIDEO_PLUGIN_API_VERSION;
if (PluginNamePtr != NULL)
*PluginNamePtr = PLUGIN_NAME;
if (Capabilities != NULL)
{
*Capabilities = 0;
}
return M64ERR_SUCCESS;
}
#pragma endregion
// IGNORE
EXPORT void CALL ChangeWindow (void)
{
LOG("API WRAPPER:\t ChangeWindow")
}
// NOTE: NEW GFX_INFO vs old
EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info)
{
LOG("API WRAPPER:\t InitiateGFX")
Config_Open();
SETTINGS settings;
settings.anisotropic_level = (int)Config_ReadInt("anisotropic_level","ANISOTROPIC_FILTERING_LEVEL",0,TRUE,FALSE);
settings.brightness = (int)Config_ReadInt("brightness","Brightness level",0,TRUE,FALSE);
settings.antialiasing_level = (int)Config_ReadInt("antialiasing_level","Antialiasing level",0,TRUE,FALSE);
settings.super2xsal = (BOOL)Config_ReadInt("super2xsal","Enables Super2xSal textures",FALSE);
settings.texture_filter = (BOOL)Config_ReadInt("texture_filter","Always use texture filter",FALSE);
settings.adjust_aspect_ratio = (BOOL)Config_ReadInt("adjust_aspect_ratio","Adjust game aspect ratio to match yours",FALSE);
settings.legacy_pixel_pipeline = (BOOL)Config_ReadInt("legacy_pixel_pipeline","Use legacy pixel pipeline",FALSE);
settings.alpha_blending = (BOOL)Config_ReadInt("alpha_blending","Force alpha blending",FALSE);
settings.wireframe = (BOOL)Config_ReadInt("wireframe","Wireframe rendering",FALSE);
settings.direct3d_transformation_pipeline = (BOOL)Config_ReadInt("direct3d_transformation_pipeline","Use Direct3D transformation pipeline",FALSE);
settings.z_compare = (BOOL)Config_ReadInt("z_compare","Force Z Compare",FALSE);
settings.copy_framebuffer = (BOOL)Config_ReadInt("copy_framebuffer","Copy framebuffer to RDRAM",FALSE);
settings.resolution_width = (int)Config_ReadInt("resolution_width","Emulated Width",-1,TRUE,FALSE);
settings.resolution_height = (int)Config_ReadInt("resolution_height","Emulated Height",-1,TRUE,FALSE);
settings.clear_mode = (int)Config_ReadInt("clear_mode","Direct3D Clear Mode Height",0,TRUE,FALSE);
DWORD new_options_val = 0;
if (settings.copy_framebuffer == TRUE) { new_options_val |= 0x20000000; }
if (settings.z_compare == TRUE) { new_options_val |= 0x10000000; }
if (settings.legacy_pixel_pipeline == TRUE) { new_options_val |= 0x08000000; }
if (settings.alpha_blending == TRUE) { new_options_val |= 0x04000000; }
if (settings.adjust_aspect_ratio == TRUE) { new_options_val |= 0x02000000; }
if (settings.texture_filter == TRUE) { new_options_val |= 0x01000000; }
if (settings.super2xsal == TRUE) { new_options_val |= 0x00001000; }
new_options_val |= (((settings.brightness - 100) / 3) & 0x1F) << 19;
switch (settings.antialiasing_level)
{
case 1: new_options_val |= 0x00004004; break;
case 2: new_options_val |= 0x00008004; break;
case 3: new_options_val |= 0x00010004; break;
}
switch (settings.anisotropic_level)
{
case 1: new_options_val |= 0x00000024; break;
case 2: new_options_val |= 0x00000044; break;
case 3: new_options_val |= 0x00000084; break;
case 4: new_options_val |= 0x00000104; break;
}
// Force 800x600 for now
new_options_val |= 0x00000004;
DWORD new_initflags_val = 0x00e00000;
if (settings.direct3d_transformation_pipeline == TRUE) { new_initflags_val = 0x00a00000; }
readOptionsInitflags(&old_options,&old_initflags);
writeOptionsInitflags(new_options_val,new_initflags_val);
OldAPI::GFX_INFO blah;
blah.hWnd = hWnd_jabo;
blah.hStatusBar = NULL;
blah.MemoryBswaped = true;
blah.HEADER = Gfx_Info.HEADER;
blah.RDRAM = Gfx_Info.RDRAM;
blah.DMEM = Gfx_Info.DMEM;
blah.IMEM = Gfx_Info.IMEM;
blah.MI_INTR_REG = (DWORD *)Gfx_Info.MI_INTR_REG;
blah.DPC_START_REG = (DWORD *)Gfx_Info.DPC_START_REG;
blah.DPC_END_REG = (DWORD *)Gfx_Info.DPC_END_REG;
blah.DPC_CURRENT_REG = (DWORD *)Gfx_Info.DPC_CURRENT_REG;
blah.DPC_STATUS_REG = (DWORD *)Gfx_Info.DPC_STATUS_REG;
blah.DPC_CLOCK_REG = (DWORD *)Gfx_Info.DPC_CLOCK_REG;
blah.DPC_BUFBUSY_REG = (DWORD *)Gfx_Info.DPC_BUFBUSY_REG;
blah.DPC_PIPEBUSY_REG = (DWORD *)Gfx_Info.DPC_PIPEBUSY_REG;
blah.DPC_TMEM_REG = (DWORD *)Gfx_Info.DPC_TMEM_REG;
blah.VI_STATUS_REG = (DWORD *)Gfx_Info.VI_STATUS_REG;
blah.VI_ORIGIN_REG = (DWORD *)Gfx_Info.VI_ORIGIN_REG;
blah.VI_WIDTH_REG = (DWORD *)Gfx_Info.VI_WIDTH_REG;
blah.VI_INTR_REG = (DWORD *)Gfx_Info.VI_INTR_REG;
blah.VI_V_CURRENT_LINE_REG = (DWORD *)Gfx_Info.VI_V_CURRENT_LINE_REG;
blah.VI_TIMING_REG = (DWORD *)Gfx_Info.VI_TIMING_REG;
blah.VI_V_SYNC_REG = (DWORD *)Gfx_Info.VI_V_SYNC_REG;
blah.VI_H_SYNC_REG = (DWORD *)Gfx_Info.VI_H_SYNC_REG;
blah.VI_LEAP_REG = (DWORD *)Gfx_Info.VI_LEAP_REG;
blah.VI_H_START_REG = (DWORD *)Gfx_Info.VI_H_START_REG;
blah.VI_V_START_REG = (DWORD *)Gfx_Info.VI_V_START_REG;
blah.VI_V_BURST_REG = (DWORD *)Gfx_Info.VI_V_BURST_REG;
blah.VI_X_SCALE_REG = (DWORD *)Gfx_Info.VI_X_SCALE_REG;
blah.VI_Y_SCALE_REG = (DWORD *)Gfx_Info.VI_Y_SCALE_REG;
blah.CheckInterrupts = Gfx_Info.CheckInterrupts;
OldAPI::InitiateGFX(blah);
//OldAPI::DllConfig(hWnd_jabo);
return(TRUE);
}
EXPORT void CALL MoveScreen (int xpos, int ypos)
{
LOG("API WRAPPER:\t MoveScreen")
OldAPI::MoveScreen(xpos, ypos);
}
EXPORT void CALL ProcessDList(void)
{
LOG("API WRAPPER:\t ProcessDList")
OldAPI::ProcessDList();
}
EXPORT void CALL ProcessRDPList(void)
{
LOG("API WRAPPER:\t ProcessRDPList")
OldAPI::ProcessRDPList();
}
EXPORT void CALL ShowCFB(void)
{
LOG("API WRAPPER:\t ShowCFB")
OldAPI::ShowCFB();
}
EXPORT void CALL UpdateScreen(void)
{
LOG("API WRAPPER:\t UpdateScreen")
OldAPI::UpdateScreen();
}
EXPORT void CALL ViStatusChanged(void)
{
LOG("API WRAPPER:\t ViStatusChanged")
OldAPI::ViStatusChanged();
}
EXPORT void CALL ViWidthChanged(void)
{
LOG("API WRAPPER:\t ViWidthChanged")
OldAPI::ViWidthChanged();
}
// TODO
EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront)
{
LOG("API WRAPPER:\t ReadScreen2")
if (D3D8_ReadScreen != NULL)
{
D3D8_ReadScreen(dest, width, height);
}
//*width = 800;
//*height = 600;
}
// TODO
EXPORT void CALL SetRenderingCallback(void (*callback)(int))
{
LOG("API WRAPPER:\t SetRenderingCallback")
if (D3D8_SetRenderingCallback != NULL)
{
D3D8_SetRenderingCallback(callback);
}
}
// IMPLEMENT LATER?
EXPORT void CALL FBRead(uint32 addr)
{
LOG("API WRAPPER:\t FBRead")
}
// IMPLEMENT LATER?
EXPORT void CALL FBWrite(uint32 addr, uint32 size)
{
LOG("API WRAPPER:\t FBWrite")
}
// ???
EXPORT void CALL FBGetFrameBufferInfo(void *p)
{
LOG("API WRAPPER:\t FBGetFrameBufferInfo")
//FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
}
/* Simple Window code */
HINSTANCE inj_hModule; //Injected Modules Handle
//WndProc for the new window
LRESULT CALLBACK DLLWindowProc (HWND, UINT, WPARAM, LPARAM);
//Register our windows Class
BOOL RegisterDLLWindowClass(char szClassName[])
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof (WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DLLWindowProc;
wc.hInstance = inj_hModule;
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.lpszClassName = szClassName;
if (!RegisterClassEx (&wc))
return 0;
return 0;
}
//The new thread
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
MSG messages;
char *pString = (char *)(lpParam);
RegisterDLLWindowClass("InjectedDLLWindowClass");
hWnd_jabo = CreateWindowEx (0, "InjectedDLLWindowClass", pString, WS_OVERLAPPEDWINDOW, 300, 300, 400, 300, NULL, NULL,inj_hModule, NULL );
ShowWindow (hWnd_jabo, SW_SHOWNORMAL);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return 1;
}
//Our new windows proc
LRESULT CALLBACK DLLWindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call,LPVOID lpReserved)
{
if(ul_reason_for_call==DLL_PROCESS_ATTACH) {
inj_hModule = hModule;
window_thread = CreateThread(0, NULL, ThreadProc, (LPVOID)"Window Title", NULL, NULL);
}
return TRUE;
}