diff options
Diffstat (limited to 'Src/Winamp/setup/spage_assoc.cpp')
-rw-r--r-- | Src/Winamp/setup/spage_assoc.cpp | 1069 |
1 files changed, 1069 insertions, 0 deletions
diff --git a/Src/Winamp/setup/spage_assoc.cpp b/Src/Winamp/setup/spage_assoc.cpp new file mode 100644 index 00000000..937284d6 --- /dev/null +++ b/Src/Winamp/setup/spage_assoc.cpp @@ -0,0 +1,1069 @@ +#define APSTUDIO_READONLY_SYMBOLS +#include "main.h" +#include "api.h" +#include "./spage_assoc.h" +#include "./setup_resource.h" +#include "../nu/ns_wc.h" +#include "../nu/AutoWide.h" +#include "./langutil.h" +#include "./setupcommon.h" +#include "../playlist/svc_playlisthandler.h" +#include <api/service/waservicefactorybase.h> +#include "../Agave/URIHandler/svc_urihandler.h" +#include <api/service/waservicefactory.h> +#include <commctrl.h> + +#define MF_SELECTED 0x0001 +#define MF_TYPE_MASK 0xFF00 +#define MF_TYPE_REREAD 0xFF +#define MF_TYPE_UNKNOWN 0x00 +#define MF_TYPE_AUDIO 0x01 +#define MF_TYPE_VIDEO 0x02 +#define MF_TYPE_PLAYLIST 0x03 +#define MF_TYPE_AUXILIARY 0x04 + +#define ID_REGISTERCD ((TYPE_CATEGORIES_NUM) + 1) +#define ID_REGISTERAGENT ((TYPE_CATEGORIES_NUM) + 2) + +#define SET_TYPE(_val, _type) ((_val) = ((_val) & ~MF_TYPE_MASK) | ((_type) << 8)) +#define GET_TYPE(_val) ((_val) >> 8) +#define IS_NEEDREREAD(_val) GET_TYPE((_val), MF_TYPE_REREAD) +#define IS_SELECTED(_val) (MF_SELECTED & (_val)) +#define INITMETA( _type, _selected) ((WORD)(((_type) << 8) | ((_selected) ? MF_SELECTED : 0x0000))) + +static wchar_t szAuxExt[] = L"wsz\0wal\0wlz\0"; + +static LRESULT WINAPI TreeViewProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static BOOL IsAgentScheduled(void) +{ + HKEY hKey = NULL; + BOOL bActive(FALSE); + WCHAR szAgent[MAX_PATH*2] = {0}; + DWORD cb = sizeof(szAgent); + + if (ERROR_SUCCESS != RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey)) + return FALSE; + if (ERROR_SUCCESS != RegQueryValueExW(hKey, L"WinampAgent", NULL, NULL, (BYTE*)szAgent, &cb)) + szAgent[0] = 0x00; + RegCloseKey(hKey); + + if (*szAgent) + { + WCHAR szPath[MAX_PATH*2] = {0}; + GetModuleFileNameW(NULL, szPath, sizeof(szPath)/sizeof(wchar_t)); + PathUnquoteSpacesW(szAgent); + PathRemoveFileSpecW(szAgent); + PathRemoveFileSpecW(szPath); + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + bActive = (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, szPath, -1, szAgent, -1)); + } + + return bActive; +} + +static BOOL IsAgentExist(void) +{ + wchar_t szAgent[MAX_PATH] = {0}; + if (0 == GetModuleFileNameW(hMainInstance, szAgent, sizeof(szAgent)/sizeof(wchar_t))) + return FALSE; + + PathRemoveFileSpecW(szAgent); + if (NULL == PathCombineW(szAgent, szAgent, L"winampa.exe")) + return FALSE; + + return (FALSE != PathFileExistsW(szAgent)); +} + +static BOOL RefreshIcons(void) +{ + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL); + return TRUE; +} + +static void RegisterProtocols() +{ + if (config_no_registry) + return; + + wchar_t winampexe[MAX_PATH] = {0}; + GetModuleFileNameW(hMainInstance, winampexe, MAX_PATH); + + WCHAR szApplication[256] = {0}; + INT r = MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, NULL, 0); + if (r > ARRAYSIZE(szApplication) || 0 == r) + return; + if (0 == MultiByteToWideCharSZ(CP_ACP, 0, app_name, -1, szApplication, ARRAYSIZE(szApplication))) + return; + + if (NULL != WASABI_API_SVC) + { + for(size_t i =0;;i++) + { + waServiceFactory *sf = WASABI_API_SVC->service_enumService(svc_urihandler::getServiceType(), i); + if (NULL == sf) break; + + svc_urihandler *handler = (svc_urihandler *)sf->getInterface(); + if (NULL != handler) + { + WCHAR szName[128] = {0}, szDesc[256] = {0}; + for (size_t k = 0; ;k++) + { + INT ret = handler->EnumProtocols(k, szName, ARRAYSIZE(szName), szDesc, ARRAYSIZE(szDesc)); + if (0 != ret) + break; + + if (0 == handler->RegisterProtocol(szName, winampexe)) + { + IFileTypeRegistrar *registrar = 0; + if (GetRegistrar(®istrar, true) == 0 && registrar) + { + registrar->RegisterMediaPlayerProtocol(szName, szApplication); + registrar->Release(); + } + } + } + sf->releaseInterface(handler); + } + } + } +} + +setup_page_assoc::setup_page_assoc() : ref(1), hwnd(NULL), pszTypes(NULL), pMeta(NULL), bRegCD(FALSE), bAgent(FALSE), bExplorerMenu(TRUE) +{ + ZeroMemory(expanded, sizeof(expanded)); + ZeroMemory(szTopExt, sizeof(szTopExt)); + ZeroMemory(szCaretExt, sizeof(szCaretExt)); +} + +setup_page_assoc::~setup_page_assoc() +{ + if (pszTypes) + { + free(pszTypes); + pszTypes = NULL; + } + if (pMeta) + { + free(pMeta); + pMeta = NULL; + } +} + +size_t setup_page_assoc::AddRef() +{ + return ++ref; +} + +size_t setup_page_assoc::Release() +{ + if (1 == ref) + { + delete(this); + return 0; + } + return --ref; +} + +HRESULT setup_page_assoc::GetName(bool bShort, const wchar_t **pszName) +{ + if (bShort) + { + static wchar_t szShortName[32] = {0}; + *pszName = (*szShortName) ? szShortName : getStringW(IDS_PAGE_ASSOCIATIONS, szShortName, sizeof(szShortName)/sizeof(wchar_t)); + } + else + { + static wchar_t szLongName[64] = {0}; + *pszName = (*szLongName) ? szLongName : getStringW(IDS_PAGE_ASSOCIATIONS_LONG, szLongName, sizeof(szLongName)/sizeof(wchar_t)); + } + return S_OK; +} + +HRESULT setup_page_assoc::Save(HWND hwndText) +{ + HRESULT hr(S_OK); + WORD *pm; + wchar_t ext_list[16384] = {0}, *p = 0, *pe = ext_list; + BOOL bFirst(TRUE); + size_t len = ARRAYSIZE(ext_list); + + // make sure that we honour the agent setting even if no settings changed + // this allows the agent to be restarted correctly after a normal upgrade + if (bAgent && IsAgentExist()) + config_agent_add(); + else + config_agent_remove(); + + // temporary: always enumerate and register protocols + RegisterProtocols(); + + if (S_FALSE == IsDirty()) return S_OK; + + if (!pszTypes) return S_FALSE; + + config_setup_filetypes(0); + + for(pm = pMeta, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, pm++) + { + config_register_capability(p, 0); + config_register(p, IS_SELECTED(*pm)); + if (IS_SELECTED(*pm) && (S_OK == hr) && GET_TYPE(*pm) != MF_TYPE_AUXILIARY) + { + if (!len) { hr = S_FALSE; continue; } + if (!bFirst) + { + pe[0] = L':'; + pe++; + len--; + } + else bFirst = FALSE; + if (S_OK != StringCchCopyExW(pe, len, p, &pe, &len, STRSAFE_IGNORE_NULLS)) hr = S_FALSE; + } + } + if (S_OK == hr) _w_sW("config_extlist", ext_list); + + config_regcdplayer(bRegCD, 0); + (bExplorerMenu) ? config_adddircontext(0) : config_removedircontext(0); + + config_registermediaplayer(1); + + WritePrivateProfileStringW(L"Jump To File Extra", L"newIconLib", L"refresh", INI_FILE); + RefreshIcons(); + + return hr; +} + +static BOOL IsFirstSetup() +{ + wchar_t szVer[512] = {0}; + if (0 == GetPrivateProfileIntW(L"WinampReg", L"IsFirstInst", 1, INI_FILE)) return FALSE; + + GetPrivateProfileStringW(L"Winamp", L"config_extlist", L"", szVer, 512, INI_FILE); + if (*szVer) return FALSE; + + GetPrivateProfileStringW(L"WinampReg", L"WAVer", L"", szVer, 512, INI_FILE); + return (!*szVer || CSTR_EQUAL != CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), + NORM_IGNORECASE, szVer, -1, AutoWide(APP_VERSION), -1)); +} + +static wchar_t *BuildExtensionString(WORD **ppMeta, BOOL bFirstSetup) +{ + INT cWA(0), cPL(0), cAux(0), lWA(0), lPL(0), lAux(0); + wchar_t *pszType, *pWAExt = in_getextlistW(), *pPLExt, *p; + + if (pWAExt) + { + for(p = pWAExt; *p != 0; cWA++, p += lstrlenW(p) + 1); + lWA = (INT)(p - pWAExt); + } + + if (playlistManager) + { + size_t playlistEnum = 0; + const wchar_t *playlistExt=0; + while (NULL != (playlistExt = playlistManager->EnumExtension(playlistEnum++))) { lPL += (lstrlenW(playlistExt) + 1); cPL++; } + lPL += 2; + } + + for(p = szAuxExt; *p != 0; cAux++, p += lstrlenW(p) + 1); + lAux = (INT)(p - szAuxExt); + + pszType = (wchar_t*)calloc((lWA + lPL + lAux + 1), sizeof(wchar_t)); + if (ppMeta) + { + *ppMeta = (WORD*)calloc((cWA + cPL + cAux), sizeof(WORD)); + } + + if (pszType) + { + if (pWAExt) CopyMemory(pszType, pWAExt, lWA*sizeof(wchar_t)); + pPLExt = pszType + lWA; + p = pPLExt; + if (playlistManager) + { + size_t playlistEnum=0; + const wchar_t *playlistExt=0; + while (lPL > 0 && NULL != (playlistExt = playlistManager->EnumExtension(playlistEnum++))) + { + int c = lstrlenW(playlistExt) + 1; + lstrcpynW(p, playlistExt, c); + if (c) + { + p += c; + lPL -= c; + } + } + if (lPL > 1) *p = 0x00; + } + CopyMemory(p, szAuxExt, lAux*sizeof(wchar_t)); + *(p+lAux)=0; + } + + if(ppMeta && *ppMeta) + { + int i; + WORD *pm = *ppMeta; + p = pszType; + for (i = 0; i < cWA; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_REREAD, ((!bFirstSetup) ? config_isregistered(p) : 1)); + for (i = 0; i < cPL; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_PLAYLIST, ((!bFirstSetup) ? config_isregistered(p) : 1)); + for (i = 0; i < cAux; i++, pm++, p += lstrlenW(p) + 1) *pm = INITMETA(MF_TYPE_AUXILIARY, ((!bFirstSetup) ? config_isregistered(p) : 1)); + } + + if (pWAExt) GlobalFree(pWAExt); + + return pszType; +} + +static BOOL GetPLExtensionName(LPCWSTR pszExt, LPWSTR pszDest, INT cchDest) +{ + BOOL result(FALSE); + int n(0); + waServiceFactory *sf = 0; + LPCWSTR ext; + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + + while (NULL != (sf = WASABI_API_SVC->service_enumService(WaSvc::PLAYLISTHANDLER, n++))) + { + svc_playlisthandler * handler = static_cast<svc_playlisthandler *>(sf->getInterface()); + if (handler) + { + int k(0); + while (NULL != (ext = handler->EnumerateExtensions(k++))) + { + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, ext, -1)) + { + result = (S_OK == StringCchCopyW(pszDest, cchDest, handler->GetName())); + if (result && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"M3U8", -1)) // ugly... + result = (S_OK == StringCchCatW(pszDest, cchDest, L" (Unicode)")); + break; + } + } + sf->releaseInterface(handler); + } + } + return result; +} + +static BOOL GetAuxExtensionName(LPCWSTR pszExt, LPWSTR pszDest, INT cchDest) +{ + BOOL result(FALSE); + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wal", -1)) + result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_SKIN_MODERN, NULL, 0))); + else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wsz", -1)) + result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_SKIN_CLASSIC, NULL, 0))); + else if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszExt, -1, L"wlz", -1)) + result = (S_OK == StringCchCopyW(pszDest, cchDest, getStringW(IDS_WINAMP_LANG_PACK, NULL, 0))); + return result; +} + +static BOOL GetExtensionName(LPCWSTR pszFile, INT type, LPWSTR pszDest, INT cchDest) +{ + switch(type) + { + case MF_TYPE_AUDIO: + case MF_TYPE_VIDEO: + return in_get_extended_fileinfoW(pszFile, L"family", pszDest, cchDest); + case MF_TYPE_PLAYLIST: + { + const wchar_t *pszExt = PathFindExtensionW(pszFile); + return (L'.' == *pszExt && 0x00 != *(++pszExt)) ? GetPLExtensionName(pszExt, pszDest, cchDest) : FALSE; + } + case MF_TYPE_AUXILIARY: + { + const wchar_t *pszExt = PathFindExtensionW(pszFile); + return (L'.' == *pszExt && 0x00 != *(++pszExt)) ? GetAuxExtensionName(pszExt, pszDest, cchDest) : FALSE; + } + } + return FALSE; +} + +HRESULT setup_page_assoc::Revert(void) +{ + HRESULT hr(S_OK); + + if (pszTypes) + { + free(pszTypes); + pszTypes = NULL; + } + + if (pMeta) + { + free(pMeta); + pMeta = NULL; + } + + BOOL firstSetup = IsFirstSetup(); + pszTypes = BuildExtensionString(&pMeta, firstSetup); + + ZeroMemory(expanded, sizeof(expanded)); + ZeroMemory(szTopExt, sizeof(szTopExt)); + ZeroMemory(szCaretExt, sizeof(szCaretExt)); + + bRegCD = (firstSetup) ? TRUE : config_iscdplayer(); + bAgent = (FALSE != IsAgentExist()) ? ((firstSetup) ? FALSE : IsAgentScheduled()) : FALSE; + bExplorerMenu = (firstSetup) ? TRUE : config_isdircontext(); + + if (hwnd) UpdateUI(); + return hr; +} + +HRESULT setup_page_assoc::IsDirty(void) +{ + if (IsFirstSetup()) return S_OK; + + HRESULT hr(S_FALSE); + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + wchar_t *pszOrigTypes = BuildExtensionString(NULL, TRUE), *p; + if ((!pszOrigTypes && pszTypes) || (pszOrigTypes && !pszTypes)) + { + if (pszOrigTypes) free(pszOrigTypes); + return S_OK; + } + else if (!pszOrigTypes && !pszTypes) return S_FALSE; + + INT cr = CompareStringW(lcid, NORM_IGNORECASE, pszTypes, -1, pszOrigTypes, -1); + if (0 == cr) hr = E_UNEXPECTED; + else if (CSTR_EQUAL == cr) + { + WORD *pm; + for(pm = pMeta, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, pm++) + { + if ((MF_SELECTED & *pm) != (BYTE)config_isregistered(p)) { hr = S_OK; break; } + } + } + else hr = S_OK; + + if (pszOrigTypes) free(pszOrigTypes); + + if (S_FALSE == hr && bRegCD != config_iscdplayer()) hr = S_OK; + if (S_FALSE == hr && bAgent != (IsAgentExist() && IsAgentScheduled())) hr = S_OK; + if (S_FALSE == hr && bExplorerMenu != config_isdircontext()) hr = S_OK; + + return hr; +} + +HRESULT setup_page_assoc::Validate(void) +{ + return S_OK; +} + +HRESULT setup_page_assoc::CreateView(HWND hwndParent, HWND *phwnd) +{ + *phwnd = WACreateDialogParam(MAKEINTRESOURCEW((!IsWin8() ? IDD_SETUP_PAGE_ASSOC : IDD_SETUP_PAGE_ASSOC_WIN8)), hwndParent, ::DialogProc, (LPARAM)this); + return S_OK; +} + +void setup_page_assoc::UpdateUI(void) +{ + TVINSERTSTRUCTW is = {0}; + WORD *pm; + HTREEITEM hBranch[TYPE_CATEGORIES_NUM], hFirst(NULL), hCaret(NULL), hItem; + INT sBranch[TYPE_CATEGORIES_NUM] = {0}; + INT ids[TYPE_CATEGORIES_NUM] = {IDS_FILETYPE_UNKNOWN, IDS_FILETYPE_AUDIO, IDS_FILETYPE_VIDEO, IDS_FILETYPE_PLAYLIST, IDS_FILETYPE_AUXILIARY}; + INT i; + + wchar_t szText[MAX_PATH] = {0}, buf[MAX_PATH] = {0}, buf2[MAX_PATH] = {0}, *p, *test; + if (!hwnd || !IsWindow(hwnd)) return; + + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + + HWND hwndTree = GetDlgItem(hwnd,IDC_TREE_TYPES); + SendMessageW(hwndTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); + if (!pszTypes) return; + + for (i = 0; i < ARRAYSIZE(hBranch); i++) + { + hBranch[i] = NULL; + sBranch[i] = -1; + } + + INT len = ARRAYSIZE(buf); + StringCchCopyW(buf, len, L"test."); + test = buf + lstrlenW(buf); + len -= (INT)(test - buf); + + SendMessageW(hwndTree, WM_SETREDRAW, FALSE, 0L); + + is.hInsertAfter = TVI_LAST; + is.item.mask = TVIF_STATE | TVIF_CHILDREN | TVIF_TEXT | TVIF_PARAM; + is.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED; + for(i = 0, pm = pMeta, p = pszTypes; *p != 0 && *(p+1) != 0; pm++, p += lstrlenW(p) + 1, i++) + { + StringCchCopyW(test, len, p); + OutputDebugStringW(test); + OutputDebugStringW(L"\r\n"); + if (MF_TYPE_REREAD == GET_TYPE(*pm)) + { + if (!in_get_extended_fileinfoW(buf, L"type", buf2, MAX_PATH)) + ZeroMemory(buf2, sizeof(buf2)); + + *pm = *pm & 0x00FF; + switch(buf2[0]) + { + case L'0': SET_TYPE(*pm, MF_TYPE_AUDIO); break; + case L'1': SET_TYPE(*pm, MF_TYPE_VIDEO); break; + } + } + + INT index = GET_TYPE(*pm); + if (!hBranch[index]) + { + is.hInsertAfter = TVI_SORT; + is.hParent = TVI_ROOT; + is.item.cChildren = 1; + is.item.state = INDEXTOSTATEIMAGEMASK(1) | ((expanded[index]) ? TVIS_EXPANDED : 0); + is.item.pszText = getStringW(ids[index], NULL, 0); + is.item.lParam = -(index + 1); + hBranch[index] = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is); + is.item.cChildren = 0; + is.hInsertAfter = TVI_LAST; + + wchar_t t[32] = {0}; + StringCchPrintfW(t, ARRAYSIZE(t), L"#%d", index + 1); + if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szTopExt, -1)) hFirst = hBranch[index]; + if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szCaretExt, -1)) hCaret = hBranch[index]; + } + + is.hParent = hBranch[index]; + + if (MF_SELECTED & *pm) + { + if (-1 == sBranch[index]) sBranch[index] = 1; + else if (0 == sBranch[index]) sBranch[index] = 2; + } + else + { + if (-1 == sBranch[index]) sBranch[index] = 0; + else if (1 == sBranch[index]) sBranch[index] = 2; + } + + lstrcpynW(szText, p, MAX_PATH); + INT count = lstrlenW(szText); + CharUpperW(szText); + wchar_t szName[MAX_PATH] = {0}; + if (GetExtensionName(buf, GET_TYPE(*pm), szName, MAX_PATH)) + { + if (count) StringCchCatW(szText, MAX_PATH, L"\t"); + StringCchCatW(szText, MAX_PATH, szName); + } + + is.item.pszText = szText; + is.item.lParam = (LPARAM)i; + is.item.state = INDEXTOSTATEIMAGEMASK((MF_SELECTED & *pm)?2:1); + + hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is); + + if (hItem) + { + if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, p, -1, szTopExt, -1)) hFirst = hItem; + if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, p, -1, szCaretExt, -1)) hCaret = hItem; + } + } + + // insert cd + is.hParent = TVI_ROOT; + is.item.state = INDEXTOSTATEIMAGEMASK(bRegCD + 1); + is.item.pszText = getStringW(IDS_REGISTER_CDPLAYER, NULL, 0); + is.item.lParam = -ID_REGISTERCD; + hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)&is); + if (!hFirst || !hCaret) + { + wchar_t t[32] = {0}; + StringCchPrintfW(t, ARRAYSIZE(t), L"#%d", ID_REGISTERCD); + if (!hFirst && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szTopExt, -1)) hFirst = hItem; + if (!hCaret && CSTR_EQUAL == CompareStringW(lcid, 0, t, -1, szCaretExt, -1)) hCaret = hItem; + } + + // agent + BOOL bAgentExist = IsAgentExist(); + HWND hwndCtrl = GetDlgItem(hwnd, IDC_CHK_AGENT); + if (hwndCtrl) EnableWindow(hwndCtrl, bAgentExist); + hwndCtrl = GetDlgItem(hwnd, IDC_LBL_AGENT_DESC); + if (hwndCtrl) EnableWindow(hwndCtrl, bAgentExist); + + CheckDlgButton(hwnd, IDC_CHK_AGENT, (bAgent && bAgentExist) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_CD, (bRegCD) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_EXPLORER_MENU, (bExplorerMenu) ? BST_CHECKED : BST_UNCHECKED); + + is.item.mask = TVIF_STATE; + is.item.stateMask = TVIS_STATEIMAGEMASK; + + for (int i = 0; i < sizeof(hBranch)/sizeof(HTREEITEM); i++) + { + if (!hBranch[i]) continue; + is.item.hItem = hBranch[i]; + is.item.state = INDEXTOSTATEIMAGEMASK(sBranch[i] + 1); + SendMessageW(hwndTree, TVM_SETITEM, 0, (LPARAM)&is.item); + SendMessageW(hwndTree, TVM_SORTCHILDREN, FALSE, (LPARAM)hBranch[i]); + } + + if (hCaret) PostMessageW(hwndTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hCaret); + if (hFirst) PostMessageW(hwndTree, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hFirst); + + SendMessageW(hwndTree, WM_SETREDRAW, TRUE, 0L); +} + +INT setup_page_assoc::TreeView_OnCustomDraw(NMTVCUSTOMDRAW *ptvcd) +{ + switch(ptvcd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_DODEFAULT | CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + return CDRF_DODEFAULT | CDRF_NOTIFYPOSTPAINT; + case CDDS_ITEMPOSTPAINT: + { + RECT rt; + WCHAR szText[256] = {0}; + TVITEMW item = {0}; + + item.hItem = (HTREEITEM)ptvcd->nmcd.dwItemSpec; + item.mask = TVIF_TEXT | TVIF_STATE; + item.stateMask = TVIS_SELECTED; + item.pszText = szText; + item.cchTextMax = 256; + SendMessageW(ptvcd->nmcd.hdr.hwndFrom, TVM_GETITEMW, 0, (LPARAM)&item); + *(DWORD_PTR*)&rt = ptvcd->nmcd.dwItemSpec; + SendMessageW(ptvcd->nmcd.hdr.hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rt); + SetTextColor(ptvcd->nmcd.hdc, ptvcd->clrText); + SetBkColor(ptvcd->nmcd.hdc, ptvcd->clrTextBk); + + DrawTextW(ptvcd->nmcd.hdc, item.pszText, -1, &rt, DT_EXPANDTABS | DT_NOPREFIX | DT_SINGLELINE | DT_CALCRECT); + rt.right += 8; + rt.top = ptvcd->nmcd.rc.top; + rt.bottom = ptvcd->nmcd.rc.bottom; + + ExtTextOutW(ptvcd->nmcd.hdc, 0, 0, ETO_OPAQUE, &rt, L"", 0, NULL); + rt.left += 4; + DrawTextW(ptvcd->nmcd.hdc, item.pszText, -1, &rt, DT_EXPANDTABS | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); + + if ((TVIS_SELECTED & item.state) && ptvcd->nmcd.hdr.hwndFrom == GetFocus()) + { + if (0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(ptvcd->nmcd.hdr.hwndFrom, 0x0129/*WM_QUERYUISTATE*/, 0, 0L))) + { + rt.left -= 4; + SetTextColor(ptvcd->nmcd.hdc, GetSysColor(COLOR_WINDOWTEXT)); + SetBkColor(ptvcd->nmcd.hdc, GetSysColor(COLOR_WINDOW)); + DrawFocusRect(ptvcd->nmcd.hdc, &rt); + } + } + } + break; + } + return CDRF_DODEFAULT; +} + +BOOL setup_page_assoc::TreeView_OnClick(NMHDR *pnmh) +{ + TVHITTESTINFO ht; + GetCursorPos(&ht.pt); + MapWindowPoints(HWND_DESKTOP, pnmh->hwndFrom, &ht.pt, 1); + if(NULL != SendMessageW(pnmh->hwndFrom, TVM_HITTEST, 0, (LPARAM)&ht)) + { + if ((TVHT_ONITEM | TVHT_ONITEMRIGHT) & ht.flags) + { + TreeView_OnItemStateClick(pnmh->hwndFrom, ht.hItem); + if (TVHT_ONITEMSTATEICON & ht.flags) return TRUE; + } + } + return FALSE; +} + +BOOL setup_page_assoc::TreeView_OnKeyDown(NMTVKEYDOWN *ptvkd) +{ + switch(ptvkd->wVKey) + { + case VK_SPACE: + { + HTREEITEM hItem = (HTREEITEM)(HTREEITEM)SendMessageW(ptvkd->hdr.hwndFrom, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L); + if (hItem) TreeView_OnItemStateClick(ptvkd->hdr.hwndFrom, hItem); + return TRUE; + } + } + return FALSE; +} + +void setup_page_assoc::TreeView_OnItemStateClick(HWND hwndTree, HTREEITEM hItem) +{ + HTREEITEM hParent = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PARENT, (LPARAM)hItem); + HTREEITEM hChild = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hItem); + TVITEMW item = {0}; + item.hItem = hItem; + item.mask = TVIF_STATE | TVIF_PARAM; + item.stateMask = TVIS_STATEIMAGEMASK; + + if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) return; + INT state = ((item.state>>12) - 1); + INT param = (INT)item.lParam; + + SendMessageW(hwndTree, WM_SETREDRAW, FALSE, 0L); + + state = (2 == state) ? 1 : !state; + + item.mask = TVIF_STATE; + item.state = INDEXTOSTATEIMAGEMASK(state + 1); + SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item); + + if (!hChild) + { + INT count = 1, selcount = state; + + item.hItem = hItem; + while(NULL != (item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PREVIOUS, (LPARAM)item.hItem))) + { + count++; + if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) continue; + if (2 == (item.state>>12)) selcount++; + } + item.hItem = hItem; + while(NULL != (item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem))) + { + count++; + if (!SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) continue; + if (2 == (item.state>>12)) selcount++; + } + + item.hItem = hParent; + item.state = INDEXTOSTATEIMAGEMASK(((!selcount) ? 1 : ((selcount == count) ? 2 :3))); + SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item); + if (param >= 0) pMeta[param] = (pMeta[param] & ~MF_SELECTED) | ((state) ? MF_SELECTED : 0); + else + { + switch(-param) + { + case ID_REGISTERCD: bRegCD = state; break; + } + } + } + else + { + item.hItem = hChild; + while(item.hItem) + { + item.mask = TVIF_PARAM; + if (SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item) && item.lParam >= 0) pMeta[item.lParam] = (pMeta[item.lParam] & ~MF_SELECTED) | ((state) ? MF_SELECTED : 0); + + item.mask = TVIF_STATE; + item.state = INDEXTOSTATEIMAGEMASK(state + 1); + SendMessageW(hwndTree, TVM_SETITEMW, 0, (LPARAM)&item); + item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem); + } + } + UpdateWindow(hwnd); + SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L); + SendMessageW(hwndTree, WM_SETREDRAW, TRUE, 0L); + SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L); + InvalidateRect(hwndTree, NULL, FALSE); +} + +INT_PTR setup_page_assoc::OnInitDialog(HWND hwndFocus, LPARAM lParam) +{ + HWND hwndTree = GetDlgItem(hwnd, IDC_TREE_TYPES); + if (hwndTree) + { + HIMAGELIST himl = ImageList_LoadImage(hMainInstance, MAKEINTRESOURCE(IDB_CHECKBOX), 16, 1, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_LOADTRANSPARENT); + if (himl) himl = (HIMAGELIST) SendMessageW(hwndTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl); + if (himl) ImageList_Destroy(himl); + + WNDPROC fnOldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)TreeViewProc); + if (fnOldProc) SetPropW(hwndTree, L"TVPROC", fnOldProc); + } + UpdateUI(); + return 0; +} + +void setup_page_assoc::OnDestroy(void) +{ + HWND hwndTree = GetDlgItem(hwnd, IDC_TREE_TYPES); + if (hwndTree) + { + TVITEMW item = {0}; + HIMAGELIST himl; + INT index1(-1), index2(-1); + wchar_t *p; + + ZeroMemory(expanded, sizeof(expanded)); + ZeroMemory(szTopExt, sizeof(szTopExt)); + ZeroMemory(szCaretExt, sizeof(szCaretExt)); + + item.mask = TVIF_PARAM | TVIF_STATE; + item.stateMask = TVIS_EXPANDED; + item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_ROOT, 0L); + while(item.hItem) + { + if (SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) + { + INT param = (INT)-item.lParam; + if (param < TYPE_CATEGORIES_NUM) expanded[param] = (BYTE)(TVIS_EXPANDED & item.state); + } + item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)item.hItem); + } + item.mask = TVIF_PARAM; + item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_FIRSTVISIBLE, 0L); + if (item.hItem && SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) index1 = (INT)item.lParam; + item.hItem = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L); + if (item.hItem && SendMessageW(hwndTree, TVM_GETITEMW, 0, (LPARAM)&item)) index2 = (INT)item.lParam; + + if (index1 < 0) StringCchPrintfW(szTopExt, ARRAYSIZE(szTopExt), L"#%d", -index1); + if (index2 < 0) StringCchPrintfW(szCaretExt, ARRAYSIZE(szCaretExt), L"#%d", -index2); + + if (index1 >= 0 || index2 >= 0) + { + INT i; + for(i = 0, p = pszTypes; *p != 0; p += lstrlenW(p) + 1, i++) + { + if (index1 == i) + { + StringCchCopyW(szTopExt, ARRAYSIZE(szTopExt), p); + if (index2 < 0) break; + index1 = -1; + } + if (index2 == i) + { + StringCchCopyW(szCaretExt, ARRAYSIZE(szCaretExt), p); + if (index1 < 0) break; + index2 = -1; + } + } + } + himl = (HIMAGELIST) SendMessageW(hwndTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)NULL); + if (himl) ImageList_Destroy(himl); + } +} + +void setup_page_assoc::OnSize(UINT nType, INT cx, INT cy) +{ + RECT rw; + INT h, r; + h = cy; + r = cx; + + HWND hwndCtrl = GetDlgItem(hwnd, IDC_LBL_HEADER); + if (hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, 0, 0, cx - rw.left*2, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); + } + + if (IsWin8()) + { + // hide the treeview (as needed to process things nicely but needs to be hidden on Windows 8 and higher as they work differently) + hwndCtrl = GetDlgItem(hwnd, IDC_TREE_TYPES); + if (hwndCtrl) + { + SetWindowPos(hwndCtrl, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_HIDEWINDOW); + } + return; + } + + hwndCtrl = GetDlgItem(hwnd, IDC_CHK_EXPLORER_MENU); + if (hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + h = cy - (((rw.bottom - rw.top)*3) + 6); + r = max(0, (cx - (rw.right - rw.left))/2) + (rw.right - rw.left); + SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12, + h, rw.right - rw.left + 26, + rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER); + + } + hwndCtrl = GetDlgItem(hwnd, IDC_CHK_AGENT); + if (hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12, + h + (rw.bottom - rw.top) + 2, + rw.right - rw.left + 26, + rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER); + } + hwndCtrl = GetDlgItem(hwnd, IDC_LBL_AGENT_DESC); + if (hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12, + h + (rw.bottom - rw.top)*2 + 2, + rw.right - rw.left + 26, + rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER); + } + hwndCtrl = GetDlgItem(hwnd, IDC_TREE_TYPES); + if (hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, r - (rw.right - rw.left) - 12, + rw.top, rw.right - rw.left + 26, + h - rw.top - 4, SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +void setup_page_assoc::OnCommand(INT nCtrlID, INT nEvntID, HWND hwndCtrl) +{ + switch(nCtrlID) + { + case IDC_CHK_EXPLORER_MENU: + { + switch (nEvntID) + { + case BN_CLICKED: + bExplorerMenu = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L))); + break; + } + break; + } + case IDC_CHK_AGENT: + { + switch (nEvntID) + { + case BN_CLICKED: + bAgent = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L))); + break; + } + break; + } + case IDC_CHK_CD: + { + switch (nEvntID) + { + case BN_CLICKED: + bRegCD = (BST_CHECKED == (BST_CHECKED & (INT)SendMessageW(hwndCtrl, BM_GETSTATE, 0, 0L))); + break; + } + break; + } + } +} + +BOOL setup_page_assoc::OnNotify(INT nCtrlID, NMHDR *pnmh, LRESULT *pResult) +{ + switch(nCtrlID) + { + case IDC_TREE_TYPES: + switch(pnmh->code) + { + case NM_CUSTOMDRAW: *pResult = TreeView_OnCustomDraw((NMTVCUSTOMDRAW*)pnmh); return TRUE; + case NM_CLICK: *pResult = TreeView_OnClick(pnmh); return TRUE; + case TVN_KEYDOWN: *pResult = TreeView_OnKeyDown((NMTVKEYDOWN*)pnmh); return TRUE; + } + } + return FALSE; +} + +INT_PTR setup_page_assoc::PageDlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam); + case WM_DESTROY: OnDestroy(); break; + case WM_SIZE: OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam)); break; + case WM_COMMAND: OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + case WM_NOTIFY: + { + LRESULT result = 0; + if (OnNotify((INT)wParam, (NMHDR*)lParam, &result)) + { + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)result); + return TRUE; + } + } + break; + } + return 0; +} + +static INT_PTR WINAPI DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + setup_page_assoc *pInst = (setup_page_assoc*)GetPropW(hwnd, L"SETUPPAGE"); + + switch(uMsg) + { + case WM_INITDIALOG: + pInst = (setup_page_assoc*)lParam; + if (pInst) + { + pInst->hwnd = hwnd; + SetPropW(hwnd, L"SETUPPAGE", pInst); + } + break; + + case WM_DESTROY: + if (pInst) + { + pInst->PageDlgProc(uMsg, wParam, lParam); + RemovePropW(hwnd, L"SETUPPAGE"); + pInst = NULL; + } + break; + } + + return (pInst) ? pInst->PageDlgProc(uMsg, wParam, lParam) : 0; +} + +static void TreeViewCheckItems(HWND hwnd, TVITEMW *pItem) +{ + while (pItem->hItem) + { + SendMessageW(hwnd, TVM_SETITEMW, 0, (LPARAM)pItem); + HTREEITEM hChild = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)pItem->hItem); + if (hChild) + { + HTREEITEM hTemp = pItem->hItem; + pItem->hItem = hChild; + TreeViewCheckItems(hwnd, pItem); + pItem->hItem = hTemp; + } + pItem->hItem = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM , TVGN_NEXT, (LPARAM)pItem->hItem); + } +} + +static LRESULT WINAPI TreeViewProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"TVPROC"); + if (!fnOldProc) return DefWindowProcW(hwnd, uMsg, wParam, lParam); + switch(uMsg) + { + case WM_DESTROY: + RemovePropW(hwnd, L"TVPROC"); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)fnOldProc); + break; + + case WM_CHAR: + if (0x01/*(CTRL_A)*/ == wParam) + { + TVITEMW item = {0}; + item.mask = TVIF_HANDLE | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + item.state = INDEXTOSTATEIMAGEMASK(2); + item.hItem = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM , TVGN_ROOT, 0L); + SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L); + TreeViewCheckItems(hwnd, &item); + SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L); + return 0; + } + break; + } + return CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam); +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS setup_page_assoc +START_DISPATCH +CB(ADDREF, AddRef) +CB(RELEASE, Release) +CB(API_SETUPPAGE_GET_NAME, GetName) +CB(API_SETUPPAGE_CREATEVIEW, CreateView) +CB(API_SETUPPAGE_SAVE, Save) +CB(API_SETUPPAGE_REVERT, Revert) +CB(API_SETUPPAGE_ISDIRTY, IsDirty) +CB(API_SETUPPAGE_VALIDATE, Validate) +END_DISPATCH +#undef CBCLASS
\ No newline at end of file |