1265 строки
42 KiB
C++
1265 строки
42 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Name: dxview.cpp
|
|
//
|
|
// Desc: DirectX Capabilities Viewer (Main program)
|
|
//
|
|
// Copyright(c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
//
|
|
// https://go.microsoft.com/fwlink/?linkid=2136896
|
|
//-----------------------------------------------------------------------------
|
|
#include "dxview.h"
|
|
|
|
#include <objbase.h>
|
|
#include <stdio.h>
|
|
#include <strsafe.h>
|
|
#include <shlwapi.h>
|
|
|
|
// These are from d3d8types.h
|
|
#define D3DSHADER_VERSION_MAJOR(_Version) (((_Version)>>8)&0xFF)
|
|
#define D3DSHADER_VERSION_MINOR(_Version) (((_Version)>>0)&0xFF)
|
|
|
|
constexpr size_t c_maxPasteBuffer = 200;
|
|
constexpr size_t c_maxPrintLine = 128;
|
|
constexpr int c_tabStop = 52;
|
|
|
|
static_assert(c_tabStop >= c_DefNameLength, "print stop should be at least as long as the default name");
|
|
|
|
HINSTANCE g_hInstance = nullptr;
|
|
HWND g_hwndMain = nullptr;
|
|
CHAR g_strAppName[] = "DXView";
|
|
CHAR g_strClassName[] = "DXView";
|
|
CHAR g_strTitle[] = "DirectX Caps Viewer";
|
|
|
|
extern const char c_szYes[] = "Yes";
|
|
extern const char c_szNo[] = "No";
|
|
extern const char c_szCurrentMode[] = "Current Mode";
|
|
extern const char c_szNA[] = "n/a";
|
|
|
|
HWND g_hwndLV = nullptr; // List view
|
|
HWND g_hwndTV = nullptr; // Tree view
|
|
HIMAGELIST g_hImageList = nullptr;
|
|
HFONT g_hFont = nullptr;
|
|
int g_xPaneSplit;
|
|
int g_xHalfSplitWidth;
|
|
BOOL g_bSplitMove;
|
|
DWORD g_dwViewState;
|
|
DWORD g_dwView9Ex;
|
|
DWORD g_tmAveCharWidth;
|
|
extern BOOL g_PrintToFile;
|
|
extern TCHAR g_PrintToFilePath[MAX_PATH];
|
|
CHAR g_szClip[c_maxPasteBuffer];
|
|
TCHAR g_helpPath[MAX_PATH] = {};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Local function prototypes
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
BOOL DXView_OnCreate( HWND hwnd );
|
|
VOID DXView_OnCommand( HWND hwnd, WPARAM wParam );
|
|
VOID DXView_OnSize( HWND hwnd );
|
|
VOID DXView_OnTreeSelect( HWND hwndTV, NM_TREEVIEW* ptv );
|
|
VOID DXView_OnListViewDblClick( HWND hwndLV, NM_LISTVIEW* plv );
|
|
VOID DXView_Cleanup();
|
|
BOOL DXView_InitImageList();
|
|
BOOL DXView_OnPrint( HWND hWindow, HWND hTreeView, BOOL bPrintAll );
|
|
BOOL DXView_OnFile( HWND hWindow, HWND hTreeWnd,BOOL bPrintAll );
|
|
VOID CreateCopyMenu( VOID );
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// External function prototypes
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID DXGI_FillTree( HWND hwndTV );
|
|
VOID DXG_FillTree( HWND hwndTV );
|
|
VOID DD_FillTree( HWND hwndTV );
|
|
|
|
VOID DXGI_Init();
|
|
VOID DXG_Init();
|
|
VOID DD_Init();
|
|
|
|
VOID DXGI_CleanUp();
|
|
VOID DXG_CleanUp();
|
|
VOID DD_CleanUp();
|
|
|
|
BOOL DXG_Is9Ex();
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Int2Str()
|
|
// Desc: Get number as a string
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT Int2Str( _Out_z_cap_(nDestLen) LPTSTR strDest, UINT nDestLen, DWORD i )
|
|
{
|
|
*strDest = 0;
|
|
|
|
char strDec[2];
|
|
GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, strDec, 2 );
|
|
char strIn[32];
|
|
sprintf_s( strIn, sizeof(strIn), "%u",i );
|
|
|
|
char strOut[32];
|
|
if( 0 == GetNumberFormat( LOCALE_USER_DEFAULT, 0, strIn, nullptr, strOut, 32 ) )
|
|
{
|
|
strcpy_s( strDest, nDestLen, strIn );
|
|
return E_FAIL;
|
|
}
|
|
|
|
char * pstrDec = strrchr( strOut, strDec[0] );
|
|
if( pstrDec)
|
|
*pstrDec = '\0';
|
|
|
|
if( strcpy_s( strDest, nDestLen, strOut ) != 0)
|
|
{
|
|
*strDest = 0;
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT PrintStringValueLine(const char * szText, const char * szText2, PRINTCBINFO *lpInfo)
|
|
{
|
|
// Calculate Name and Value column x offsets
|
|
int xName = (lpInfo->dwCurrIndent * DEF_TAB_SIZE * lpInfo->dwCharWidth);
|
|
int xVal = xName + (c_tabStop * lpInfo->dwCharWidth);
|
|
int yLine = (lpInfo->dwCurrLine * lpInfo->dwLineHeight);
|
|
|
|
// Print name
|
|
char szBuff[c_maxPrintLine];
|
|
strcpy_s(szBuff, sizeof(szBuff), szText);
|
|
szBuff[c_maxPrintLine - 1] = '\0';
|
|
auto cchLen = static_cast<DWORD>(_tcslen(szText));
|
|
if( FAILED( PrintLine (xName, yLine, szBuff, cchLen, lpInfo) ) )
|
|
return E_FAIL;
|
|
|
|
// Print value
|
|
strcpy_s(szBuff, sizeof(szBuff), szText2);
|
|
szBuff[c_maxPrintLine - 1] = '\0';
|
|
cchLen = static_cast<DWORD>(_tcslen(szText2));
|
|
if( FAILED( PrintLine (xVal, yLine, szBuff, cchLen, lpInfo) ) )
|
|
return E_FAIL;
|
|
|
|
// Advance to next line on page
|
|
if( FAILED( PrintNextLine(lpInfo) ) )
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT PrintValueLine(const char * szText, DWORD dwValue, PRINTCBINFO *lpInfo)
|
|
{
|
|
char szBuff[c_maxPrintLine];
|
|
Int2Str(szBuff, c_maxPrintLine, dwValue);
|
|
return PrintStringValueLine( szText, szBuff, lpInfo );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT PrintHexValueLine(const char * szText, DWORD dwValue, PRINTCBINFO *lpInfo)
|
|
{
|
|
char szBuff[c_maxPrintLine];
|
|
sprintf_s( szBuff, sizeof(szBuff), "0x%08x", dwValue );
|
|
return PrintStringValueLine( szText, szBuff, lpInfo );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT PrintStringLine(const char * szText, PRINTCBINFO *lpInfo)
|
|
{
|
|
// Calculate Name and Value column x offsets
|
|
int xName = (lpInfo->dwCurrIndent * DEF_TAB_SIZE * lpInfo->dwCharWidth);
|
|
int yLine = (lpInfo->dwCurrLine * lpInfo->dwLineHeight);
|
|
|
|
// Print name
|
|
char szBuff[c_maxPrintLine];
|
|
strcpy_s(szBuff, sizeof(szBuff), szText);
|
|
szBuff[c_maxPrintLine - 1] = '\0';
|
|
auto cchLen = static_cast<DWORD>(_tcslen(szText));
|
|
if( FAILED( PrintLine (xName, yLine, szBuff, cchLen, lpInfo) ) )
|
|
return E_FAIL;
|
|
|
|
// Advance to next line on page
|
|
if( FAILED( PrintNextLine(lpInfo) ) )
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: WinMain
|
|
//-----------------------------------------------------------------------------
|
|
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance*/,
|
|
_In_ LPSTR /*strCmdLine*/, _In_ int /*nCmdShow*/)
|
|
{
|
|
g_hInstance = hInstance; // Store instance handle in our global variable
|
|
g_PrintToFilePath[0] = TEXT('\0');
|
|
|
|
// Initialize COM
|
|
HRESULT hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
|
|
if (FAILED(hr))
|
|
return 1;
|
|
|
|
// Init various DX components
|
|
DXGI_Init();
|
|
DXG_Init();
|
|
DD_Init();
|
|
|
|
// Register window class
|
|
WNDCLASS wc;
|
|
wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s).
|
|
wc.lpfnWndProc = (WNDPROC)WndProc; // Window Procedure
|
|
wc.cbClsExtra = 0; // No per-class extra data.
|
|
wc.cbWndExtra = 0; // No per-window extra data.
|
|
wc.hInstance = hInstance; // Owner of this class
|
|
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIRECTX)); // Icon name from .RC
|
|
wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_SPLIT));// Cursor
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); // Default color
|
|
wc.lpszMenuName = "Menu"; // Menu name from .RC
|
|
wc.lpszClassName = g_strClassName; // Name to register as
|
|
RegisterClass(&wc);
|
|
|
|
// Create a main window for this application instance.
|
|
g_hwndMain = CreateWindowEx(0, g_strClassName, g_strTitle, WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, DXView_WIDTH, DXView_HEIGHT,
|
|
nullptr, nullptr, hInstance, nullptr);
|
|
|
|
// If window could not be created, return "failure"
|
|
if (!g_hwndMain)
|
|
{
|
|
CoUninitialize();
|
|
return -1;
|
|
}
|
|
|
|
TCHAR* pszCmdLine = GetCommandLine();
|
|
// Skip past program name (first token in command line).
|
|
if (*pszCmdLine == TEXT('"')) // Check for and handle quoted program name
|
|
{
|
|
pszCmdLine++;
|
|
// Scan, and skip over, subsequent characters until another
|
|
// double-quote or a null is encountered
|
|
while (*pszCmdLine && (*pszCmdLine != TEXT('"')))
|
|
pszCmdLine++;
|
|
// If we stopped on a double-quote (usual case), skip over it.
|
|
if (*pszCmdLine == TEXT('"'))
|
|
pszCmdLine++;
|
|
}
|
|
else // First token wasn't a quote
|
|
{
|
|
while (*pszCmdLine > TEXT(' '))
|
|
pszCmdLine++;
|
|
}
|
|
|
|
// Skip past any white space preceeding the next token.
|
|
while (*pszCmdLine && (*pszCmdLine <= TEXT(' ')))
|
|
pszCmdLine++;
|
|
|
|
// Treat the rest of the command line as a filename to save the whole tree to
|
|
TCHAR* pstrSave = g_PrintToFilePath;
|
|
if (*pszCmdLine == TEXT('"')) // Check for and handle quoted program name
|
|
{
|
|
pszCmdLine++;
|
|
// Scan, and copy, subsequent characters until another
|
|
// double-quote or a null is encountered
|
|
while (*pszCmdLine && (*pszCmdLine != TEXT('"')))
|
|
*pstrSave++ = *pszCmdLine++;
|
|
// If we stopped on a double-quote (usual case), skip over it.
|
|
if (*pszCmdLine == TEXT('"'))
|
|
pszCmdLine++;
|
|
}
|
|
else // First token wasn't a quote
|
|
{
|
|
while (*pszCmdLine > TEXT(' '))
|
|
*pstrSave++ = *pszCmdLine++;
|
|
}
|
|
*pstrSave = TEXT('\0');
|
|
|
|
if (strlen(g_PrintToFilePath) > 0)
|
|
{
|
|
PostMessage(g_hwndMain, WM_COMMAND, IDM_PRINTWHOLETREETOFILE, 0);
|
|
PostMessage(g_hwndMain, WM_CLOSE, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// Make the window visible; update its client area; and return "success"
|
|
ShowWindow(g_hwndMain, SW_MAXIMIZE /*nCmdShow*/);
|
|
}
|
|
|
|
// Message pump
|
|
MSG msg;
|
|
while (GetMessage(&msg, nullptr, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
return (int)msg.wParam;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_CREATE:
|
|
return DXView_OnCreate(hWnd);
|
|
|
|
case WM_SIZE:
|
|
DXView_OnSize(hWnd);
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
g_bSplitMove = TRUE;
|
|
SetCapture(hWnd);
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
g_bSplitMove = FALSE;
|
|
ReleaseCapture();
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if (g_bSplitMove)
|
|
{
|
|
RECT rect;
|
|
// change the value from unsigned to signed
|
|
int x = (int)(short)LOWORD(lParam);
|
|
|
|
GetClientRect(hWnd, &rect);
|
|
if (rect.left > x)
|
|
{
|
|
x = rect.left;
|
|
}
|
|
else if (rect.right < x)
|
|
{
|
|
x = rect.right;
|
|
}
|
|
g_xPaneSplit = (x - g_xHalfSplitWidth);
|
|
DXView_OnSize(hWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
if (((NMHDR*)lParam)->hwndFrom == g_hwndTV)
|
|
{
|
|
if (((NMHDR*)lParam)->code == TVN_SELCHANGED)
|
|
DXView_OnTreeSelect(g_hwndTV, (NM_TREEVIEW*)lParam);
|
|
else if (((NMHDR*)lParam)->code == NM_RCLICK)
|
|
{
|
|
NMHDR* pnmhdr = (NMHDR*)lParam;
|
|
TVHITTESTINFO info;
|
|
GetCursorPos(&info.pt);
|
|
ScreenToClient(pnmhdr->hwndFrom, &info.pt);
|
|
TreeView_HitTest(pnmhdr->hwndFrom, &info);
|
|
if (info.flags & TVHT_ONITEMLABEL)
|
|
{
|
|
TVITEM tvitem;
|
|
tvitem.mask = TVIF_TEXT;
|
|
tvitem.hItem = info.hItem;
|
|
tvitem.pszText = g_szClip;
|
|
tvitem.cchTextMax = c_maxPasteBuffer;
|
|
TreeView_GetItem(g_hwndTV, &tvitem);
|
|
CreateCopyMenu();
|
|
}
|
|
}
|
|
else if (((NMHDR*)lParam)->code == TVN_KEYDOWN)
|
|
{
|
|
NMTVKEYDOWN* ptvkd = (LPNMTVKEYDOWN)lParam;
|
|
if (ptvkd->wVKey == VK_TAB)
|
|
SetFocus(g_hwndLV);
|
|
}
|
|
}
|
|
|
|
if (((NMHDR*)lParam)->hwndFrom == g_hwndLV)
|
|
{
|
|
if (((NMHDR*)lParam)->code == NM_RDBLCLK)
|
|
DXView_OnListViewDblClick(g_hwndLV, (NM_LISTVIEW*)lParam);
|
|
else if (((NMHDR*)lParam)->code == NM_RCLICK)
|
|
{
|
|
NMHDR* pnmhdr = (NMHDR*)lParam;
|
|
LVHITTESTINFO info;
|
|
GetCursorPos(&info.pt);
|
|
ScreenToClient(pnmhdr->hwndFrom, &info.pt);
|
|
ListView_SubItemHitTest(pnmhdr->hwndFrom, &info);
|
|
if (info.iItem >= 0)
|
|
{
|
|
ListView_GetItemText(g_hwndLV, info.iItem, info.iSubItem, g_szClip, c_maxPasteBuffer);
|
|
CreateCopyMenu();
|
|
}
|
|
}
|
|
else if (((NMHDR*)lParam)->code == LVN_KEYDOWN)
|
|
{
|
|
NMLVKEYDOWN* plvkd = (LPNMLVKEYDOWN)lParam;
|
|
if (plvkd->wVKey == VK_TAB)
|
|
SetFocus(g_hwndTV);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
SetFocus(g_hwndTV);
|
|
break;
|
|
|
|
case WM_COMMAND: // message: command from application menu
|
|
DXView_OnCommand(hWnd, wParam);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(hWnd);
|
|
return 0;
|
|
|
|
case WM_DESTROY: // message: window being destroyed
|
|
DXView_Cleanup(); // Free per item struct for all items
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
VOID CreateCopyMenu(VOID)
|
|
{
|
|
HMENU hPopupMenu = LoadMenu(nullptr, "POPUP");
|
|
if (!hPopupMenu)
|
|
return;
|
|
HMENU hMenu = GetSubMenu(hPopupMenu, 0);
|
|
if (!hMenu)
|
|
{
|
|
DestroyMenu(hPopupMenu);
|
|
return;
|
|
}
|
|
TCHAR szMenu[c_maxPasteBuffer];
|
|
GetMenuString(hMenu, IDM_COPY, szMenu, c_maxPasteBuffer, MF_BYCOMMAND);
|
|
|
|
TCHAR szMenuNew[c_maxPasteBuffer];
|
|
sprintf_s(szMenuNew, sizeof(szMenuNew), szMenu, g_szClip);
|
|
|
|
MENUITEMINFO mii = {};
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_TYPE;
|
|
mii.fType = MFT_STRING;
|
|
mii.dwTypeData = szMenuNew;
|
|
SetMenuItemInfo(hMenu, IDM_COPY, FALSE, &mii);
|
|
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, g_hwndMain, nullptr);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL DXView_OnCreate(HWND hWnd)
|
|
{
|
|
HDC hDC = GetDC(hWnd);
|
|
int PixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSX);
|
|
|
|
NONCLIENTMETRICS nmi = {};
|
|
nmi.cbSize = sizeof(nmi);
|
|
|
|
(void)SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nmi, 0);
|
|
g_hFont = CreateFontIndirect(&nmi.lfMessageFont);
|
|
|
|
SelectObject(hDC, g_hFont);
|
|
|
|
TEXTMETRIC tm = {};
|
|
GetTextMetrics(hDC, &tm);
|
|
g_tmAveCharWidth = tm.tmAveCharWidth;
|
|
ReleaseDC(hWnd, hDC);
|
|
|
|
// Initialize global data
|
|
g_dwViewState = IDM_VIEWALL;
|
|
g_xPaneSplit = PixelsPerInch * 12 / 4;
|
|
g_xHalfSplitWidth = GetSystemMetrics(SM_CXSIZEFRAME) / 2;
|
|
|
|
g_dwView9Ex = DXG_Is9Ex() ? 1 : 0;
|
|
CheckMenuItem(GetMenu(hWnd), IDM_VIEW9EX, MF_BYCOMMAND | (g_dwView9Ex ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
// Make sure that the common control library read to rock
|
|
InitCommonControls();
|
|
|
|
CheckMenuItem(GetMenu(hWnd), g_dwViewState, MF_BYCOMMAND | MF_CHECKED);
|
|
|
|
// Create the list view window.
|
|
g_hwndLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
|
|
WS_VISIBLE | WS_CHILD | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL,
|
|
0, 0, 0, 0, hWnd, (HMENU)IDC_LV, g_hInstance, nullptr);
|
|
ListView_SetExtendedListViewStyleEx(g_hwndLV, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
|
|
|
|
// create the tree view window.
|
|
g_hwndTV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
|
|
WS_VISIBLE | WS_CHILD | TVS_HASLINES |
|
|
TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS,
|
|
0, 0, 0, 0, hWnd, (HMENU)IDC_TV, g_hInstance, nullptr);
|
|
|
|
// create our image list.
|
|
DXView_InitImageList();
|
|
|
|
// Add DXStuff stuff to the tree
|
|
// view.
|
|
DXGI_FillTree(g_hwndTV);
|
|
DXG_FillTree(g_hwndTV);
|
|
DD_FillTree(g_hwndTV);
|
|
|
|
TreeView_SelectItem(g_hwndTV, TreeView_GetRoot(g_hwndTV));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void AddCapsToTV(HTREEITEM hRoot, CAPDEFS* pcds, LPARAM lParam1)
|
|
{
|
|
BOOL bRoot = TRUE; // the first one is always a root
|
|
|
|
HTREEITEM hParent[20];
|
|
hParent[0] = hRoot;
|
|
|
|
int level = 0;
|
|
const char* name;
|
|
while ((name = pcds->strName) != nullptr)
|
|
{
|
|
if (name[0] == '-')
|
|
{
|
|
level--;
|
|
if (level < 0)
|
|
level = 0;
|
|
name++;
|
|
}
|
|
|
|
if (name[0] == '+')
|
|
{
|
|
bRoot = TRUE;
|
|
name++;
|
|
}
|
|
|
|
if (name[0] && (level >= 0 && level < 20))
|
|
{
|
|
HTREEITEM hTree = TVAddNode(hParent[level], name, bRoot, IDI_CAPS,
|
|
pcds->fnDisplayCallback, lParam1,
|
|
pcds->lParam2);
|
|
|
|
if (bRoot)
|
|
{
|
|
level++;
|
|
if (level >= 20)
|
|
level = 19;
|
|
hParent[level] = hTree;
|
|
bRoot = FALSE;
|
|
}
|
|
}
|
|
|
|
pcds++; // Get next Cap bit definition
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AddMoreCapsToLV is like AddCapsToLV, except it doesn't add the
|
|
// column headers like AddCapsToLV does.
|
|
void AddMoreCapsToLV(CAPDEF* pcd, LPVOID pv)
|
|
{
|
|
TCHAR szBuff[64];
|
|
|
|
while (pcd->strName && *pcd->strName)
|
|
{
|
|
if (!g_dwView9Ex && (pcd->dwCapsFlags & DXV_9EXCAP))
|
|
{
|
|
pcd++; // Get next Cap bit definition
|
|
continue;
|
|
}
|
|
|
|
auto dwValue = *reinterpret_cast<DWORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
|
|
switch (pcd->dwFlag)
|
|
{
|
|
case 0:
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
Int2Str(szBuff, 64, dwValue);
|
|
LVAddText(g_hwndLV, 1, "%s", szBuff);
|
|
break;
|
|
case 0xFFFFFFFF: // Hex
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
LVAddText(g_hwndLV, 1, "0x%08X", dwValue);
|
|
break;
|
|
case 0xEFFFFFFF: // Shader Version
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
LVAddText(g_hwndLV, 1, "%d.%0d", D3DSHADER_VERSION_MAJOR(dwValue), D3DSHADER_VERSION_MINOR(dwValue));
|
|
break;
|
|
case 0xBFFFFFFF: // FLOAT Support for new DX6 "D3DVALUE" values in D3DDeviceDesc
|
|
{
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
auto fValue = *reinterpret_cast<float*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
LVAddText(g_hwndLV, 1, "%G", fValue);
|
|
break;
|
|
}
|
|
case 0x7FFFFFFF: // HEX Support for new DX6 "WORD" values in D3DDeviceDesc
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
dwValue = *reinterpret_cast<WORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
LVAddText(g_hwndLV, 1, "0x%04X", dwValue);
|
|
break;
|
|
case 0x3FFFFFFF: // VAL Support for new DX6 "WORD" values in D3DDeviceDesc
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
dwValue = *reinterpret_cast<WORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
Int2Str(szBuff, 64, dwValue);
|
|
LVAddText(g_hwndLV, 1, "%s", szBuff);
|
|
break;
|
|
case 0x1FFFFFFF: // "-1 == unlimited"
|
|
LVAddText(g_hwndLV, 0, "%s", pcd->strName);
|
|
if (dwValue == 0xFFFFFFFF)
|
|
{
|
|
LVAddText(g_hwndLV, 1, "Unlimited");
|
|
}
|
|
else
|
|
{
|
|
Int2Str(szBuff, 64, dwValue);
|
|
LVAddText(g_hwndLV, 1, "%s", szBuff);
|
|
}
|
|
break;
|
|
case 0x0fffffff: // Mask with 0xffff
|
|
{
|
|
LVAddText(g_hwndLV, 0, pcd->strName);
|
|
dwValue = (*reinterpret_cast<DWORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset)) & 0xffff;
|
|
Int2Str(szBuff, 64, dwValue);
|
|
LVAddText(g_hwndLV, 1, "%s", szBuff);
|
|
}
|
|
break;
|
|
default:
|
|
if (pcd->dwFlag & dwValue)
|
|
{
|
|
LVAddText(g_hwndLV, 0, pcd->strName);
|
|
LVAddText(g_hwndLV, 1, c_szYes);
|
|
}
|
|
else if (g_dwViewState == IDM_VIEWALL)
|
|
{
|
|
LVAddText(g_hwndLV, 0, pcd->strName);
|
|
LVAddText(g_hwndLV, 1, c_szNo);
|
|
}
|
|
break;
|
|
}
|
|
pcd++; // Get next Cap bit definition
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AddColsToLV adds the column headers but no data.
|
|
void AddColsToLV(void)
|
|
{
|
|
LVAddColumn(g_hwndLV, 0, "Name", c_DefNameLength);
|
|
LVAddColumn(g_hwndLV, 1, "Value", 10);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
VOID AddCapsToLV(CAPDEF *pcd, LPVOID pv)
|
|
{
|
|
AddColsToLV();
|
|
AddMoreCapsToLV(pcd, pv);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT PrintCapsToDC(CAPDEF* pcd, LPVOID pv, PRINTCBINFO* lpInfo)
|
|
{
|
|
DWORD cchLen;
|
|
TCHAR szValue[100];
|
|
|
|
// Check Parameters
|
|
if ((!pcd) || (!lpInfo))
|
|
return E_FAIL;
|
|
|
|
// Calculate Name and Value column x offsets
|
|
int xName = (lpInfo->dwCurrIndent * DEF_TAB_SIZE * lpInfo->dwCharWidth);
|
|
int xVal = xName + (c_tabStop * lpInfo->dwCharWidth);
|
|
|
|
while (pcd->strName && *pcd->strName)
|
|
{
|
|
if (!g_dwView9Ex && (pcd->dwCapsFlags & DXV_9EXCAP))
|
|
{
|
|
pcd++; // Get next Cap bit definition
|
|
continue;
|
|
}
|
|
|
|
auto dwValue = *reinterpret_cast<DWORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
int yLine = lpInfo->dwCurrLine * lpInfo->dwLineHeight;
|
|
|
|
if (pcd->dwFlag)
|
|
{
|
|
switch (pcd->dwFlag)
|
|
{
|
|
case 0xFFFFFFFF: // Hex
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print value in hex
|
|
sprintf_s(szValue, sizeof(szValue), "0x%08X", dwValue);
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
|
|
case 0xEFFFFFFF: // Shader Version
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print version
|
|
sprintf_s(szValue, sizeof(szValue), "%u.%0u", D3DSHADER_VERSION_MAJOR(dwValue), D3DSHADER_VERSION_MINOR(dwValue));
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
|
|
case 0xBFFFFFFF: // FLOAT Support for new DX6 "D3DVALUE" values in D3DDeviceDesc
|
|
{
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print value
|
|
auto fValue = *reinterpret_cast<float*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
sprintf_s(szValue, sizeof(szValue), "%G", fValue);
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
}
|
|
|
|
case 0x7FFFFFFF: // HEX Support for new DX6 "WORD" values in D3DDeviceDesc
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print value
|
|
dwValue = *reinterpret_cast<WORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
sprintf_s(szValue, sizeof(szValue), "0x%04X", dwValue);
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
|
|
case 0x3FFFFFFF: // VAL Support for new DX6 "WORD" values in D3DDeviceDesc
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print value
|
|
dwValue = *reinterpret_cast<WORD*>(static_cast<BYTE*>(pv) + pcd->dwOffset);
|
|
*szValue = 0;
|
|
Int2Str(szValue, 100, dwValue);
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
|
|
case 0x1FFFFFFF: // "-1 == unlimited"
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
// Print value
|
|
*szValue = 0;
|
|
if (dwValue == 0xFFFFFFFF)
|
|
strcpy_s(szValue, sizeof(szValue), "Unlimited");
|
|
else
|
|
Int2Str(szValue, 100, dwValue);
|
|
if (FAILED(PrintLine(xVal, yLine, szValue, strlen(szValue), lpInfo)))
|
|
return E_FAIL;
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
break;
|
|
|
|
default:
|
|
if (pcd->dwFlag & dwValue)
|
|
{
|
|
// Print Name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Print Yes in value column
|
|
cchLen = static_cast<DWORD>(_tcslen(c_szYes));
|
|
if (FAILED(PrintLine(xVal, yLine, c_szYes, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
}
|
|
else if (g_dwViewState == IDM_VIEWALL)
|
|
{
|
|
// Print name
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, pcd->strName, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Print No in value column
|
|
cchLen = static_cast<DWORD>(_tcslen(c_szNo));
|
|
if (FAILED(PrintLine(xVal, yLine, c_szNo, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char szBuff[c_maxPrintLine];
|
|
|
|
// Print name
|
|
sprintf_s(szBuff, sizeof(szBuff), pcd->strName, "test");
|
|
cchLen = static_cast<DWORD>(_tcslen(pcd->strName));
|
|
if (FAILED(PrintLine(xName, yLine, szBuff, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Print value
|
|
Int2Str(szBuff, c_maxPrintLine, dwValue);
|
|
cchLen = static_cast<DWORD>(_tcslen(szBuff));
|
|
if (FAILED(PrintLine(xVal, yLine, szBuff, cchLen, lpInfo)))
|
|
return E_FAIL;
|
|
|
|
// Advance to next line on page
|
|
if (FAILED(PrintNextLine(lpInfo)))
|
|
return E_FAIL;
|
|
}
|
|
|
|
pcd++; // Get next Cap bit definition
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void DXView_OnTreeSelect(HWND /*hwndTV*/, NM_TREEVIEW* ptv)
|
|
{
|
|
SendMessage(g_hwndLV, WM_SETREDRAW, FALSE, 0);
|
|
LVDeleteAllItems(g_hwndLV);
|
|
LVAddColumn(g_hwndLV, 0, "", 0);
|
|
|
|
NODEINFO* pni = nullptr;
|
|
if (!ptv)
|
|
{
|
|
TV_ITEM tvi = {};
|
|
// get lParam of current tree node
|
|
tvi.hItem = TreeView_GetSelection(g_hwndTV);
|
|
tvi.mask = TVIF_PARAM;
|
|
TreeView_GetItem(g_hwndTV, &tvi);
|
|
pni = (NODEINFO*)tvi.lParam;
|
|
}
|
|
else
|
|
{
|
|
pni = (NODEINFO*)ptv->itemNew.lParam;
|
|
}
|
|
|
|
if (pni && pni->fnDisplayCallback)
|
|
{
|
|
if (pni->bUseLParam3)
|
|
((DISPLAYCALLBACKEX)(pni->fnDisplayCallback))(pni->lParam1, pni->lParam2, pni->lParam3, nullptr);
|
|
else
|
|
pni->fnDisplayCallback(pni->lParam1, pni->lParam2, nullptr);
|
|
}
|
|
|
|
ListView_SetItemState(g_hwndLV, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
|
|
|
|
SendMessage(g_hwndLV, WM_SETREDRAW, TRUE, 0);
|
|
InvalidateRect(g_hwndLV, nullptr, TRUE);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void DXView_OnListViewDblClick(HWND hwndLV, NM_LISTVIEW *plv)
|
|
{
|
|
LV_ITEM lvi = {};
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = plv->iItem;
|
|
ListView_GetItem(hwndLV, &lvi);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void DXView_OnCommand(HWND hWnd, WPARAM wParam)
|
|
{
|
|
HMENU hMenu;
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDM_VIEWAVAIL:
|
|
case IDM_VIEWALL:
|
|
hMenu = GetMenu(hWnd);
|
|
CheckMenuItem(hMenu, g_dwViewState, MF_BYCOMMAND | MF_UNCHECKED);
|
|
g_dwViewState = LOWORD(wParam);
|
|
CheckMenuItem(hMenu, g_dwViewState, MF_BYCOMMAND | MF_CHECKED);
|
|
DXView_OnTreeSelect(g_hwndTV, nullptr);
|
|
break;
|
|
|
|
case IDM_VIEW9EX:
|
|
hMenu = GetMenu(hWnd);
|
|
g_dwView9Ex = !g_dwView9Ex;
|
|
CheckMenuItem(hMenu, IDM_VIEW9EX, MF_BYCOMMAND | (g_dwView9Ex ? MF_CHECKED : MF_UNCHECKED));
|
|
DXView_OnTreeSelect(g_hwndTV, nullptr);
|
|
break;
|
|
|
|
case IDM_PRINTWHOLETREETOPRINTER:
|
|
g_PrintToFile = FALSE;
|
|
DXView_OnPrint(hWnd, g_hwndTV, TRUE);
|
|
break;
|
|
|
|
case IDM_PRINTSUBTREETOPRINTER:
|
|
g_PrintToFile = FALSE;
|
|
DXView_OnPrint(hWnd, g_hwndTV, FALSE);
|
|
break;
|
|
|
|
case IDM_PRINTWHOLETREETOFILE:
|
|
g_PrintToFile = TRUE;
|
|
DXView_OnFile(hWnd, g_hwndTV, TRUE);
|
|
break;
|
|
|
|
case IDM_PRINTSUBTREETOFILE:
|
|
g_PrintToFile = TRUE;
|
|
DXView_OnFile(hWnd, g_hwndTV, FALSE);
|
|
break;
|
|
|
|
case IDM_COPY:
|
|
{
|
|
// Put g_szClip into the clipboard
|
|
UINT GlobalSize = static_cast<UINT>(strlen(g_szClip) + 1);
|
|
HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, GlobalSize);
|
|
if (hGlobal)
|
|
{
|
|
VOID* pGlobal = GlobalLock(hGlobal);
|
|
if (pGlobal)
|
|
{
|
|
strcpy_s((CHAR*)pGlobal, GlobalSize, g_szClip);
|
|
GlobalUnlock(hGlobal);
|
|
OpenClipboard(g_hwndMain);
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_TEXT, hGlobal);
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_ABOUT:
|
|
DialogBox(g_hInstance, "About", hWnd, (DLGPROC)About);
|
|
break;
|
|
|
|
case IDM_EXIT:
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void DXView_Cleanup()
|
|
{
|
|
DXGI_CleanUp();
|
|
|
|
DXG_CleanUp();
|
|
|
|
DD_CleanUp();
|
|
|
|
if (g_hImageList)
|
|
ImageList_Destroy(g_hImageList);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
BOOL DXView_InitImageList()
|
|
{
|
|
if (g_hImageList)
|
|
return TRUE;
|
|
|
|
int cxSmIcon = GetSystemMetrics(SM_CXSMICON);
|
|
int cySmIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
// First, create the image list that is needed.
|
|
if ((g_hImageList = ImageList_Create(cxSmIcon, cySmIcon, TRUE, IDI_LASTIMAGE - IDI_FIRSTIMAGE, 10)) == nullptr)
|
|
return(FALSE);
|
|
|
|
//
|
|
// Initialize the image list with all of the icons that we'll be using
|
|
// Once set, send its handle to all interested child windows.
|
|
//
|
|
for (UINT Index = IDI_FIRSTIMAGE; Index <= IDI_LASTIMAGE; Index++)
|
|
{
|
|
auto hIcon = reinterpret_cast<HICON>(LoadImage(g_hInstance, MAKEINTRESOURCE(Index), IMAGE_ICON, cxSmIcon, cySmIcon, 0));
|
|
if (hIcon)
|
|
{
|
|
ImageList_AddIcon(g_hImageList, hIcon);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
}
|
|
|
|
TreeView_SetImageList(g_hwndTV, g_hImageList, TVSIL_NORMAL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: About()
|
|
// Desc: Process about box
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK About(HWND hDlg, UINT msg, WPARAM wParam, LPARAM /*lParam*/)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
VS_FIXEDFILEINFO* pVersion = nullptr;
|
|
TCHAR strFmt[500];
|
|
GetWindowText(GetDlgItem(hDlg, IDC_VERSION), strFmt, 500);
|
|
|
|
TCHAR szFile[MAX_PATH];
|
|
*szFile = 0;
|
|
GetModuleFileName(nullptr, szFile, MAX_PATH);
|
|
|
|
DWORD dwHandle;
|
|
UINT cb = GetFileVersionInfoSize(szFile, &dwHandle/*ignored*/);
|
|
if (cb > 0)
|
|
{
|
|
BYTE FileVersionBuffer[1024];
|
|
|
|
if (cb > sizeof(FileVersionBuffer))
|
|
cb = sizeof(FileVersionBuffer);
|
|
|
|
if (GetFileVersionInfo(szFile, 0, cb, FileVersionBuffer))
|
|
{
|
|
pVersion = nullptr;
|
|
if (VerQueryValue(FileVersionBuffer, "\\", (VOID**)&pVersion, &cb)
|
|
&& pVersion != nullptr)
|
|
{
|
|
TCHAR strVersion[100];
|
|
sprintf_s(strVersion, sizeof(strVersion), "%u.%02u.%02u.%04u",
|
|
HIWORD(pVersion->dwFileVersionMS),
|
|
LOWORD(pVersion->dwFileVersionMS),
|
|
HIWORD(pVersion->dwFileVersionLS),
|
|
LOWORD(pVersion->dwFileVersionLS));
|
|
|
|
TCHAR str[500];
|
|
sprintf_s(str, sizeof(str), strFmt, strVersion);
|
|
SetWindowText(GetDlgItem(hDlg, IDC_VERSION), str);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note: The warning text is static, but it must be set via code,
|
|
// not in the .rc file, because it is > 256 characters (warning RC4206).
|
|
{
|
|
const TCHAR* pstrWarning = TEXT("Warning: This computer program is protected by copyright law and international treaties. Unauthorized reproduction or distribution of this program, or any portion of it, may result in severe civil and criminal penalties, and will be prosecuted to the maximum extent possible under the law.");
|
|
SetWindowText(GetDlgItem(hDlg, IDC_WARNING), pstrWarning);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
|
{
|
|
EndDialog(hDlg, TRUE); // Exit the dialog
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DXView_OnSize()
|
|
// Desc: Called whenever the size of the app window has changed or the size
|
|
// of its child controls should be adjusted.
|
|
//-----------------------------------------------------------------------------
|
|
VOID DXView_OnSize(HWND hWnd)
|
|
{
|
|
if (IsIconic(hWnd))
|
|
return;
|
|
|
|
HDWP hDWP;
|
|
if ((hDWP = BeginDeferWindowPos(2)) != nullptr)
|
|
{
|
|
// Data structure used when calling GetEffectiveClientRect (which takes into
|
|
// account space taken up by the toolbars/status bars). First half of the
|
|
// pair is zero when at the end of the list, second half is the control id.
|
|
int s_EffectiveClientRectData[] =
|
|
{
|
|
1, 0, // For the menu bar, but is unused
|
|
0, 0 // First zero marks end of data
|
|
};
|
|
|
|
RECT ClientRect;
|
|
GetEffectiveClientRect(hWnd, &ClientRect, s_EffectiveClientRectData);
|
|
int Height = ClientRect.bottom - ClientRect.top;
|
|
|
|
HWND hKeyTreeWnd = g_hwndTV;
|
|
|
|
DeferWindowPos(hDWP, hKeyTreeWnd, nullptr, 0, ClientRect.top, g_xPaneSplit,
|
|
Height, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
int x = g_xPaneSplit + GetSystemMetrics(SM_CXSIZEFRAME);
|
|
int dx = ClientRect.right - ClientRect.left - x;
|
|
|
|
HWND hValueListWnd = g_hwndLV;
|
|
|
|
DeferWindowPos(hDWP, hValueListWnd, nullptr, x, ClientRect.top, dx, Height,
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
EndDeferWindowPos(hDWP);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void LVAddColumn(HWND hwndLV, int i, const char* name, int width)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
while (ListView_DeleteColumn(hwndLV, 0))
|
|
;
|
|
}
|
|
|
|
LV_COLUMN col = {};
|
|
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
|
|
col.fmt = LVCFMT_LEFT;
|
|
col.pszText = (char*)name;
|
|
col.cx = width * g_tmAveCharWidth;
|
|
ListView_InsertColumn(hwndLV, i, &col);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int LVAddText(HWND hwndLV, int col, const char* sz, ...)
|
|
{
|
|
va_list vl;
|
|
va_start(vl, sz);
|
|
|
|
char ach[c_maxPrintLine];
|
|
vsprintf_s(ach, sizeof(ach), sz, vl);
|
|
ach[c_maxPrintLine - 1] = '\0';
|
|
|
|
LV_ITEM lvi = {};
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.pszText = ach;
|
|
|
|
if (col == 0)
|
|
{
|
|
lvi.iItem = 0x7FFF;
|
|
lvi.iSubItem = 0;
|
|
va_end(vl);
|
|
return ListView_InsertItem(hwndLV, &lvi);
|
|
}
|
|
else
|
|
{
|
|
lvi.iItem = ListView_GetItemCount(hwndLV) - 1;
|
|
lvi.iSubItem = col;
|
|
va_end(vl);
|
|
return ListView_SetItem(hwndLV, &lvi);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void LVDeleteAllItems(HWND hwndLV)
|
|
{
|
|
ListView_DeleteAllItems(hwndLV);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HTREEITEM TVAddNode(HTREEITEM hParent, LPCSTR strText, BOOL fKids,
|
|
int iImage, DISPLAYCALLBACK fnDisplayCallback, LPARAM lParam1,
|
|
LPARAM lParam2)
|
|
{
|
|
auto pni = reinterpret_cast<NODEINFO*>(LocalAlloc(LPTR, sizeof(NODEINFO)));
|
|
if (!pni)
|
|
return nullptr;
|
|
|
|
pni->bUseLParam3 = FALSE;
|
|
pni->lParam1 = lParam1;
|
|
pni->lParam2 = lParam2;
|
|
pni->lParam3 = 0;
|
|
pni->fnDisplayCallback = fnDisplayCallback;
|
|
|
|
// Add Node to treeview
|
|
TV_INSERTSTRUCT tvi = {};
|
|
tvi.hParent = hParent;
|
|
tvi.hInsertAfter = TVI_LAST;
|
|
tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
|
|
TVIF_PARAM | TVIF_CHILDREN;
|
|
tvi.item.iImage = iImage - IDI_FIRSTIMAGE;
|
|
tvi.item.iSelectedImage = iImage - IDI_FIRSTIMAGE;
|
|
tvi.item.lParam = (LPARAM)pni;
|
|
tvi.item.cChildren = fKids;
|
|
tvi.item.pszText = (LPSTR)strText;
|
|
|
|
return TreeView_InsertItem(g_hwndTV, &tvi);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HTREEITEM TVAddNodeEx(HTREEITEM hParent, LPCSTR strText, BOOL fKids,
|
|
int iImage, DISPLAYCALLBACKEX fnDisplayCallback, LPARAM lParam1,
|
|
LPARAM lParam2, LPARAM lParam3)
|
|
{
|
|
auto pni = reinterpret_cast<NODEINFO*>(LocalAlloc(LPTR, sizeof(NODEINFO)));
|
|
if (!pni)
|
|
return nullptr;
|
|
|
|
pni->bUseLParam3 = TRUE;
|
|
pni->lParam1 = lParam1;
|
|
pni->lParam2 = lParam2;
|
|
pni->lParam3 = lParam3;
|
|
pni->fnDisplayCallback = reinterpret_cast<DISPLAYCALLBACK>(fnDisplayCallback);
|
|
|
|
// Add Node to treeview
|
|
TV_INSERTSTRUCT tvi = {};
|
|
tvi.hParent = hParent;
|
|
tvi.hInsertAfter = TVI_LAST;
|
|
tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
|
|
TVIF_PARAM | TVIF_CHILDREN;
|
|
tvi.item.iImage = iImage - IDI_FIRSTIMAGE;
|
|
tvi.item.iSelectedImage = iImage - IDI_FIRSTIMAGE;
|
|
tvi.item.lParam = (LPARAM)pni;
|
|
tvi.item.cChildren = fKids;
|
|
tvi.item.pszText = (LPSTR)strText;
|
|
|
|
return TreeView_InsertItem(g_hwndTV, &tvi);
|
|
}
|