diff foosdk/sdk/foobar2000/shared/filedialogs.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/foobar2000/shared/filedialogs.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,317 @@
+#include "shared.h"
+#include "filedialogs.h"
+#include <shlobj.h>
+
+#define dTEXT(X) pfc::stringcvt::string_os_from_utf8(X)
+
+static UINT_PTR CALLBACK uGetOpenFileName_Hook(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
+{
+	switch(msg) {
+	case WM_INITDIALOG:
+		{
+			OPENFILENAME * ofn = reinterpret_cast<OPENFILENAME*>(lp);
+			reinterpret_cast<modal_dialog_scope*>(ofn->lCustData)->initialize(FindOwningPopup(wnd));
+		}
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+static void ImportExtMask(pfc::array_t<TCHAR> & out, const char * in) {
+	{
+		pfc::stringcvt::string_os_from_utf8 temp(in);
+		out.set_size(temp.length()+2);
+		out.fill_null();
+		pfc::memcpy_t(out.get_ptr(),temp.get_ptr(),temp.length());
+	}
+
+	for(t_size walk = 0; walk < out.get_size(); ++walk) {
+		if (out[walk] == '|') out[walk] = 0;
+	}
+}
+
+BOOL Vista_GetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save);
+BOOL Vista_GetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::ptrholder_t<uGetOpenFileNameMultiResult> & out);
+BOOL Vista_BrowseForFolder(HWND parent, const char * p_title, pfc::string_base & path);
+puGetOpenFileNameMultiResult Vista_BrowseForFolderEx(HWND parent,const char * title, const char * initPath);
+
+static bool UseVistaDialogs() {
+#if FB2K_TARGET_MICROSOFT_STORE || _WIN32_WINNT >= 0x600
+	return true;
+#else
+	return GetWindowsVersionCode() >= 0x600;
+#endif
+}
+
+BOOL SHARED_EXPORT uGetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save) {
+	TRACK_CALL_TEXT("uGetOpenFileName");
+	try {
+		if (UseVistaDialogs()) return Vista_GetOpenFileName(parent, p_ext_mask, def_ext_mask, p_def_ext, p_title, p_directory, p_filename, b_save);
+	} catch(pfc::exception_not_implemented const &) {}
+
+	modal_dialog_scope scope;
+
+	pfc::array_t<TCHAR> ext_mask;
+	ImportExtMask(ext_mask,p_ext_mask);
+	
+	TCHAR buffer[4096];
+
+	pfc::stringToBuffer(buffer,pfc::stringcvt::string_os_from_utf8(p_filename));
+
+	pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""),
+		directory(p_directory ? p_directory : "");
+
+	OPENFILENAME ofn = {};
+
+	ofn.lStructSize=sizeof(ofn);
+	ofn.hwndOwner = parent;
+	ofn.lpstrFilter = ext_mask.get_ptr();
+	ofn.nFilterIndex = def_ext_mask + 1;
+	ofn.lpstrFile = buffer;
+	ofn.lpstrInitialDir = directory;
+	ofn.nMaxFile = _countof(buffer);
+	ofn.Flags = b_save ? OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_ENABLEHOOK|OFN_ENABLESIZING : OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ENABLEHOOK|OFN_ENABLESIZING;
+	ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0;
+	ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0;
+	ofn.lCustData = reinterpret_cast<LPARAM>(&scope);
+	ofn.lpfnHook = uGetOpenFileName_Hook;
+	if (b_save ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn))
+	{
+		buffer[_countof(buffer)-1]=0;
+
+		{
+			t_size ptr = _tcslen(buffer);
+			while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0;
+		}
+
+		p_filename = pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer));
+		return TRUE;
+	}
+	else return FALSE;
+}
+
+
+puGetOpenFileNameMultiResult SHARED_EXPORT uGetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory) {
+	TRACK_CALL_TEXT("uGetOpenFileNameMulti");
+	try {
+		if (UseVistaDialogs()) {
+			pfc::ptrholder_t<uGetOpenFileNameMultiResult> result;
+			if (!Vista_GetOpenFileNameMulti(parent,p_ext_mask,def_ext_mask,p_def_ext,p_title,p_directory,result)) return NULL;
+			return result.detach();
+		}
+	} catch(pfc::exception_not_implemented const &) {}
+
+	modal_dialog_scope scope;
+
+	pfc::array_t<TCHAR> ext_mask;
+	ImportExtMask(ext_mask,p_ext_mask);
+	
+	TCHAR buffer[0x4000];
+	buffer[0]=0;
+
+	pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""),
+		directory(p_directory ? p_directory : "");
+
+	OPENFILENAME ofn = {};
+
+	ofn.lStructSize=sizeof(ofn);
+	ofn.hwndOwner = parent;
+	ofn.lpstrFilter = ext_mask.get_ptr();
+	ofn.nFilterIndex = def_ext_mask + 1;
+	ofn.lpstrFile = buffer;
+	ofn.lpstrInitialDir = directory;
+	ofn.nMaxFile = _countof(buffer);
+	ofn.Flags = OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLESIZING;
+	ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0;
+	ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0;
+	ofn.lCustData = reinterpret_cast<LPARAM>(&scope);
+	ofn.lpfnHook = uGetOpenFileName_Hook;
+	if (GetOpenFileName(&ofn))
+	{
+		buffer[_countof(buffer)-1]=0;
+		buffer[_countof(buffer)-2]=0;
+
+		pfc::ptrholder_t<uGetOpenFileNameMultiResult_impl> result = new uGetOpenFileNameMultiResult_impl;
+
+		TCHAR * p=buffer;
+		while(*p) p++;
+		p++;
+		if (!*p)
+		{
+			{
+				t_size ptr = _tcslen(buffer);
+				while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0;
+			}
+
+			result->AddItem(pfc::stringcvt::string_utf8_from_os(buffer));
+		}
+		else
+		{
+			pfc::string_formatter s = (const char*) pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer));
+			t_size ofs = s.length();
+			if (ofs>0 && s[ofs-1]!='\\') {s.add_char('\\');ofs++;}
+			while(*p)
+			{
+				s.truncate(ofs);
+				s += pfc::stringcvt::string_utf8_from_os(p);
+				s.skip_trailing_char(' ');
+				result->AddItem(s);
+				while(*p) p++;
+				p++;
+			}
+		}
+		return result.detach();
+	}
+	else return 0;
+}
+
+
+
+
+
+struct browse_for_dir_struct
+{
+	const TCHAR * m_initval;
+	const TCHAR * m_tofind;
+
+	modal_dialog_scope m_scope;
+};
+
+static bool file_exists(const TCHAR * p_path)
+{
+	DWORD val = GetFileAttributes(p_path);
+	if (val == (-1) || (val & FILE_ATTRIBUTE_DIRECTORY)) return false;
+	return true;
+}
+
+static void browse_proc_check_okbutton(HWND wnd,const browse_for_dir_struct * p_struct,const TCHAR * p_path)
+{
+	TCHAR temp[MAX_PATH+1];
+	pfc::stringToBuffer(temp, p_path);
+
+	t_size len = _tcslen(temp);
+	if (len < MAX_PATH && len > 0)
+	{
+		if (temp[len-1] != '\\')
+			temp[len++] = '\\';
+	}
+	t_size idx = 0;
+	while(p_struct->m_tofind[idx] && idx+len < MAX_PATH)
+	{
+		temp[len+idx] = p_struct->m_tofind[idx];
+		idx++;
+	}
+	temp[len+idx] = 0;
+
+	SendMessage(wnd,BFFM_ENABLEOK,0,!!file_exists(temp));
+
+}
+
+static int _stdcall browse_proc(HWND wnd,UINT msg,LPARAM lp,LPARAM dat)
+{
+	browse_for_dir_struct * p_struct = reinterpret_cast<browse_for_dir_struct*>(dat);
+	switch(msg)
+	{
+	case BFFM_INITIALIZED:
+		p_struct->m_scope.initialize(wnd);
+		SendMessage(wnd,BFFM_SETSELECTION,1,(LPARAM)p_struct->m_initval);
+		if (p_struct->m_tofind) browse_proc_check_okbutton(wnd,p_struct,p_struct->m_initval);
+		break;
+	case BFFM_SELCHANGED:
+		if (p_struct->m_tofind)
+		{
+			if (lp != 0)
+			{
+				TCHAR temp[MAX_PATH+1];
+				if (SHGetPathFromIDList(reinterpret_cast<LPCITEMIDLIST>(lp),temp))
+				{
+					temp[MAX_PATH] = 0;
+					browse_proc_check_okbutton(wnd,p_struct,temp);
+				}
+				else
+					SendMessage(wnd,BFFM_ENABLEOK,0,FALSE);
+			}
+			else SendMessage(wnd,BFFM_ENABLEOK,0,FALSE);
+		}
+		break;
+	}
+	return 0;
+}
+
+static BOOL BrowseForFolderHelper(HWND p_parent,const TCHAR * p_title,TCHAR (&p_out)[MAX_PATH],const TCHAR * p_file_to_find)
+{
+	pfc::com_ptr_t<IMalloc> mallocptr;
+	
+	if (FAILED(SHGetMalloc(mallocptr.receive_ptr()))) return FALSE;
+	if (mallocptr.is_empty()) return FALSE;
+
+	browse_for_dir_struct data;
+	data.m_initval = p_out;
+	data.m_tofind = p_file_to_find;
+
+
+	BROWSEINFO bi=
+	{
+		p_parent,
+		0,
+		0,
+		p_title,
+		BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX,
+		browse_proc,
+		reinterpret_cast<LPARAM>(&data),
+		0
+	};
+
+	LPITEMIDLIST li = SHBrowseForFolder(&bi);
+	if (li == NULL) return FALSE;
+	BOOL state = SHGetPathFromIDList(li,p_out);
+	mallocptr->Free(li);
+	return state;
+}
+
+BOOL SHARED_EXPORT uBrowseForFolder(HWND parent,const char * p_title,pfc::string_base & out) {
+	TRACK_CALL_TEXT("uBrowseForFolder");
+	try {
+		if (UseVistaDialogs()) {
+			return Vista_BrowseForFolder(parent,p_title,out);
+		}
+	} catch(pfc::exception_not_implemented const &) {}
+
+	TCHAR temp[MAX_PATH];
+	pfc::stringToBuffer(temp,dTEXT(out));
+	BOOL rv = BrowseForFolderHelper(parent,dTEXT(p_title),temp,0);
+	if (rv) {
+		out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp));
+	}
+	return rv;
+}
+
+BOOL SHARED_EXPORT uBrowseForFolderWithFile(HWND parent,const char * title,pfc::string_base & out,const char * p_file_to_find)
+{
+	TRACK_CALL_TEXT("uBrowseForFolderWithFile");
+	TCHAR temp[MAX_PATH];
+	pfc::stringToBuffer(temp,dTEXT(out));
+	BOOL rv = BrowseForFolderHelper(parent,dTEXT(title),temp,dTEXT(p_file_to_find));
+	if (rv) {
+		out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp));
+	}
+	return rv;
+}
+
+
+puGetOpenFileNameMultiResult SHARED_EXPORT uBrowseForFolderEx(HWND parent,const char * title, const char * initPath) {
+	TRACK_CALL_TEXT("uBrowseForFolderEx");
+	try {
+		if (UseVistaDialogs()) {
+			return Vista_BrowseForFolderEx(parent,title, initPath);
+		} 
+	} catch(pfc::exception_not_implemented const &) {}
+
+	pfc::string8 temp;
+	if (initPath) temp = initPath;
+	if (!uBrowseForFolder(parent, title, temp)) return NULL;
+	pfc::ptrholder_t<uGetOpenFileNameMultiResult_impl> result = new uGetOpenFileNameMultiResult_impl;
+	result->AddItem(temp);
+	return result.detach();
+}