|
|
/*****************************************************************************
* * diquick.c * * DirectInput quick test * *****************************************************************************/
#include "diquick.h"
/*****************************************************************************
* * GetCheckedRadioButton * * Return the ID of the one that is checked. * * If nothing is checked, we return idFirst. * *****************************************************************************/
UINT EXTERNAL GetCheckedRadioButton(HWND hdlg, UINT idFirst, UINT idLast) { for (; idFirst < idLast; idLast--) { if (IsDlgButtonChecked(hdlg, idLast)) { return idLast; } } return idLast; }
/*****************************************************************************
* * MessageBoxV * * Format a message and display a message box. * *****************************************************************************/
int __cdecl MessageBoxV(HWND hdlg, UINT ids, ...) { va_list ap; TCHAR tszStr[256] = {0}; TCHAR tszBuf[1024] = {0};
LoadString(g_hinst, ids, tszStr, cA(tszStr)); va_start(ap, ids); #ifdef WIN95
{ char *psz = NULL; char szDfs[1024]={0}; strcpy(szDfs,tszStr); // make a local copy of format string
while (psz = strstr(szDfs,"%p")) // find each %p
*(psz+1) = 'x'; // replace each %p with %x
wvsprintf(tszBuf, szDfs, ap); // use the local format string
} #else
{ wvsprintf(tszBuf, tszStr, ap); } #endif
va_end(ap); return MessageBox(hdlg, tszBuf, TEXT("DirectInput QuickTest"), MB_OK);
}
/*****************************************************************************
* * ThreadFailHres * * Tell the parent that a thread failed to start, and display * an error message with an HRESULT code. * *****************************************************************************/
int EXTERNAL ThreadFailHres(HWND hdlg, UINT ids, HRESULT hres) { SendNotifyMessage(hdlg, WM_THREADSTARTED, 0, 0); SendNotifyMessage(hdlg, WM_CHILDEXIT, 0, 0);
return MessageBoxV(hdlg, ids, hres); }
/*****************************************************************************
* * RecalcCursor * * If the cursor is over the window, force a new WM_SETCUSOR. * *****************************************************************************/
void EXTERNAL RecalcCursor(HWND hdlg) { POINT pt; HWND hwnd; GetCursorPos(&pt); hwnd = WindowFromPoint(pt); if( (hwnd != NULL) && (hwnd == hdlg || IsChild(hdlg, hwnd)) ) { SetCursorPos(pt.x, pt.y); } }
/*****************************************************************************
* * ModalVtbl * * Things that tell you about the modal gizmo. * *****************************************************************************/
typedef struct MODALVTBL { BOOL (WINAPI *IsDialogMessage)(HWND, LPMSG); BOOL (WINAPI *IsAlive)(HWND); void (INTERNAL *SendIdle)(HWND); } MODALVTBL, *PMODALVTBL;
/*****************************************************************************
* * ModalLoop * * Spin waiting for the dialog box to die. * * WEIRDNESS! We send the WM_SELFENTERIDLE message to the dialog box * rather than to the owner. This avoids inter-thread sendmessage goo. * * Don't re-post the quit message if we get one. The purpose of the * quit message is to break the modal loop. * *****************************************************************************/
int EXTERNAL ModalLoop(HWND hwndOwner, HWND hdlg, PMODALVTBL pvtbl) { if (hdlg) { BOOL fSentIdle = 0; while (pvtbl->IsAlive(hdlg)) { MSG msg; if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { fSentIdle = 0; if (msg.message == WM_QUIT) { break; } if (!pvtbl->IsDialogMessage(hdlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else { if (fSentIdle) { WaitMessage(); } else { fSentIdle = 1; pvtbl->SendIdle(hdlg); } } } if (IsWindow(hdlg)) { DestroyWindow(hdlg); } }
SendNotifyMessage(hwndOwner, WM_CHILDEXIT, 0, 0);
return 0; }
/*****************************************************************************
* * SendDlgIdle * * Send the fake idle message. * *****************************************************************************/
void INTERNAL SendDlgIdle(HWND hdlg) { SendMessage(hdlg, WM_SELFENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hdlg); }
/*****************************************************************************
* * SemimodalDialogBoxParam * * Create a non-modal dialog box, then spin waiting for it to die. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
MODALVTBL c_dlgvtbl = { IsDialogMessage, IsWindow, SendDlgIdle, };
#pragma END_CONST_DATA
int EXTERNAL SemimodalDialogBoxParam(UINT idd, HWND hwndOwner, DLGPROC dp, LPARAM lp) { return ModalLoop(hwndOwner, CreateDialogParam(g_hinst, (LPVOID)(UINT_PTR)idd, hwndOwner, dp, lp), &c_dlgvtbl);
}
/*****************************************************************************
* * IsPrshtMessage * *****************************************************************************/
BOOL WINAPI IsPrshtMessage(HWND hdlg, LPMSG pmsg) { return PropSheet_IsDialogMessage(hdlg, pmsg); }
/*****************************************************************************
* * IsPrshtAlive * *****************************************************************************/
BOOL WINAPI IsPrshtAlive(HWND hdlg) { return (BOOL)(INT_PTR)PropSheet_GetCurrentPageHwnd(hdlg); }
/*****************************************************************************
* * SendPrshtIdle * * Send the fake idle message. * *****************************************************************************/
void INTERNAL SendPrshtIdle(HWND hdlg) { hdlg = PropSheet_GetCurrentPageHwnd(hdlg); SendDlgIdle(hdlg); }
/*****************************************************************************
* * SemimodalPropertySheet * * Create a non-modal property sheet, then spin waiting for it to die. * * We nuke the Cancel and Apply buttons, change OK to Close, and move * the button into the corner. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
MODALVTBL c_pshvtbl = { IsPrshtMessage, IsPrshtAlive, SendPrshtIdle, };
#pragma END_CONST_DATA
int EXTERNAL SemimodalPropertySheet(HWND hwndOwner, LPPROPSHEETHEADER ppsh) { HWND hdlg = (HWND)PropertySheet(ppsh); if ( hdlg && hdlg != (HWND)-1 ) { RECT rcOk, rcCancel; HWND hwnd; PropSheet_CancelToClose(hdlg);
/* Slide the Close button to where the Cancel button is */ hwnd = GetDlgItem(hdlg, IDCANCEL); GetWindowRect(hwnd, &rcCancel); ShowWindow(hwnd, SW_HIDE);
hwnd = GetDlgItem(hdlg, IDOK); GetWindowRect(hwnd, &rcOk);
rcOk.left += rcCancel.right - rcOk.right; ScreenToClient(hdlg, (LPPOINT)&rcOk); SetWindowPos(hwnd, 0, rcOk.left, rcOk.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
return ModalLoop(hwndOwner, hdlg, &c_pshvtbl); } else { return -1; }
}
/*****************************************************************************
* * CreateDI * * Create an IDirectInput interface in the appropriate manner. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
/*
* This table must be in sync with the CDIFL_* values. */ const IID *c_rgiidDI[] = { &IID_IDirectInput8A, /* CDIFL_DI8 */ &IID_IDirectInput8W, /* CDIFL_UNICODE | CDIFL_DI8 */ };
#pragma END_CONST_DATA
STDMETHODIMP CreateDI(BOOL fOle, UINT flCreate, PV ppvOut) { HRESULT hres; if (fOle) { const IID *piid = c_rgiidDI[flCreate]; hres = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, piid, ppvOut); if (SUCCEEDED(hres)) { LPDIRECTINPUT pdi = *(PPV)ppvOut; hres = pdi->lpVtbl->Initialize(pdi, g_hinst, g_dwDIVer); if (FAILED(hres)) { pdi->lpVtbl->Release(pdi); *(PPV)ppvOut = 0; } } } else { /* Create via DI */ if (flCreate & CDIFL_UNICODE) { hres = DirectInput8Create(g_hinst, g_dwDIVer, &IID_IDirectInput8W, ppvOut, 0); } else { hres = DirectInput8Create(g_hinst, g_dwDIVer, &IID_IDirectInput8A, ppvOut, 0); }
/*
* If necessary, QI for the 2 interface. */ if (flCreate & CDIFL_DI2) { LPDIRECTINPUT pdi = *(PPV)ppvOut; hres = pdi->lpVtbl->QueryInterface(pdi, c_rgiidDI[flCreate], ppvOut); pdi->lpVtbl->Release(pdi); } }
return hres; }
/*****************************************************************************
* * GetDwordProperty * * Get a DWORD property from an IDirectInputDevice. * *****************************************************************************/
STDMETHODIMP GetDwordProperty(IDirectInputDevice8 *pdid, PCGUID pguid, LPDWORD pdw) { HRESULT hres; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE;
hres = IDirectInputDevice8_GetProperty(pdid, pguid, &dipdw.diph); if (SUCCEEDED(hres)) { *pdw = dipdw.dwData; }
return hres; }
/*****************************************************************************
* * SetDwordProperty * * Set a DWORD property into an IDirectInputDevice. * *****************************************************************************/
STDMETHODIMP SetDwordProperty(IDirectInputDevice8 *pdid, PCGUID pguid, DWORD dw) { DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = dw;
return IDirectInputDevice8_SetProperty(pdid, pguid, &dipdw.diph); }
/*****************************************************************************
* * ConvertString * * Convert a string from whatever character set it is in into * the preferred character set (ANSI or UNICODE, whichever we * were compiled with). * * This is used to convert strings received from DirectInput * into something we like. * *****************************************************************************/
void EXTERNAL ConvertString(BOOL fWide, LPCVOID pvIn, LPTSTR ptszOut, UINT ctchOut) { if (fTchar(fWide)) { lstrcpyn(ptszOut, pvIn, ctchOut); } else { #ifdef UNICODE
MultiByteToWideChar(CP_ACP, 0, pvIn, -1, ptszOut, ctchOut); #else
WideCharToMultiByte(CP_ACP, 0, pvIn, -1, ptszOut, ctchOut, 0, 0); #endif
} }
/*****************************************************************************
* * UnconvertString * * Convert a string from the preferred character set * (ANSI or UNICODE, whichever we were compiled with) * into the specified character set. * * This is used to convert strings generated from dialogs * into something that DirectInput will like. * *****************************************************************************/
void EXTERNAL UnconvertString(BOOL fWide, LPCTSTR ptszIn, LPVOID pvOut, UINT ctchOut) { if (fTchar(fWide)) { lstrcpyn(pvOut, ptszIn, ctchOut); } else { #ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, ptszIn, -1, pvOut, ctchOut, 0, 0); #else
MultiByteToWideChar(CP_ACP, 0, ptszIn, -1, pvOut, ctchOut); #endif
} }
/*****************************************************************************
* * ConvertDoi * * Convert the pvDoi into the local character set. * *****************************************************************************/
void EXTERNAL ConvertDoi(PDEVDLGINFO pddi, LPDIDEVICEOBJECTINSTANCE pdoi, LPCVOID pvDoi) { if (IsUnicodeDidc(pddi->didcItf)) { LPCDIDEVICEOBJECTINSTANCEW pdoiW = pvDoi; ConvertString(TRUE, pdoiW->tszName, pdoi->tszName, cA(pdoi->tszName)); pdoi->guidType = pdoiW->guidType; pdoi->dwOfs = pdoiW->dwOfs; pdoi->dwType = pdoiW->dwType; pdoi->dwFlags = pdoiW->dwFlags; pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3); pdoi->wReportId = pdoiW->wReportId;
if (pdoiW->dwSize > cbX(DIDEVICEOBJECTINSTANCE_DX3W)) { pdoi->dwFFMaxForce = pdoiW->dwFFMaxForce; pdoi->dwFFForceResolution = pdoiW->dwFFForceResolution; pdoi->wCollectionNumber = pdoiW->wCollectionNumber; pdoi->wDesignatorIndex = pdoiW->wDesignatorIndex; pdoi->wUsagePage = pdoiW->wUsagePage; pdoi->wUsage = pdoiW->wUsage; pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE); }
} else { LPCDIDEVICEOBJECTINSTANCEA pdoiA = pvDoi; ConvertString(FALSE, pdoiA->tszName, pdoi->tszName, cA(pdoi->tszName)); pdoi->guidType = pdoiA->guidType; pdoi->dwOfs = pdoiA->dwOfs; pdoi->dwType = pdoiA->dwType; pdoi->dwFlags = pdoiA->dwFlags; pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3); pdoi->wReportId = pdoiA->wReportId;
if (pdoiA->dwSize > cbX(DIDEVICEOBJECTINSTANCE_DX3A)) { pdoi->dwFFMaxForce = pdoiA->dwFFMaxForce; pdoi->dwFFForceResolution = pdoiA->dwFFForceResolution; pdoi->wCollectionNumber = pdoiA->wCollectionNumber; pdoi->wDesignatorIndex = pdoiA->wDesignatorIndex; pdoi->wUsagePage = pdoiA->wUsagePage; pdoi->wUsage = pdoiA->wUsage; pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE); } } }
/*****************************************************************************
* * GetObjectInfo * * Do a GetObjectInfo with character set conversion. * *****************************************************************************/
HRESULT EXTERNAL GetObjectInfo(PDEVDLGINFO pddi, LPDIDEVICEOBJECTINSTANCE pdoi, DWORD dwObj, DWORD dwHow) { HRESULT hres; union { DIDEVICEOBJECTINSTANCEA doiA; DIDEVICEOBJECTINSTANCEW doiW; } u;
if (IsUnicodeDidc(pddi->didcItf)) { if (g_dwDIVer > 0x0300) { u.doiW.dwSize = cbX(u.doiW); } else { u.doiW.dwSize = cbX(DIDEVICEOBJECTINSTANCE_DX3W); } } else { if (g_dwDIVer > 0x0300) { u.doiA.dwSize = cbX(u.doiA); } else { u.doiA.dwSize = cbX(DIDEVICEOBJECTINSTANCE_DX3A); } }
hres = IDirectInputDevice8_GetObjectInfo(pddi->pdid, (PV)&u, dwObj, dwHow);
if (SUCCEEDED(hres)) { ConvertDoi(pddi, pdoi, &u); hres = S_OK; }
return hres; }
/*****************************************************************************
* * ConvertDdi * * Convert the pvDdi into the local character set. * *****************************************************************************/
void EXTERNAL ConvertDdi(PDEVDLGINFO pddi, LPDIDEVICEINSTANCE pinst, LPCVOID pvDdi) { if (IsUnicodeDidc(pddi->didcItf)) { LPCDIDEVICEINSTANCEW pinstW = pvDdi;
ConvertString(TRUE, pinstW->tszInstanceName, pinst->tszInstanceName, cA(pinst->tszInstanceName)); ConvertString(TRUE, pinstW->tszProductName, pinst->tszProductName, cA(pinst->tszProductName));
pinst->guidInstance = pinstW->guidInstance; pinst->guidProduct = pinstW->guidProduct; pinst->dwDevType = pinstW->dwDevType; pinst->dwSize = sizeof(DIDEVICEINSTANCE_DX3);
if (pinstW->dwSize > cbX(DIDEVICEINSTANCE_DX3W)) { pinst->guidFFDriver = pinstW->guidFFDriver; pinst->wUsagePage = pinstW->wUsagePage; pinst->wUsage = pinstW->wUsage; pinst->dwSize = sizeof(DIDEVICEINSTANCE); }
} else { LPCDIDEVICEINSTANCEA pinstA = pvDdi;
ConvertString(FALSE, pinstA->tszInstanceName, pinst->tszInstanceName, cA(pinst->tszInstanceName)); ConvertString(FALSE, pinstA->tszProductName, pinst->tszProductName, cA(pinst->tszProductName));
pinst->guidInstance = pinstA->guidInstance; pinst->guidProduct = pinstA->guidProduct; pinst->dwDevType = pinstA->dwDevType; pinst->dwSize = sizeof(DIDEVICEINSTANCE_DX3);
if (pinstA->dwSize > cbX(DIDEVICEINSTANCE_DX3A)) { pinst->guidFFDriver = pinstA->guidFFDriver; pinst->wUsagePage = pinstA->wUsagePage; pinst->wUsage = pinstA->wUsage; pinst->dwSize = sizeof(DIDEVICEINSTANCE); }
} }
/*****************************************************************************
* * GetDeviceInfo * * Do a GetDeviceInfo with character set conversion. * *****************************************************************************/
HRESULT EXTERNAL GetDeviceInfo(PDEVDLGINFO pddi, LPDIDEVICEINSTANCE pinst) { HRESULT hres; union { DIDEVICEINSTANCEA ddiA; DIDEVICEINSTANCEW ddiW; } u;
if (IsUnicodeDidc(pddi->didcItf)) { if (g_dwDIVer > 0x0300) { u.ddiW.dwSize = cbX(u.ddiW); } else { u.ddiW.dwSize = cbX(DIDEVICEINSTANCE_DX3W); } } else { if (g_dwDIVer > 0x0300) { u.ddiA.dwSize = cbX(u.ddiA); } else { u.ddiA.dwSize = cbX(DIDEVICEINSTANCE_DX3A); } }
hres = IDirectInputDevice8_GetDeviceInfo(pddi->pdid, (PV)&u);
if (SUCCEEDED(hres)) { ConvertDdi(pddi, pinst, &u); hres = S_OK; }
return hres; }
/*****************************************************************************
* * ConvertEffi * * Convert the pvEffi into the local character set. * *****************************************************************************/
void EXTERNAL ConvertEffi(PDEVDLGINFO pddi, LPDIEFFECTINFO pei, LPCVOID pvEffi) { LPCDIEFFECTINFOW peiW = pvEffi; LPCDIEFFECTINFOA peiA = pvEffi; LPCVOID pvStr;
if (IsUnicodeDidc(pddi->didcItf)) { pvStr = peiW->tszName; } else { pvStr = peiA->tszName; }
ConvertString(IsUnicodeDidc(pddi->didcItf), pvStr, pei->tszName, cA(pei->tszName));
pei->guid = peiA->guid; pei->dwEffType = peiA->dwEffType; pei->dwStaticParams = peiA->dwStaticParams; pei->dwDynamicParams= peiA->dwDynamicParams; }
/*****************************************************************************
* * GetEffectInfo * * Do a GetEffectInfo with character set conversion. * *****************************************************************************/
HRESULT EXTERNAL GetEffectInfo(PDEVDLGINFO pddi, LPDIEFFECTINFO pei, REFGUID rguid) { HRESULT hres; union { DIEFFECTINFOA deiA; DIEFFECTINFOW deiW; } u;
if (IsUnicodeDidc(pddi->didcItf)) { u.deiW.dwSize = cbX(u.deiW); } else { u.deiA.dwSize = cbX(u.deiA); }
hres = IDirectInputDevice8_GetEffectInfo(pddi->pdid, (PV)&u, rguid);
if (SUCCEEDED(hres)) { ConvertEffi(pddi, pei, &u); hres = S_OK; }
return hres; }
/*****************************************************************************
* * StringFromGuid * *****************************************************************************/
void EXTERNAL StringFromGuid(LPTSTR ptsz, REFGUID rclsid) { wsprintf(ptsz, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"), rclsid->Data1, rclsid->Data2, rclsid->Data3, rclsid->Data4[0], rclsid->Data4[1], rclsid->Data4[2], rclsid->Data4[3], rclsid->Data4[4], rclsid->Data4[5], rclsid->Data4[6], rclsid->Data4[7]); }
/*****************************************************************************
* * MapGUID * * Convert a GUID to a string, using a friendly name if possible. * * ptszBuf must be large enough to hold a stringized GUID. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
extern GUID GUID_HIDClass;
GUID GUID_Null;
GUIDMAP c_rggm[] = { { &GUID_XAxis, "GUID_XAxis", }, { &GUID_YAxis, "GUID_YAxis", }, { &GUID_ZAxis, "GUID_ZAxis", }, { &GUID_RxAxis, "GUID_RxAxis", }, { &GUID_RyAxis, "GUID_RyAxis", }, { &GUID_RzAxis, "GUID_RzAxis", }, { &GUID_Slider, "GUID_Slider", }, { &GUID_Button, "GUID_Button", }, { &GUID_Key, "GUID_Key", }, { &GUID_POV, "GUID_POV", }, { &GUID_Unknown, "GUID_Unknown", }, { &GUID_SysMouse, "GUID_SysMouse" }, { &GUID_SysKeyboard, "GUID_SysKeyboard" }, { &GUID_Joystick, "GUID_Joystick", }, { &GUID_Unknown, "GUID_Unknown", }, { &GUID_ConstantForce,"GUID_ConstantForce", }, { &GUID_RampForce, "GUID_RampForce", }, { &GUID_Square, "GUID_Square", }, { &GUID_Sine, "GUID_Sine", }, { &GUID_Triangle, "GUID_Triangle", }, { &GUID_SawtoothUp, "GUID_SawtoothUp", }, { &GUID_SawtoothDown, "GUID_SawtoothDown", }, { &GUID_Spring, "GUID_Spring", }, { &GUID_Damper, "GUID_Damper", }, { &GUID_Inertia, "GUID_Inertia", }, { &GUID_Friction, "GUID_Friction", }, { &GUID_CustomForce, "GUID_CustomForce", }, { &GUID_Null, "GUID_NULL", }, { &GUID_HIDClass, "GUID_HIDClass", }, };
LPCTSTR EXTERNAL MapGUID(REFGUID rguid, LPTSTR ptszBuf) { int igm;
for (igm = 0; igm < cA(c_rggm); igm++) { if (IsEqualGUID(rguid, c_rggm[igm].rguid)) { return c_rggm[igm].ptsz; } }
StringFromGuid(ptszBuf, rguid);
return ptszBuf; }
/*****************************************************************************
* * ProbeDinputVersion * * Snoop around to determine what version of DirectInput is available. * *****************************************************************************/
void INTERNAL ProbeDinputVersion(void) { IDirectInput *pdi; HRESULT hres;
/*
* For safety's sake, start with DirectX 3.0 and gradually * work upwards. */ g_dwDIVer = DIRECTINPUT_VERSION; #if 0
hres = DirectInput8Create(g_hinst, 0x0300, &IID_IDirectInput8, (PVOID)&pdi, 0);
if (SUCCEEDED(hres)) {
/*
* Probe upward to see what version of DirectX is supported. */ if (SUCCEEDED(IDirectInput_Initialize(pdi, g_hinst, DIRECTINPUT_VERSION))) { g_dwDIVer = DIRECTINPUT_VERSION;
}
IDirectInput_Release(pdi);
} #endif
}
/*****************************************************************************
* * Globals * *****************************************************************************/
HINSTANCE g_hinst; HCURSOR g_hcurWait; HCURSOR g_hcurStarting; DWORD g_dwDIVer; #ifdef DEBUG
TCHAR g_tszInvalid[128]; #endif
/*****************************************************************************
* * Entry * *****************************************************************************/
void __cdecl Entry(void) { g_hcurWait = LoadCursor(0, IDC_WAIT); g_hcurStarting = LoadCursor(0, IDC_APPSTARTING); g_hinst = GetModuleHandle(0);
#ifdef DEBUG
LoadString(g_hinst, IDS_INVALID, g_tszInvalid, cA(g_tszInvalid)); #endif
Checklist_Init(); ProbeDinputVersion(); if (SUCCEEDED(CoInitialize(0))) { DialogBox(g_hinst, MAKEINTRESOURCE(IDD_MAIN), 0, Diq_DlgProc); CoUninitialize(); }
Checklist_Term(); ExitProcess(0); }
|