mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-20 21:13:25 +08:00
2082 lines
52 KiB
C
2082 lines
52 KiB
C
/******************************************************************************
|
|
* *
|
|
* *
|
|
* MiniPath - Notepad3 Explorer Plugin *
|
|
* *
|
|
* Helpers.c *
|
|
* General helper functions *
|
|
* Based on code from metapath, (c) Florian Balmer 1996-2011 *
|
|
* *
|
|
* (c) Rizonesoft 2008-2016 *
|
|
* https://rizonesoft.com *
|
|
* *
|
|
* *
|
|
*******************************************************************************/
|
|
#if !defined(_WIN32_WINNT)
|
|
#define _WIN32_WINNT 0x601
|
|
#endif
|
|
#define VC_EXTRALEAN 1
|
|
//#define WIN32_LEAN_AND_MEAN 1
|
|
//#define NOMINMAX 1
|
|
#include <windows.h>
|
|
#include <shlobj.h>
|
|
#include <shlwapi.h>
|
|
#include <commctrl.h>
|
|
#include <uxtheme.h>
|
|
#include <strsafe.h>
|
|
#include "dlapi.h"
|
|
#include "helpers.h"
|
|
#include "resource.h"
|
|
|
|
extern LANGID g_iPrefLANGID;
|
|
|
|
//=============================================================================
|
|
//
|
|
// Manipulation of (cached) ini file sections
|
|
//
|
|
int IniSectionGetString(
|
|
LPCWSTR lpCachedIniSection,
|
|
LPCWSTR lpName,
|
|
LPCWSTR lpDefault,
|
|
LPWSTR lpReturnedString,
|
|
int cchReturnedString)
|
|
{
|
|
LPWSTR p = (LPWSTR)lpCachedIniSection;
|
|
if (p) {
|
|
int const ich = lstrlen(lpName);
|
|
while (*p) {
|
|
if ((StrCmpNI(p,lpName,ich) == 0) && (p[ich] == L'=')) {
|
|
lstrcpyn(lpReturnedString,(p+ich+1),cchReturnedString);
|
|
return lstrlen(lpReturnedString);
|
|
}
|
|
else
|
|
p = StrEnd(p) + 1;
|
|
}
|
|
}
|
|
lstrcpyn(lpReturnedString,lpDefault,cchReturnedString);
|
|
return lstrlen(lpReturnedString);
|
|
}
|
|
|
|
|
|
int IniSectionGetInt(
|
|
LPCWSTR lpCachedIniSection,
|
|
LPCWSTR lpName,
|
|
int iDefault)
|
|
{
|
|
LPWSTR p = (LPWSTR)lpCachedIniSection;
|
|
if (p) {
|
|
int const ich = lstrlen(lpName);
|
|
while (*p) {
|
|
if ((StrCmpNI(p,lpName,ich) == 0) && (p[ich] == L'=')) {
|
|
int i;
|
|
if (swscanf_s((p+ich+1),L"%i",&i) == 1)
|
|
return(i);
|
|
else
|
|
return(iDefault);
|
|
}
|
|
else
|
|
p = StrEnd(p) + 1;
|
|
}
|
|
}
|
|
return(iDefault);
|
|
}
|
|
|
|
|
|
BOOL IniSectionSetString(LPWSTR lpCachedIniSection,LPCWSTR lpName,LPCWSTR lpString)
|
|
{
|
|
LPWSTR p = lpCachedIniSection;
|
|
if (p) {
|
|
while (*p) {
|
|
p = StrEnd(p) + 1;
|
|
}
|
|
wsprintf(p,L"%s=%s",lpName,lpString);
|
|
p = StrEnd(p) + 1;
|
|
*p = 0;
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// BeginWaitCursor()
|
|
//
|
|
void BeginWaitCursor()
|
|
{
|
|
|
|
DestroyCursor(
|
|
SetCursor(
|
|
LoadCursor(NULL,IDC_WAIT)));
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// EndWaitCursor()
|
|
//
|
|
void EndWaitCursor()
|
|
{
|
|
|
|
DestroyCursor(
|
|
SetCursor(
|
|
LoadCursor(NULL,IDC_ARROW)));
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// LoadLngStringW()
|
|
//
|
|
int LoadLngStringW(UINT uID, LPWSTR lpBuffer, int nBufferMax)
|
|
{
|
|
const int nLen = LoadStringW(g_hLngResContainer, uID, lpBuffer, nBufferMax);
|
|
return (nLen != 0) ? nLen : LoadStringW(g_hInstance, uID, lpBuffer, nBufferMax);
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// LoadLngStringA()
|
|
//
|
|
int LoadLngStringA(UINT uID, LPSTR lpBuffer, int nBufferMax)
|
|
{
|
|
const int nLen = LoadStringA(g_hLngResContainer, uID, lpBuffer, nBufferMax);
|
|
return (nLen != 0) ? nLen : LoadStringA(g_hInstance, uID, lpBuffer, nBufferMax);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// FormatLngStringW()
|
|
//
|
|
int FormatLngStringW(LPWSTR lpOutput, int nOutput, UINT uIdFormat, ...)
|
|
{
|
|
WCHAR* pBuffer = LocalAlloc(LPTR, sizeof(WCHAR)*nOutput);
|
|
if (pBuffer) {
|
|
if (LoadLngStringW(uIdFormat, pBuffer, nOutput)) {
|
|
int t = vswprintf_s(lpOutput, nOutput, pBuffer, (LPVOID)((PUINT_PTR)&uIdFormat + 1));
|
|
lpOutput[t] = L'\0';
|
|
}
|
|
LocalFree(pBuffer);
|
|
return (int)lstrlen(lpOutput);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// FormatLngStringA()
|
|
//
|
|
int FormatLngStringA(LPSTR lpOutput, int nOutput, UINT uIdFormat, ...)
|
|
{
|
|
CHAR* pBuffer = LocalAlloc(LPTR, sizeof(CHAR)*nOutput);
|
|
if (pBuffer) {
|
|
if (LoadLngStringA(uIdFormat, pBuffer, nOutput)) {
|
|
int t = vsprintf_s(lpOutput, nOutput, pBuffer, (LPVOID)((PUINT_PTR)&uIdFormat + 1));
|
|
lpOutput[t] = '\0';
|
|
}
|
|
LocalFree(pBuffer);
|
|
return (int)strlen(lpOutput);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// GetLastErrorToMsgBox()
|
|
//
|
|
DWORD GetLastErrorToMsgBox(LPWSTR lpszFunction, DWORD dwErrID)
|
|
{
|
|
// Retrieve the system error message for the last-error code
|
|
if (!dwErrID) {
|
|
dwErrID = GetLastError();
|
|
}
|
|
|
|
LPVOID lpMsgBuf;
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwErrID,
|
|
g_iPrefLANGID,
|
|
(LPTSTR)&lpMsgBuf,
|
|
0, NULL);
|
|
|
|
// Display the error message and exit the process
|
|
|
|
LPVOID lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlen((LPCWSTR)lpMsgBuf) + lstrlen((LPCWSTR)lpszFunction) + 80) * sizeof(WCHAR));
|
|
|
|
wsprintf((LPWSTR)lpDisplayBuf, L"Error: '%s' failed with error id %d:\n%s.\n", lpszFunction, dwErrID, (LPWSTR)lpMsgBuf);
|
|
|
|
MessageBox(NULL, (LPCWSTR)lpDisplayBuf, L"Notepad3 - ERROR", MB_OK | MB_ICONEXCLAMATION);
|
|
|
|
LocalFree(lpMsgBuf);
|
|
LocalFree(lpDisplayBuf);
|
|
|
|
return dwErrID;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// ExeNameFromWnd()
|
|
//
|
|
DWORD WINAPI GetModuleFileNameExW(HANDLE,HMODULE,LPTSTR,DWORD);
|
|
BOOL WINAPI EnumProcessModules(HANDLE,HMODULE*,DWORD,LPDWORD);
|
|
|
|
BOOL ExeNameFromWnd(HWND hwnd,LPWSTR szExeName,int cchExeName)
|
|
{
|
|
//HMODULE hPSAPI;
|
|
DWORD dwProcessId;
|
|
HANDLE hProcess;
|
|
HMODULE hModule;
|
|
DWORD cbNeeded = 0;
|
|
//FARPROC fpCreateToolhelp32Snapshot;
|
|
//FARPROC fpProcess32First;
|
|
//FARPROC fpProcess32Next;
|
|
//HANDLE hProcessList;
|
|
//PROCESSENTRY32 pe;
|
|
//BOOL bMoreEntries;
|
|
//BOOL bFoundMatching = FALSE;
|
|
|
|
/*if (IsWindowsNT())
|
|
{
|
|
if (hPSAPI = LoadLibrary(L"PSAPI"))
|
|
{*/
|
|
GetWindowThreadProcessId(hwnd,&dwProcessId);
|
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,dwProcessId);
|
|
/*GetProcAddress(hPSAPI,"EnumProcessModules")*/ EnumProcessModules(hProcess,&hModule,sizeof(HMODULE),&cbNeeded);
|
|
/*GetProcAddress(hPSAPI,"GetModuleFileNameExW")*/ GetModuleFileNameExW(hProcess,hModule,szExeName,cchExeName);
|
|
CloseHandle(hProcess);
|
|
//FreeLibrary(hPSAPI);
|
|
return TRUE;
|
|
/*}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
else
|
|
{
|
|
fpCreateToolhelp32Snapshot = GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"CreateToolhelp32Snapshot");
|
|
fpProcess32First = GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"Process32First");
|
|
fpProcess32Next = GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"Process32Next");
|
|
|
|
if (fpCreateToolhelp32Snapshot)
|
|
{
|
|
GetWindowThreadProcessId(hwnd,&dwProcessId);
|
|
hProcessList = (HANDLE)fpCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
pe.dwSize = sizeof(PROCESSENTRY32);
|
|
bMoreEntries = fpProcess32First(hProcessList,&pe);
|
|
|
|
while (bMoreEntries)
|
|
{
|
|
if (pe.th32ProcessID == dwProcessId)
|
|
{
|
|
bMoreEntries = FALSE;
|
|
bFoundMatching = TRUE;
|
|
lstrcpyn(szExeName,pe.szExeFile,cchExeName);
|
|
}
|
|
else
|
|
bMoreEntries = fpProcess32Next(hProcessList,&pe);
|
|
}
|
|
CloseHandle(hProcessList);
|
|
return (bFoundMatching);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}*/
|
|
}
|
|
|
|
|
|
////=============================================================================
|
|
////
|
|
//// Is32bitExe()
|
|
////
|
|
//BOOL Is32bitExe(LPCWSTR lpszExeName)
|
|
//{
|
|
// SHFILEINFO shfi;
|
|
// DWORD dwExeType;
|
|
// WCHAR tch[MAX_PATH];
|
|
//
|
|
// if (PathIsLnkFile(lpszExeName) &&
|
|
// PathGetLnkPath(lpszExeName,tch,COUNTOF(tch)))
|
|
// dwExeType = SHGetFileInfo(tch,0,&shfi,sizeof(SHFILEINFO),SHGFI_EXETYPE);
|
|
// else
|
|
// dwExeType = SHGetFileInfo(lpszExeName,0,&shfi,sizeof(SHFILEINFO),SHGFI_EXETYPE);
|
|
//
|
|
// return (HIWORD(dwExeType) && LOWORD(dwExeType)) ? TRUE : FALSE;
|
|
//}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// PrivateIsAppThemed()
|
|
//
|
|
BOOL PrivateIsAppThemed()
|
|
{
|
|
BOOL bIsAppThemed = FALSE;
|
|
HMODULE hDll = LoadLibrary(L"uxtheme.dll");
|
|
if (hDll)
|
|
{
|
|
FARPROC fp = GetProcAddress(hDll,"IsAppThemed");
|
|
if (fp)
|
|
bIsAppThemed = (BOOL)fp();
|
|
FreeLibrary(hDll);
|
|
}
|
|
return bIsAppThemed;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// SetTheme()
|
|
//
|
|
BOOL SetTheme(HWND hwnd, LPCWSTR lpszTheme)
|
|
{
|
|
return (S_OK == SetWindowTheme(hwnd, lpszTheme, NULL));
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// BitmapMergeAlpha()
|
|
// Merge alpha channel into color channel
|
|
//
|
|
BOOL BitmapMergeAlpha(HBITMAP hbmp,COLORREF crDest)
|
|
{
|
|
BITMAP bmp;
|
|
if (GetObject(hbmp,sizeof(BITMAP),&bmp)) {
|
|
|
|
if (bmp.bmBitsPixel == 32) {
|
|
|
|
int x,y;
|
|
RGBQUAD *prgba = bmp.bmBits;
|
|
|
|
for (y = 0; y < bmp.bmHeight; y++) {
|
|
for (x = 0; x < bmp.bmWidth; x++) {
|
|
BYTE alpha = prgba[x].rgbReserved;
|
|
prgba[x].rgbRed = ((prgba[x].rgbRed * alpha) + (GetRValue(crDest) * (255-alpha))) >> 8;
|
|
prgba[x].rgbGreen = ((prgba[x].rgbGreen * alpha) + (GetGValue(crDest) * (255-alpha))) >> 8;
|
|
prgba[x].rgbBlue = ((prgba[x].rgbBlue * alpha) + (GetBValue(crDest) * (255-alpha))) >> 8;
|
|
prgba[x].rgbReserved = 0xFF;
|
|
}
|
|
prgba = (RGBQUAD*)((LPBYTE)prgba + bmp.bmWidthBytes);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// BitmapAlphaBlend()
|
|
// Perform alpha blending to color channel only
|
|
//
|
|
BOOL BitmapAlphaBlend(HBITMAP hbmp,COLORREF crDest,BYTE alpha)
|
|
{
|
|
BITMAP bmp;
|
|
if (GetObject(hbmp,sizeof(BITMAP),&bmp)) {
|
|
|
|
if (bmp.bmBitsPixel == 32) {
|
|
|
|
int x,y;
|
|
RGBQUAD *prgba = bmp.bmBits;
|
|
|
|
for (y = 0; y < bmp.bmHeight; y++) {
|
|
for (x = 0; x < bmp.bmWidth; x++) {
|
|
prgba[x].rgbRed = ((prgba[x].rgbRed * alpha) + (GetRValue(crDest) * (255-alpha))) >> 8;
|
|
prgba[x].rgbGreen = ((prgba[x].rgbGreen * alpha) + (GetGValue(crDest) * (255-alpha))) >> 8;
|
|
prgba[x].rgbBlue = ((prgba[x].rgbBlue * alpha) + (GetBValue(crDest) * (255-alpha))) >> 8;
|
|
}
|
|
prgba = (RGBQUAD*)((LPBYTE)prgba + bmp.bmWidthBytes);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// BitmapGrayScale()
|
|
// Gray scale color channel only
|
|
//
|
|
BOOL BitmapGrayScale(HBITMAP hbmp)
|
|
{
|
|
BITMAP bmp;
|
|
if (GetObject(hbmp,sizeof(BITMAP),&bmp)) {
|
|
|
|
if (bmp.bmBitsPixel == 32) {
|
|
|
|
int x,y;
|
|
RGBQUAD *prgba = bmp.bmBits;
|
|
|
|
for (y = 0; y < bmp.bmHeight; y++) {
|
|
for (x = 0; x < bmp.bmWidth; x++) {
|
|
prgba[x].rgbRed = prgba[x].rgbGreen = prgba[x].rgbBlue =
|
|
(((BYTE)((prgba[x].rgbRed * 38 + prgba[x].rgbGreen * 75 + prgba[x].rgbBlue * 15) >> 7) * 0x80) + (0xD0 * (255-0x80))) >> 8;
|
|
}
|
|
prgba = (RGBQUAD*)((LPBYTE)prgba + bmp.bmWidthBytes);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// SetWindowPathTitle()
|
|
//
|
|
BOOL SetWindowPathTitle(HWND hwnd,LPCWSTR lpszFile)
|
|
{
|
|
WCHAR szTitle[MAX_PATH + 120] = { L'\0' };
|
|
|
|
if (StrIsNotEmpty(lpszFile))
|
|
{
|
|
if (!PathIsRoot(lpszFile))
|
|
{
|
|
SHFILEINFO shfi;
|
|
if (SHGetFileInfo(lpszFile, 0, &shfi, sizeof(SHFILEINFO), SHGFI_DISPLAYNAME))
|
|
lstrcpy(szTitle, shfi.szDisplayName);
|
|
else
|
|
lstrcpy(szTitle, PathFindFileName(lpszFile));
|
|
|
|
WCHAR tchPath[MAX_PATH] = { L'\0' };
|
|
lstrcpy(tchPath, lpszFile);
|
|
PathRemoveFileSpec(tchPath);
|
|
lstrcat(szTitle, L" - [");
|
|
lstrcat(szTitle, tchPath);
|
|
if (tchPath[0] && (tchPath[lstrlen(tchPath)-1] == L'\\'))
|
|
lstrcat(szTitle, L"]");
|
|
else
|
|
lstrcat(szTitle, L"\\]");
|
|
}
|
|
else
|
|
lstrcpy(szTitle, lpszFile);
|
|
}
|
|
|
|
return SetWindowText(hwnd, szTitle);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// CenterDlgInParent()
|
|
//
|
|
void CenterDlgInParent(HWND hDlg)
|
|
{
|
|
|
|
RECT rcDlg;
|
|
HWND hParent;
|
|
RECT rcParent;
|
|
MONITORINFO mi;
|
|
HMONITOR hMonitor;
|
|
|
|
int xMin, yMin, xMax, yMax, x, y;
|
|
|
|
GetWindowRect(hDlg,&rcDlg);
|
|
|
|
hParent = GetParent(hDlg);
|
|
GetWindowRect(hParent,&rcParent);
|
|
|
|
hMonitor = MonitorFromRect(&rcParent,MONITOR_DEFAULTTONEAREST);
|
|
mi.cbSize = sizeof(mi);
|
|
GetMonitorInfo(hMonitor,&mi);
|
|
|
|
xMin = mi.rcWork.left;
|
|
yMin = mi.rcWork.top;
|
|
|
|
xMax = (mi.rcWork.right) - (rcDlg.right - rcDlg.left);
|
|
yMax = (mi.rcWork.bottom) - (rcDlg.bottom - rcDlg.top);
|
|
|
|
if ((rcParent.right - rcParent.left) - (rcDlg.right - rcDlg.left) > 20)
|
|
x = rcParent.left + (((rcParent.right - rcParent.left) - (rcDlg.right - rcDlg.left)) / 2);
|
|
else
|
|
x = rcParent.left + 70;
|
|
|
|
if ((rcParent.bottom - rcParent.top) - (rcDlg.bottom - rcDlg.top) > 20)
|
|
y = rcParent.top + (((rcParent.bottom - rcParent.top) - (rcDlg.bottom - rcDlg.top)) / 2);
|
|
else
|
|
y = rcParent.top + 60;
|
|
|
|
SetWindowPos(hDlg,NULL, clampi(x, xMin, xMax), clampi(y, yMin, yMax),0,0,SWP_NOZORDER|SWP_NOSIZE);
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// MakeBitmapButton()
|
|
//
|
|
void MakeBitmapButton(HWND hwnd, int nCtlId, HINSTANCE hInstance, WORD uBmpId)
|
|
{
|
|
HWND hwndCtl = GetDlgItem(hwnd,nCtlId);
|
|
BITMAP bmp;
|
|
BUTTON_IMAGELIST bi;
|
|
HBITMAP hBmp = LoadImage(hInstance,MAKEINTRESOURCE(uBmpId),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
|
GetObject(hBmp,sizeof(BITMAP),&bmp);
|
|
bi.himl = ImageList_Create(bmp.bmWidth,bmp.bmHeight,ILC_COLOR32|ILC_MASK,1,0);
|
|
ImageList_AddMasked(bi.himl,hBmp,CLR_DEFAULT);
|
|
DeleteObject(hBmp);
|
|
SetRect(&bi.margin,0,0,0,0);
|
|
bi.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
|
|
SendMessage(hwndCtl,BCM_SETIMAGELIST,0,(LPARAM)&bi);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// DeleteBitmapButton()
|
|
//
|
|
void DeleteBitmapButton(HWND hwnd,int nCtlId)
|
|
{
|
|
HWND hwndCtl = GetDlgItem(hwnd,nCtlId);
|
|
BUTTON_IMAGELIST bi;
|
|
if (SendMessage(hwndCtl,BCM_GETIMAGELIST,0,(LPARAM)&bi))
|
|
ImageList_Destroy(bi.himl);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// SetWindowTransparentMode()
|
|
//
|
|
void SetWindowTransparentMode(HWND hwnd, BOOL bTransparentMode, int iOpacityLevel)
|
|
{
|
|
if (bTransparentMode) {
|
|
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
|
BYTE const bAlpha = (BYTE)MulDiv(iOpacityLevel, 255, 100);
|
|
SetLayeredWindowAttributes(hwnd, 0, bAlpha, LWA_ALPHA);
|
|
}
|
|
else
|
|
SetWindowLongPtr(hwnd,GWL_EXSTYLE, GetWindowLongPtr(hwnd,GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// StatusSetText()
|
|
//
|
|
BOOL StatusSetText(HWND hwnd,UINT nPart,LPCWSTR lpszText)
|
|
{
|
|
|
|
UINT uFlags = (nPart == 255) ? nPart|SBT_NOBORDERS : nPart;
|
|
return (BOOL)SendMessage(hwnd,SB_SETTEXT,uFlags,(LPARAM)lpszText);
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// Toolbar_Get/SetButtons()
|
|
//
|
|
int Toolbar_GetButtons(HWND hwnd,int cmdBase,LPWSTR lpszButtons,int cchButtons)
|
|
{
|
|
WCHAR tchButtons[512];
|
|
WCHAR tchItem[32];
|
|
TBBUTTON tbb;
|
|
|
|
lstrcpy(tchButtons,L"");
|
|
int const c = min(50,(int)SendMessage(hwnd,TB_BUTTONCOUNT,0,0));
|
|
|
|
for (int i = 0; i < c; i++) {
|
|
SendMessage(hwnd,TB_GETBUTTON,(WPARAM)i,(LPARAM)&tbb);
|
|
wsprintf(tchItem,L"%i ",
|
|
(tbb.idCommand==0)?0:tbb.idCommand-cmdBase+1);
|
|
lstrcat(tchButtons,tchItem);
|
|
}
|
|
TrimStringW(tchButtons);
|
|
lstrcpyn(lpszButtons,tchButtons,cchButtons);
|
|
return(c);
|
|
}
|
|
|
|
int Toolbar_SetButtons(HWND hwnd,int cmdBase,LPCWSTR lpszButtons,LPCTBBUTTON ptbb,int ctbb)
|
|
{
|
|
WCHAR tchButtons[512];
|
|
int i,c;
|
|
int iCmd;
|
|
|
|
ZeroMemory(tchButtons,COUNTOF(tchButtons)*sizeof(tchButtons[0]));
|
|
lstrcpyn(tchButtons,lpszButtons,COUNTOF(tchButtons)-2);
|
|
TrimStringW(tchButtons);
|
|
WCHAR *p = StrStr(tchButtons, L" ");
|
|
while (p) {
|
|
MoveMemory((WCHAR*)p, (WCHAR*)p + 1, (lstrlen(p) + 1) * sizeof(WCHAR));
|
|
p = StrStr(tchButtons, L" ");
|
|
}
|
|
c = (int)SendMessage(hwnd,TB_BUTTONCOUNT,0,0);
|
|
for (i = 0; i < c; i++)
|
|
SendMessage(hwnd,TB_DELETEBUTTON,0,0);
|
|
|
|
for (i = 0; i < COUNTOF(tchButtons); i++)
|
|
if (tchButtons[i] == L' ') tchButtons[i] = 0;
|
|
|
|
p = tchButtons;
|
|
while (*p) {
|
|
if (swscanf_s(p,L"%i",&iCmd) == 1) {
|
|
iCmd = (iCmd==0)?0:iCmd+cmdBase-1;
|
|
for (i = 0; i < ctbb; i++) {
|
|
if (ptbb[i].idCommand == iCmd) {
|
|
SendMessage(hwnd,TB_ADDBUTTONS,(WPARAM)1,(LPARAM)&ptbb[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
p = StrEnd(p)+1;
|
|
}
|
|
return((int)SendMessage(hwnd,TB_BUTTONCOUNT,0,0));
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// Toolbar_SetButtonImage()
|
|
//
|
|
void Toolbar_SetButtonImage(HWND hwnd,int idCommand,int iImage)
|
|
{
|
|
TBBUTTONINFO tbbi;
|
|
|
|
tbbi.cbSize = sizeof(TBBUTTONINFO);
|
|
tbbi.dwMask = TBIF_IMAGE;
|
|
tbbi.iImage = iImage;
|
|
|
|
SendMessage(hwnd,TB_SETBUTTONINFO,(WPARAM)idCommand,(LPARAM)&tbbi);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// SendWMSize()
|
|
//
|
|
LRESULT SendWMSize(HWND hwnd)
|
|
{
|
|
RECT rc; GetClientRect(hwnd,&rc);
|
|
return(SendMessage(hwnd,WM_SIZE,SIZE_RESTORED,
|
|
MAKELPARAM(rc.right,rc.bottom)));
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// PathRelativeToApp()
|
|
//
|
|
void PathRelativeToApp(
|
|
LPWSTR lpszSrc,LPWSTR lpszDest,int cchDest,BOOL bSrcIsFile,
|
|
BOOL bUnexpandEnv,BOOL bUnexpandMyDocs) {
|
|
|
|
WCHAR wchAppPath[MAX_PATH];
|
|
WCHAR wchWinDir[MAX_PATH];
|
|
WCHAR wchUserFiles[MAX_PATH];
|
|
WCHAR wchPath[MAX_PATH];
|
|
WCHAR wchResult[MAX_PATH];
|
|
DWORD dwAttrTo = (bSrcIsFile) ? 0 : FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
GetModuleFileName(NULL,wchAppPath,COUNTOF(wchAppPath));
|
|
PathRemoveFileSpec(wchAppPath);
|
|
GetWindowsDirectory(wchWinDir,COUNTOF(wchWinDir));
|
|
SHGetFolderPath(NULL,CSIDL_PERSONAL,NULL,SHGFP_TYPE_CURRENT,wchUserFiles);
|
|
|
|
if (bUnexpandMyDocs &&
|
|
!PathIsRelative(lpszSrc) &&
|
|
!PathIsPrefix(wchUserFiles,wchAppPath) &&
|
|
PathIsPrefix(wchUserFiles,lpszSrc) &&
|
|
PathRelativePathTo(wchPath,wchUserFiles,FILE_ATTRIBUTE_DIRECTORY,lpszSrc,dwAttrTo)) {
|
|
lstrcpy(wchUserFiles,L"%CSIDL:MYDOCUMENTS%");
|
|
PathAppend(wchUserFiles,wchPath);
|
|
lstrcpy(wchPath,wchUserFiles);
|
|
}
|
|
else if (PathIsRelative(lpszSrc) || PathCommonPrefix(wchAppPath,wchWinDir,NULL))
|
|
lstrcpyn(wchPath,lpszSrc,COUNTOF(wchPath));
|
|
else {
|
|
if (!PathRelativePathTo(wchPath,wchAppPath,FILE_ATTRIBUTE_DIRECTORY,lpszSrc,dwAttrTo))
|
|
lstrcpyn(wchPath,lpszSrc,COUNTOF(wchPath));
|
|
}
|
|
|
|
if (bUnexpandEnv) {
|
|
if (!PathUnExpandEnvStrings(wchPath,wchResult,COUNTOF(wchResult)))
|
|
lstrcpyn(wchResult,wchPath,COUNTOF(wchResult));
|
|
}
|
|
else
|
|
lstrcpyn(wchResult,wchPath,COUNTOF(wchResult));
|
|
|
|
if (lpszDest == NULL || lpszSrc == lpszDest)
|
|
lstrcpyn(lpszSrc,wchResult,(cchDest == 0) ? MAX_PATH : cchDest);
|
|
else
|
|
lstrcpyn(lpszDest,wchResult,(cchDest == 0) ? MAX_PATH : cchDest);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// PathAbsoluteFromApp()
|
|
//
|
|
void PathAbsoluteFromApp(LPWSTR lpszSrc,LPWSTR lpszDest,int cchDest,BOOL bExpandEnv) {
|
|
|
|
WCHAR wchPath[MAX_PATH];
|
|
WCHAR wchResult[MAX_PATH];
|
|
|
|
if (StrCmpNI(lpszSrc,L"%CSIDL:MYDOCUMENTS%",CSTRLEN("%CSIDL:MYDOCUMENTS%")) == 0) {
|
|
SHGetFolderPath(NULL,CSIDL_PERSONAL,NULL,SHGFP_TYPE_CURRENT,wchPath);
|
|
PathAppend(wchPath,lpszSrc+ CSTRLEN("%CSIDL:MYDOCUMENTS%"));
|
|
}
|
|
else
|
|
lstrcpyn(wchPath,lpszSrc,COUNTOF(wchPath));
|
|
|
|
if (bExpandEnv)
|
|
ExpandEnvironmentStringsEx(wchPath,COUNTOF(wchPath));
|
|
|
|
if (PathIsRelative(wchPath)) {
|
|
GetModuleFileName(NULL,wchResult,COUNTOF(wchResult));
|
|
PathRemoveFileSpec(wchResult);
|
|
PathAppend(wchResult,wchPath);
|
|
}
|
|
else
|
|
lstrcpyn(wchResult,wchPath,COUNTOF(wchResult));
|
|
|
|
PathCanonicalizeEx(wchResult);
|
|
if (PathGetDriveNumber(wchResult) != -1)
|
|
CharUpperBuff(wchResult,1);
|
|
|
|
if (lpszDest == NULL || lpszSrc == lpszDest)
|
|
lstrcpyn(lpszSrc,wchResult,(cchDest == 0) ? MAX_PATH : cchDest);
|
|
else
|
|
lstrcpyn(lpszDest,wchResult,(cchDest == 0) ? MAX_PATH : cchDest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Name: PathIsLnkFile()
|
|
//
|
|
// Purpose: Determine wheter pszPath is a Windows Shell Link File by
|
|
// comparing the filename extension with L".lnk"
|
|
//
|
|
// Manipulates:
|
|
//
|
|
BOOL PathIsLnkFile(LPCWSTR pszPath)
|
|
{
|
|
|
|
//WCHAR *pszExt;
|
|
|
|
WCHAR tchResPath[256];
|
|
|
|
if (!pszPath || !*pszPath)
|
|
return FALSE;
|
|
|
|
/*pszExt = strrchr(pszPath,L'.');
|
|
|
|
if (!pszExt)
|
|
return FALSE;
|
|
|
|
if (!lstrcmpi(pszExt,L".lnk"))
|
|
return TRUE;
|
|
|
|
else
|
|
return FALSE;*/
|
|
|
|
//if (!lstrcmpi(PathFindExtension(pszPath),L".lnk"))
|
|
// return TRUE;
|
|
|
|
//else
|
|
// return FALSE;
|
|
|
|
if (lstrcmpi(PathFindExtension(pszPath),L".lnk"))
|
|
return FALSE;
|
|
|
|
else
|
|
return PathGetLnkPath(pszPath,tchResPath,COUNTOF(tchResPath));
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Name: PathGetLnkPath()
|
|
//
|
|
// Purpose: Try to get the path to which a lnk-file is linked
|
|
//
|
|
//
|
|
// Manipulates: pszResPath
|
|
//
|
|
BOOL PathGetLnkPath(LPCWSTR pszLnkFile,LPWSTR pszResPath,int cchResPath)
|
|
{
|
|
|
|
IShellLink *psl;
|
|
WIN32_FIND_DATA fd;
|
|
BOOL bSucceeded = FALSE;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink,NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IShellLink,&psl)))
|
|
{
|
|
IPersistFile *ppf;
|
|
|
|
if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,&ppf)))
|
|
{
|
|
WORD wsz[MAX_PATH];
|
|
|
|
/*MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,
|
|
pszLnkFile,-1,wsz,MAX_PATH);*/
|
|
lstrcpy(wsz,pszLnkFile);
|
|
|
|
if (SUCCEEDED(ppf->lpVtbl->Load(ppf,wsz,STGM_READ)))
|
|
{
|
|
if (NOERROR == psl->lpVtbl->GetPath(psl,pszResPath,cchResPath,&fd,0))
|
|
bSucceeded = TRUE;
|
|
}
|
|
ppf->lpVtbl->Release(ppf);
|
|
}
|
|
psl->lpVtbl->Release(psl);
|
|
}
|
|
|
|
// This additional check seems reasonable
|
|
if (StrIsEmpty(pszResPath))
|
|
bSucceeded = FALSE;
|
|
|
|
if (bSucceeded)
|
|
ExpandEnvironmentStringsEx(pszResPath,cchResPath);
|
|
|
|
return(bSucceeded);
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Name: PathIsLnkToDirectory()
|
|
//
|
|
// Purpose: Determine wheter pszPath is a Windows Shell Link File which
|
|
// refers to a directory
|
|
//
|
|
// Manipulates: pszResPath
|
|
//
|
|
BOOL PathIsLnkToDirectory(LPCWSTR pszPath,LPWSTR pszResPath,int cchResPath)
|
|
{
|
|
|
|
WCHAR tchResPath[MAX_PATH];
|
|
|
|
if (PathIsLnkFile(pszPath)) {
|
|
|
|
if (PathGetLnkPath(pszPath,tchResPath,sizeof(WCHAR)*COUNTOF(tchResPath))) {
|
|
|
|
if (PathIsDirectory(tchResPath)) {
|
|
|
|
lstrcpyn(pszResPath,tchResPath,cchResPath);
|
|
return (TRUE);
|
|
}
|
|
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
else
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Name: PathCreateLnk()
|
|
//
|
|
// Purpose: Try to create a lnk-file in the specified directory referring
|
|
// to the specified file or directory
|
|
//
|
|
// Manipulates:
|
|
//
|
|
BOOL PathCreateLnk(LPCWSTR pszLnkDir,LPCWSTR pszPath)
|
|
{
|
|
|
|
WCHAR tchLnkFileName[MAX_PATH];
|
|
|
|
IShellLink *psl;
|
|
BOOL bSucceeded = FALSE;
|
|
BOOL fMustCopy;
|
|
|
|
// Try to construct a valid filename...
|
|
if (!SHGetNewLinkInfo(pszPath,pszLnkDir,tchLnkFileName,&fMustCopy,SHGNLI_PREFIXNAME))
|
|
return(FALSE);
|
|
|
|
if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink,NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IShellLink,&psl)))
|
|
{
|
|
IPersistFile *ppf;
|
|
|
|
if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,&ppf)))
|
|
{
|
|
WORD wsz[MAX_PATH];
|
|
|
|
/*MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,
|
|
tchLnkFileName,-1,wsz,MAX_PATH);*/
|
|
lstrcpy(wsz,tchLnkFileName);
|
|
|
|
if (NOERROR == psl->lpVtbl->SetPath(psl,pszPath) &&
|
|
SUCCEEDED(ppf->lpVtbl->Save(ppf,wsz,TRUE)))
|
|
bSucceeded = TRUE;
|
|
|
|
ppf->lpVtbl->Release(ppf);
|
|
}
|
|
psl->lpVtbl->Release(psl);
|
|
}
|
|
|
|
return(bSucceeded);
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// TrimStringW()
|
|
//
|
|
BOOL TrimStringW(LPWSTR lpString)
|
|
{
|
|
|
|
LPWSTR psz;
|
|
|
|
if (!lpString || !*lpString)
|
|
return FALSE;
|
|
|
|
// Trim left
|
|
psz = lpString;
|
|
|
|
while (*psz == L' ')
|
|
psz = CharNext(psz);
|
|
|
|
MoveMemory(lpString,psz,sizeof(WCHAR)*(lstrlen(psz) + 1));
|
|
|
|
// Trim right
|
|
psz = StrEnd(lpString);
|
|
|
|
while (*(psz = CharPrev(lpString,psz)) == L' ')
|
|
*psz = L'\0';
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// ExtractFirstArgument()
|
|
//
|
|
BOOL ExtractFirstArgument(LPCWSTR lpArgs,LPWSTR lpArg1,LPWSTR lpArg2)
|
|
{
|
|
|
|
LPWSTR psz;
|
|
BOOL bQuoted = FALSE;
|
|
|
|
lstrcpy(lpArg1,lpArgs);
|
|
if (lpArg2)
|
|
*lpArg2 = L'\0';
|
|
|
|
if (!TrimStringW(lpArg1))
|
|
return FALSE;
|
|
|
|
if (*lpArg1 == L'\"')
|
|
{
|
|
*lpArg1 = L' ';
|
|
TrimStringW(lpArg1);
|
|
bQuoted = TRUE;
|
|
}
|
|
|
|
if (bQuoted)
|
|
psz = StrChr(lpArg1,L'\"');
|
|
else
|
|
psz = StrChr(lpArg1,L' ');;
|
|
|
|
if (psz)
|
|
{
|
|
*psz = L'\0';
|
|
if (lpArg2)
|
|
lstrcpy(lpArg2,psz + 1);
|
|
}
|
|
|
|
TrimStringW(lpArg1);
|
|
|
|
if (lpArg2)
|
|
TrimStringW(lpArg2);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// QuotateFilenameStr()
|
|
//
|
|
LPWSTR QuotateFilenameStr(LPWSTR lpFile)
|
|
{
|
|
if (StrChr(lpFile,L' '))
|
|
{
|
|
MoveMemory(lpFile + 1,lpFile,sizeof(WCHAR)*(lstrlen(lpFile) + 1));
|
|
*lpFile = '\"';
|
|
lstrcat(lpFile,L"\"");
|
|
}
|
|
return lpFile;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// GetFilenameStr()
|
|
//
|
|
LPWSTR GetFilenameStr(LPWSTR lpFile)
|
|
{
|
|
LPWSTR psz = StrEnd(lpFile);
|
|
|
|
while (psz != lpFile && *CharPrev(lpFile,psz) != L'\\')
|
|
psz = CharPrev(lpFile,psz);
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// PrepareFilterStr()
|
|
//
|
|
void PrepareFilterStr(LPWSTR lpFilter)
|
|
{
|
|
LPWSTR psz = StrEnd(lpFilter);
|
|
while (psz != lpFilter)
|
|
{
|
|
if (*(psz = CharPrev(lpFilter,psz)) == L'\n')
|
|
*psz = L'\0';
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// StrTab2Space() - in place conversion
|
|
//
|
|
void StrTab2Space(LPWSTR lpsz)
|
|
{
|
|
WCHAR *c = StrChr(lpsz, L'\t');
|
|
while (c) {
|
|
*c = L' ';
|
|
c = StrChr(lpsz, L'\t');
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// ExpandEnvironmentStringsEx()
|
|
//
|
|
// Adjusted for Windows 95
|
|
//
|
|
void ExpandEnvironmentStringsEx(LPWSTR lpSrc,DWORD dwSrc)
|
|
{
|
|
WCHAR szBuf[312];
|
|
|
|
if (ExpandEnvironmentStrings(lpSrc,szBuf,COUNTOF(szBuf)))
|
|
lstrcpyn(lpSrc,szBuf,dwSrc);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// PathCanonicalizeEx()
|
|
//
|
|
//
|
|
void PathCanonicalizeEx(LPWSTR lpSrc)
|
|
{
|
|
WCHAR szDst[MAX_PATH];
|
|
|
|
if (PathCanonicalize(szDst,lpSrc))
|
|
lstrcpy(lpSrc,szDst);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// SearchPathEx()
|
|
//
|
|
// This Expansion also searches the L"Favorites" folder
|
|
//
|
|
extern WCHAR g_tchFavoritesDir[MAX_PATH];
|
|
extern WCHAR szCurDir[MAX_PATH];
|
|
|
|
DWORD SearchPathEx(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,
|
|
DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart)
|
|
{
|
|
DWORD dwRetVal = 0;
|
|
|
|
if (lstrcmp(lpFileName,L"..") == 0 || lstrcmp(lpFileName,L".") == 0)
|
|
{
|
|
if (lstrcmp(lpFileName,L"..") == 0 && PathIsRoot(szCurDir)) {
|
|
lstrcpyn(lpBuffer,L"*.*",nBufferLength);
|
|
dwRetVal = 1;
|
|
}
|
|
else
|
|
dwRetVal = SearchPath(szCurDir,lpFileName,lpExtension,
|
|
nBufferLength,lpBuffer,lpFilePart);
|
|
}
|
|
|
|
else
|
|
{
|
|
dwRetVal = SearchPath(lpPath,lpFileName,lpExtension,
|
|
nBufferLength,lpBuffer,lpFilePart);
|
|
|
|
// Search L"Favorites" if no result
|
|
if (!dwRetVal)
|
|
dwRetVal = SearchPath(g_tchFavoritesDir,lpFileName,lpExtension,
|
|
nBufferLength,lpBuffer,lpFilePart);
|
|
}
|
|
|
|
return(dwRetVal);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// FormatNumberStr()
|
|
//
|
|
int FormatNumberStr(LPWSTR lpNumberStr)
|
|
{
|
|
WCHAR *c;
|
|
WCHAR szSep[8];
|
|
int i = 0;
|
|
|
|
if (StrIsEmpty(lpNumberStr))
|
|
return(0);
|
|
|
|
if (!GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_STHOUSAND, szSep, COUNTOF(szSep))) {
|
|
szSep[0] = L'\'';
|
|
}
|
|
c = StrEnd(lpNumberStr);
|
|
|
|
while ((c = CharPrev(lpNumberStr,c)) != lpNumberStr)
|
|
{
|
|
if (++i == 3)
|
|
{
|
|
i = 0;
|
|
MoveMemory(c+1,c,sizeof(WCHAR)*(lstrlen(c)+1));
|
|
*c = szSep[0];
|
|
}
|
|
}
|
|
|
|
return(lstrlen(lpNumberStr));
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// GetDefaultFavoritesDir()
|
|
//
|
|
void GetDefaultFavoritesDir(LPWSTR lpFavDir,int cchFavDir)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
if (NOERROR == SHGetSpecialFolderLocation(
|
|
NULL,CSIDL_PERSONAL,&pidl))
|
|
{
|
|
SHGetPathFromIDList(pidl,lpFavDir);
|
|
CoTaskMemFree(pidl);
|
|
}
|
|
else
|
|
GetWindowsDirectory(lpFavDir,cchFavDir);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// GetDefaultOpenWithDir()
|
|
//
|
|
void GetDefaultOpenWithDir(LPWSTR lpOpenWithDir,int cchOpenWithDir)
|
|
{
|
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
if (NOERROR == SHGetSpecialFolderLocation(
|
|
NULL,CSIDL_DESKTOPDIRECTORY,&pidl))
|
|
{
|
|
SHGetPathFromIDList(pidl,lpOpenWithDir);
|
|
CoTaskMemFree(pidl);
|
|
}
|
|
|
|
else
|
|
GetWindowsDirectory(lpOpenWithDir,cchOpenWithDir);
|
|
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// CreateDropHandle()
|
|
//
|
|
// Creates a HDROP to generate a WM_DROPFILES message
|
|
//
|
|
//
|
|
HDROP CreateDropHandle(LPCWSTR lpFileName)
|
|
{
|
|
LPDROPFILES lpdf;
|
|
HGLOBAL hDrop;
|
|
|
|
hDrop = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,
|
|
sizeof(DROPFILES) + sizeof(WCHAR)*(lstrlen(lpFileName) + 2));
|
|
|
|
lpdf = GlobalLock(hDrop);
|
|
|
|
lpdf->pFiles = sizeof(DROPFILES);
|
|
lpdf->pt.x = 0;
|
|
lpdf->pt.y = 0;
|
|
lpdf->fNC = TRUE;
|
|
lpdf->fWide = TRUE;
|
|
|
|
lstrcpy((WCHAR*)&lpdf[1],lpFileName);
|
|
|
|
GlobalUnlock(hDrop);
|
|
|
|
return(hDrop);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// DirList_IsFileSelected()
|
|
//
|
|
// Check if a file is selected in the DirList
|
|
//
|
|
//
|
|
BOOL DirList_IsFileSelected(HWND hwnd)
|
|
{
|
|
int i;
|
|
DLITEM dli;
|
|
|
|
i = (ListView_GetSelectedCount(hwnd));
|
|
dli.mask = DLI_TYPE;
|
|
dli.ntype = DLE_NONE;
|
|
DirList_GetItem(hwnd,-1,&dli);
|
|
|
|
return (i && dli.ntype == DLE_FILE);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// ExecDDECommand()
|
|
//
|
|
// Execute a DDE command (Msg,App,Topic)
|
|
//
|
|
//
|
|
|
|
HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2,
|
|
HDDEDATA hdata, ULONG_PTR dwData1, ULONG_PTR dwData2)
|
|
{
|
|
switch (uType)
|
|
{
|
|
case XTYP_ADVDATA:
|
|
return (HDDEDATA)DDE_FACK;
|
|
|
|
default:
|
|
return (HDDEDATA)NULL;
|
|
}
|
|
UNUSED(uFmt);
|
|
UNUSED(hconv);
|
|
UNUSED(hsz1);
|
|
UNUSED(hsz2);
|
|
UNUSED(hdata);
|
|
UNUSED(dwData1);
|
|
UNUSED(dwData2);
|
|
}
|
|
|
|
BOOL ExecDDECommand(LPCWSTR lpszCmdLine,
|
|
LPCWSTR lpszDDEMsg,LPCWSTR lpszDDEApp,LPCWSTR lpszDDETopic)
|
|
{
|
|
|
|
WCHAR lpszURLExec[512];
|
|
WCHAR lpszDDEMsgBuf[256];
|
|
WCHAR *pSubst;
|
|
DWORD idInst=0;
|
|
HSZ hszService, hszTopic;
|
|
HCONV hConv;
|
|
BOOL bSuccess = TRUE;
|
|
|
|
if (StrIsEmpty(lpszCmdLine) || StrIsEmpty(lpszDDEMsg) ||
|
|
StrIsEmpty(lpszDDEApp) || StrIsEmpty(lpszDDETopic))
|
|
return FALSE;
|
|
|
|
lstrcpyn(lpszDDEMsgBuf,lpszDDEMsg,COUNTOF(lpszDDEMsgBuf));
|
|
pSubst = StrStr(lpszDDEMsgBuf, L"%1");
|
|
if (pSubst)
|
|
*(pSubst+1) = L's';
|
|
|
|
wsprintf(lpszURLExec,lpszDDEMsgBuf,lpszCmdLine);
|
|
|
|
if (DdeInitialize(&idInst, DdeCallback,
|
|
APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0L) == DMLERR_NO_ERROR)
|
|
{
|
|
hszService = DdeCreateStringHandle(idInst, lpszDDEApp, CP_WINUNICODE);
|
|
hszTopic = DdeCreateStringHandle(idInst, lpszDDETopic, CP_WINUNICODE);
|
|
if (hszService && hszTopic)
|
|
{
|
|
hConv = DdeConnect(idInst, hszService, hszTopic, NULL);
|
|
if (hConv)
|
|
{
|
|
DdeClientTransaction((LPBYTE)lpszURLExec,sizeof(WCHAR)*(lstrlen(lpszURLExec) + 1),
|
|
hConv, 0, 0, XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
|
|
DdeDisconnect(hConv);
|
|
}
|
|
else
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
if (hszTopic)
|
|
DdeFreeStringHandle(idInst, hszTopic);
|
|
if (hszService)
|
|
DdeFreeStringHandle(idInst, hszService);
|
|
DdeUninitialize(idInst);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// History Functions
|
|
//
|
|
//
|
|
BOOL History_Init(PHISTORY ph)
|
|
{
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
ZeroMemory(ph,sizeof(HISTORY));
|
|
ph->iCurItem = (-1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL History_Uninit(PHISTORY ph)
|
|
{
|
|
int i;
|
|
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < HISTORY_ITEMS; i++)
|
|
{
|
|
if (ph->psz[i])
|
|
LocalFree(ph->psz[i]);
|
|
ph->psz[i] = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL History_Add(PHISTORY ph,LPCWSTR pszNew)
|
|
{
|
|
int i;
|
|
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
// Item to be added is equal to current item
|
|
if (ph->iCurItem >= 0 && ph->iCurItem <= (HISTORY_ITEMS-1))
|
|
if (!lstrcmpi(pszNew,ph->psz[ph->iCurItem]))
|
|
return FALSE;
|
|
|
|
if (ph->iCurItem == (HISTORY_ITEMS-1))
|
|
{
|
|
// Shift
|
|
if (ph->psz[0])
|
|
LocalFree(ph->psz[0]);
|
|
|
|
MoveMemory(ph->psz,ph->psz+1,(HISTORY_ITEMS-1)*sizeof(WCHAR*));
|
|
}
|
|
|
|
else
|
|
{
|
|
ph->iCurItem++;
|
|
for (i = ph->iCurItem; i < HISTORY_ITEMS; i++)
|
|
{
|
|
if (ph->psz[i])
|
|
LocalFree(ph->psz[i]);
|
|
ph->psz[i] = NULL;
|
|
}
|
|
}
|
|
|
|
ph->psz[ph->iCurItem] = StrDup(pszNew);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL History_Forward(PHISTORY ph,LPWSTR pszItem,int cItem)
|
|
{
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
if (ph->iCurItem < (HISTORY_ITEMS-1))
|
|
if (ph->psz[ph->iCurItem+1])
|
|
{
|
|
ph->iCurItem++;
|
|
lstrcpyn(pszItem,ph->psz[ph->iCurItem],cItem);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL History_Back(PHISTORY ph,LPWSTR pszItem,int cItem)
|
|
{
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
if (ph->iCurItem > 0)
|
|
if (ph->psz[ph->iCurItem-1])
|
|
{
|
|
ph->iCurItem--;
|
|
lstrcpyn(pszItem,ph->psz[ph->iCurItem],cItem);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL History_CanForward(PHISTORY ph)
|
|
{
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
if (ph->iCurItem < (HISTORY_ITEMS-1))
|
|
if (ph->psz[ph->iCurItem+1])
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL History_CanBack(PHISTORY ph)
|
|
{
|
|
if (!ph)
|
|
return FALSE;
|
|
|
|
if (ph->iCurItem > 0)
|
|
if (ph->psz[ph->iCurItem-1])
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void History_UpdateToolbar(PHISTORY ph,HWND hwnd,int cmdBack,int cmdForward)
|
|
{
|
|
if (History_CanBack(ph))
|
|
SendMessage(hwnd,TB_ENABLEBUTTON,cmdBack,MAKELONG(1,0));
|
|
else
|
|
SendMessage(hwnd,TB_ENABLEBUTTON,cmdBack,MAKELONG(0,0));
|
|
|
|
if (History_CanForward(ph))
|
|
SendMessage(hwnd,TB_ENABLEBUTTON,cmdForward,MAKELONG(1,0));
|
|
else
|
|
SendMessage(hwnd,TB_ENABLEBUTTON,cmdForward,MAKELONG(0,0));
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// MRU functions
|
|
//
|
|
LPMRULIST MRU_Create(LPCWSTR pszRegKey,int iFlags,int iSize) {
|
|
|
|
LPMRULIST pmru = LocalAlloc(LPTR,sizeof(MRULIST));
|
|
ZeroMemory(pmru,sizeof(MRULIST));
|
|
lstrcpyn(pmru->szRegKey,pszRegKey,COUNTOF(pmru->szRegKey));
|
|
pmru->iFlags = iFlags;
|
|
pmru->iSize = min(iSize,MRU_MAXITEMS);
|
|
return(pmru);
|
|
}
|
|
|
|
BOOL MRU_Destroy(LPMRULIST pmru) {
|
|
|
|
int i;
|
|
for (i = 0; i < pmru->iSize; i++) {
|
|
if (pmru->pszItems[i])
|
|
LocalFree((LPWSTR)pmru->pszItems[i]);
|
|
}
|
|
ZeroMemory(pmru,sizeof(MRULIST));
|
|
LocalFree(pmru);
|
|
return(1);
|
|
}
|
|
|
|
int MRU_Compare(LPMRULIST pmru,LPCWSTR psz1,LPCWSTR psz2) {
|
|
|
|
if (pmru->iFlags & MRU_NOCASE)
|
|
return(lstrcmpi(psz1,psz2));
|
|
else
|
|
return(lstrcmp(psz1,psz2));
|
|
}
|
|
|
|
BOOL MRU_Add(LPMRULIST pmru,LPCWSTR pszNew) {
|
|
|
|
int i;
|
|
for (i = 0; i < pmru->iSize; i++) {
|
|
if (MRU_Compare(pmru,pmru->pszItems[i],pszNew) == 0) {
|
|
LocalFree((LPWSTR)pmru->pszItems[i]);
|
|
break;
|
|
}
|
|
}
|
|
i = min(i,pmru->iSize-1);
|
|
for (; i > 0; i--)
|
|
pmru->pszItems[i] = pmru->pszItems[i-1];
|
|
pmru->pszItems[0] = StrDup(pszNew);
|
|
return(1);
|
|
}
|
|
|
|
BOOL MRU_Delete(LPMRULIST pmru,int iIndex) {
|
|
|
|
int i;
|
|
if (iIndex < 0 || iIndex > pmru->iSize-1)
|
|
return(0);
|
|
if (pmru->pszItems[iIndex])
|
|
LocalFree((LPWSTR)pmru->pszItems[iIndex]);
|
|
for (i = iIndex; i < pmru->iSize-1; i++) {
|
|
pmru->pszItems[i] = pmru->pszItems[i+1];
|
|
pmru->pszItems[i+1] = NULL;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
BOOL MRU_Empty(LPMRULIST pmru) {
|
|
|
|
int i;
|
|
for (i = 0; i < pmru->iSize; i++) {
|
|
if (pmru->pszItems[i]) {
|
|
LocalFree((LPWSTR)pmru->pszItems[i]);
|
|
pmru->pszItems[i] = NULL;
|
|
}
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
int MRU_Enum(LPMRULIST pmru,int iIndex,LPWSTR pszItem,int cchItem) {
|
|
|
|
if (pszItem == NULL || cchItem == 0) {
|
|
int i = 0;
|
|
while ((i < pmru->iSize) && (pmru->pszItems[i])) {
|
|
++i;
|
|
}
|
|
return(i);
|
|
}
|
|
else {
|
|
if (iIndex < 0 || iIndex > pmru->iSize-1 || !pmru->pszItems[iIndex])
|
|
return(-1);
|
|
else {
|
|
lstrcpyn(pszItem,pmru->pszItems[iIndex],cchItem);
|
|
return(lstrlen(pszItem));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL MRU_Load(LPMRULIST pmru) {
|
|
|
|
int i,n = 0;
|
|
WCHAR tchName[32];
|
|
WCHAR tchItem[1024];
|
|
WCHAR *pIniSection = LocalAlloc(LPTR,sizeof(WCHAR)*32*1024);
|
|
|
|
MRU_Empty(pmru);
|
|
LoadIniSection(pmru->szRegKey,pIniSection,(int)LocalSize(pIniSection)/sizeof(WCHAR));
|
|
|
|
for (i = 0; i < pmru->iSize; i++) {
|
|
wsprintf(tchName,L"%.2i",i+1);
|
|
if (IniSectionGetString(pIniSection,tchName,L"",tchItem,COUNTOF(tchItem))) {
|
|
/*if (pmru->iFlags & MRU_UTF8) {
|
|
WCHAR wchItem[1024];
|
|
int cbw = MultiByteToWideChar(CP_UTF7,0,tchItem,-1,wchItem,COUNTOF(wchItem));
|
|
WideCharToMultiByte(CP_UTF8,0,wchItem,cbw,tchItem,COUNTOF(tchItem),NULL,NULL);
|
|
pmru->pszItems[n++] = StrDup(tchItem);
|
|
}
|
|
else*/
|
|
pmru->pszItems[n++] = StrDup(tchItem);
|
|
}
|
|
}
|
|
LocalFree(pIniSection);
|
|
return(1);
|
|
}
|
|
|
|
BOOL MRU_Save(LPMRULIST pmru) {
|
|
|
|
int i;
|
|
WCHAR tchName[32];
|
|
WCHAR *pIniSection = LocalAlloc(LPTR,sizeof(WCHAR)*32*1024);
|
|
|
|
//IniDeleteSection(pmru->szRegKey);
|
|
|
|
for (i = 0; i < pmru->iSize; i++) {
|
|
if (pmru->pszItems[i]) {
|
|
wsprintf(tchName,L"%.2i",i+1);
|
|
/*if (pmru->iFlags & MRU_UTF8) {
|
|
WCHAR tchItem[1024];
|
|
WCHAR wchItem[1024];
|
|
int cbw = MultiByteToWideChar(CP_UTF8,0,pmru->pszItems[i],-1,wchItem,COUNTOF(wchItem));
|
|
WideCharToMultiByte(CP_UTF7,0,wchItem,cbw,tchItem,COUNTOF(tchItem),NULL,NULL);
|
|
IniSectionSetString(pIniSection,tchName,tchItem);
|
|
}
|
|
else*/
|
|
IniSectionSetString(pIniSection,tchName,pmru->pszItems[i]);
|
|
}
|
|
}
|
|
SaveIniSection(pmru->szRegKey,pIniSection);
|
|
LocalFree(pIniSection);
|
|
return(1);
|
|
}
|
|
|
|
void MRU_LoadToCombobox(HWND hwnd,LPCWSTR pszKey)
|
|
{
|
|
int i;
|
|
WCHAR tch[MAX_PATH];
|
|
LPMRULIST pmru = MRU_Create(pszKey,MRU_NOCASE,8);
|
|
MRU_Load(pmru);
|
|
for (i = 0; i < MRU_Count(pmru); i++) {
|
|
MRU_Enum(pmru,i,tch,COUNTOF(tch));
|
|
SendMessage(hwnd,CB_ADDSTRING,0,(LPARAM)tch);
|
|
}
|
|
MRU_Destroy(pmru);
|
|
}
|
|
|
|
|
|
void MRU_AddOneItem(LPCWSTR pszKey,LPCWSTR pszNewItem)
|
|
{
|
|
if (StrIsNotEmpty(pszNewItem)) {
|
|
LPMRULIST pmru = MRU_Create(pszKey,MRU_NOCASE,8);
|
|
MRU_Load(pmru);
|
|
MRU_Add(pmru,pszNewItem);
|
|
MRU_Save(pmru);
|
|
MRU_Destroy(pmru);
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Themed Dialogs
|
|
Modify dialog templates to use current theme font
|
|
Based on code of MFC helper class CDialogTemplate
|
|
|
|
*/
|
|
|
|
BOOL GetThemedDialogFont(LPWSTR lpFaceName, WORD* wSize)
|
|
{
|
|
BOOL bSucceed = FALSE;
|
|
|
|
HDC hDC = GetDC(NULL);
|
|
int const iLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
HTHEME hTheme = OpenThemeData(NULL, L"WINDOWSTYLE;WINDOW");
|
|
if (hTheme) {
|
|
LOGFONT lf;
|
|
if (S_OK == GetThemeSysFont(hTheme,/*TMT_MSGBOXFONT*/805, &lf)) {
|
|
if (lf.lfHeight < 0) {
|
|
lf.lfHeight = -lf.lfHeight;
|
|
}
|
|
*wSize = (WORD)MulDiv(lf.lfHeight, 72, iLogPixelsY);
|
|
if (*wSize == 0) { *wSize = 8; }
|
|
StrCpyN(lpFaceName, lf.lfFaceName, LF_FACESIZE);
|
|
bSucceed = TRUE;
|
|
}
|
|
CloseThemeData(hTheme);
|
|
}
|
|
|
|
/*
|
|
if (!bSucceed) {
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(NONCLIENTMETRICS),&ncm,0);
|
|
if (ncm.lfMessageFont.lfHeight < 0)
|
|
ncm.lfMessageFont.lfHeight = -ncm.lfMessageFont.lfHeight;
|
|
*wSize = (WORD)MulDiv(ncm.lfMessageFont.lfHeight,72,iLogPixelsY);
|
|
if (*wSize == 0)
|
|
*wSize = 8;
|
|
StrCpyN(lpFaceName,ncm.lfMessageFont.lfFaceName,LF_FACESIZE);
|
|
}*/
|
|
|
|
return(bSucceed);
|
|
}
|
|
|
|
__inline BOOL DialogTemplate_IsDialogEx(const DLGTEMPLATE* pTemplate) {
|
|
|
|
return ((DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF;
|
|
}
|
|
|
|
__inline BOOL DialogTemplate_HasFont(const DLGTEMPLATE* pTemplate) {
|
|
|
|
return (DS_SETFONT &
|
|
(DialogTemplate_IsDialogEx(pTemplate) ? ((DLGTEMPLATEEX*)pTemplate)->style : pTemplate->style));
|
|
}
|
|
|
|
__inline int DialogTemplate_FontAttrSize(BOOL bDialogEx) {
|
|
|
|
return (int)sizeof(WORD) * (bDialogEx ? 3 : 1);
|
|
}
|
|
|
|
__inline BYTE* DialogTemplate_GetFontSizeField(const DLGTEMPLATE* pTemplate) {
|
|
|
|
BOOL bDialogEx = DialogTemplate_IsDialogEx(pTemplate);
|
|
WORD* pw;
|
|
|
|
if (bDialogEx)
|
|
pw = (WORD*)((DLGTEMPLATEEX*)pTemplate + 1);
|
|
else
|
|
pw = (WORD*)(pTemplate + 1);
|
|
|
|
if (*pw == (WORD)-1)
|
|
pw += 2;
|
|
else
|
|
while(*pw++);
|
|
|
|
if (*pw == (WORD)-1)
|
|
pw += 2;
|
|
else
|
|
while(*pw++);
|
|
|
|
while (*pw++);
|
|
|
|
return (BYTE*)pw;
|
|
}
|
|
|
|
DLGTEMPLATE* LoadThemedDialogTemplate(LPCTSTR lpDialogTemplateID,HINSTANCE hInstance) {
|
|
|
|
HRSRC hRsrc;
|
|
HGLOBAL hRsrcMem;
|
|
DLGTEMPLATE *pRsrcMem;
|
|
DLGTEMPLATE *pTemplate;
|
|
UINT dwTemplateSize = 0;
|
|
WCHAR wchFaceName[LF_FACESIZE];
|
|
WORD wFontSize;
|
|
BOOL bDialogEx;
|
|
BOOL bHasFont;
|
|
int cbFontAttr;
|
|
int cbNew;
|
|
int cbOld;
|
|
BYTE* pbNew;
|
|
BYTE* pb;
|
|
BYTE* pOldControls;
|
|
BYTE* pNewControls;
|
|
WORD nCtrl;
|
|
|
|
hRsrc = FindResource(hInstance,lpDialogTemplateID,RT_DIALOG);
|
|
if (hRsrc == NULL)
|
|
return(NULL);
|
|
|
|
hRsrcMem = LoadResource(hInstance,hRsrc);
|
|
pRsrcMem = (DLGTEMPLATE*)LockResource(hRsrcMem);
|
|
dwTemplateSize = (UINT)SizeofResource(hInstance,hRsrc);
|
|
|
|
if ((dwTemplateSize == 0) ||
|
|
(pTemplate = LocalAlloc(LPTR,dwTemplateSize+LF_FACESIZE*2)) == NULL) {
|
|
UnlockResource(hRsrcMem);
|
|
FreeResource(hRsrcMem);
|
|
return(NULL);
|
|
}
|
|
|
|
CopyMemory((BYTE*)pTemplate,pRsrcMem,(size_t)dwTemplateSize);
|
|
UnlockResource(hRsrcMem);
|
|
FreeResource(hRsrcMem);
|
|
|
|
if (!GetThemedDialogFont(wchFaceName,&wFontSize))
|
|
return(pTemplate);
|
|
|
|
bDialogEx = DialogTemplate_IsDialogEx(pTemplate);
|
|
bHasFont = DialogTemplate_HasFont(pTemplate);
|
|
cbFontAttr = DialogTemplate_FontAttrSize(bDialogEx);
|
|
|
|
if (bDialogEx)
|
|
((DLGTEMPLATEEX*)pTemplate)->style |= DS_SHELLFONT;
|
|
else
|
|
pTemplate->style |= DS_SHELLFONT;
|
|
|
|
cbNew = cbFontAttr + ((lstrlen(wchFaceName) + 1) * sizeof(WCHAR));
|
|
pbNew = (BYTE*)wchFaceName;
|
|
|
|
pb = DialogTemplate_GetFontSizeField(pTemplate);
|
|
cbOld = (int)(bHasFont ? cbFontAttr + 2 * (lstrlen((WCHAR*)(pb + cbFontAttr)) + 1) : 0);
|
|
|
|
pOldControls = (BYTE*)(((DWORD_PTR)pb + cbOld + 3) & ~(DWORD_PTR)3);
|
|
pNewControls = (BYTE*)(((DWORD_PTR)pb + cbNew + 3) & ~(DWORD_PTR)3);
|
|
|
|
nCtrl = bDialogEx ?
|
|
(WORD)((DLGTEMPLATEEX*)pTemplate)->cDlgItems :
|
|
(WORD)pTemplate->cdit;
|
|
|
|
if (cbNew != cbOld && nCtrl > 0)
|
|
MoveMemory(pNewControls,pOldControls,(size_t)(dwTemplateSize - (pOldControls - (BYTE*)pTemplate)));
|
|
|
|
*(WORD*)pb = wFontSize;
|
|
MoveMemory(pb + cbFontAttr,pbNew,(size_t)(cbNew - cbFontAttr));
|
|
|
|
return(pTemplate);
|
|
}
|
|
|
|
INT_PTR ThemedDialogBoxParam(
|
|
HINSTANCE hInstance,
|
|
LPCTSTR lpTemplate,
|
|
HWND hWndParent,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam) {
|
|
|
|
INT_PTR ret = IDABORT;
|
|
DLGTEMPLATE *pDlgTemplate = NULL;
|
|
|
|
pDlgTemplate = LoadThemedDialogTemplate(lpTemplate,hInstance);
|
|
if (pDlgTemplate) {
|
|
ret = DialogBoxIndirectParam(hInstance, pDlgTemplate, hWndParent, lpDialogFunc, dwInitParam);
|
|
LocalFree(pDlgTemplate);
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
MinimizeToTray - Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>
|
|
|
|
Changes made by flo:
|
|
- Commented out: #include "stdafx.h"
|
|
- Moved variable declaration: APPBARDATA appBarData;
|
|
- Declared GetDoAnimateMinimize() as non-static
|
|
|
|
*/
|
|
|
|
// MinimizeToTray
|
|
//
|
|
// A couple of routines to show how to make it produce a custom caption
|
|
// animation to make it look like we are minimizing to and maximizing
|
|
// from the system tray
|
|
//
|
|
// These routines are public domain, but it would be nice if you dropped
|
|
// me a line if you use them!
|
|
//
|
|
// 1.0 29.06.2000 Initial version
|
|
// 1.1 01.07.2000 The window retains it's place in the Z-order of windows
|
|
// when minimized/hidden. This means that when restored/shown, it doen't
|
|
// always appear as the foreground window unless we call SetForegroundWindow
|
|
//
|
|
// Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>
|
|
/*#include "stdafx.h"*/
|
|
|
|
// Odd. VC++6 winuser.h has IDANI_CAPTION defined (as well as IDANI_OPEN and
|
|
// IDANI_CLOSE), but the Platform SDK only has IDANI_OPEN...
|
|
|
|
// I don't know what IDANI_OPEN or IDANI_CLOSE do. Trying them in this code
|
|
// produces nothing. Perhaps they were intended for window opening and closing
|
|
// like the MAC provides...
|
|
#ifndef IDANI_OPEN
|
|
#define IDANI_OPEN 1
|
|
#endif
|
|
#ifndef IDANI_CLOSE
|
|
#define IDANI_CLOSE 2
|
|
#endif
|
|
#ifndef IDANI_CAPTION
|
|
#define IDANI_CAPTION 3
|
|
#endif
|
|
|
|
#define DEFAULT_RECT_WIDTH 150
|
|
#define DEFAULT_RECT_HEIGHT 30
|
|
|
|
// Returns the rect of where we think the system tray is. This will work for
|
|
// all current versions of the shell. If explorer isn't running, we try our
|
|
// best to work with a 3rd party shell. If we still can't find anything, we
|
|
// return a rect in the lower right hand corner of the screen
|
|
static VOID GetTrayWndRect(LPRECT lpTrayRect)
|
|
{
|
|
APPBARDATA appBarData;
|
|
// First, we'll use a quick hack method. We know that the taskbar is a window
|
|
// of class Shell_TrayWnd, and the status tray is a child of this of class
|
|
// TrayNotifyWnd. This provides us a window rect to minimize to. Note, however,
|
|
// that this is not guaranteed to work on future versions of the shell. If we
|
|
// use this method, make sure we have a backup!
|
|
HWND hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
|
|
if(hShellTrayWnd)
|
|
{
|
|
HWND hTrayNotifyWnd=FindWindowEx(hShellTrayWnd,NULL,TEXT("TrayNotifyWnd"),NULL);
|
|
if(hTrayNotifyWnd)
|
|
{
|
|
GetWindowRect(hTrayNotifyWnd,lpTrayRect);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// OK, we failed to get the rect from the quick hack. Either explorer isn't
|
|
// running or it's a new version of the shell with the window class names
|
|
// changed (how dare Microsoft change these undocumented class names!) So, we
|
|
// try to find out what side of the screen the taskbar is connected to. We
|
|
// know that the system tray is either on the right or the bottom of the
|
|
// taskbar, so we can make a good guess at where to minimize to
|
|
/*APPBARDATA appBarData;*/
|
|
appBarData.cbSize=sizeof(appBarData);
|
|
if(SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData))
|
|
{
|
|
// We know the edge the taskbar is connected to, so guess the rect of the
|
|
// system tray. Use various fudge factor to make it look good
|
|
switch(appBarData.uEdge)
|
|
{
|
|
case ABE_LEFT:
|
|
case ABE_RIGHT:
|
|
// We want to minimize to the bottom of the taskbar
|
|
lpTrayRect->top=appBarData.rc.bottom-100;
|
|
lpTrayRect->bottom=appBarData.rc.bottom-16;
|
|
lpTrayRect->left=appBarData.rc.left;
|
|
lpTrayRect->right=appBarData.rc.right;
|
|
break;
|
|
|
|
case ABE_TOP:
|
|
case ABE_BOTTOM:
|
|
// We want to minimize to the right of the taskbar
|
|
lpTrayRect->top=appBarData.rc.top;
|
|
lpTrayRect->bottom=appBarData.rc.bottom;
|
|
lpTrayRect->left=appBarData.rc.right-100;
|
|
lpTrayRect->right=appBarData.rc.right-16;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Blimey, we really aren't in luck. It's possible that a third party shell
|
|
// is running instead of explorer. This shell might provide support for the
|
|
// system tray, by providing a Shell_TrayWnd window (which receives the
|
|
// messages for the icons) So, look for a Shell_TrayWnd window and work out
|
|
// the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd,
|
|
// and stretches either the width or the height of the screen. We can't rely
|
|
// on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't
|
|
// rely on it being any size. The best we can do is just blindly use the
|
|
// window rect, perhaps limiting the width and height to, say 150 square.
|
|
// Note that if the 3rd party shell supports the same configuraion as
|
|
// explorer (the icons hosted in NotifyTrayWnd, which is a child window of
|
|
// Shell_TrayWnd), we would already have caught it above
|
|
hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
|
|
if(hShellTrayWnd)
|
|
{
|
|
GetWindowRect(hShellTrayWnd,lpTrayRect);
|
|
if(lpTrayRect->right-lpTrayRect->left>DEFAULT_RECT_WIDTH)
|
|
lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
|
|
if(lpTrayRect->bottom-lpTrayRect->top>DEFAULT_RECT_HEIGHT)
|
|
lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
|
|
|
|
return;
|
|
}
|
|
|
|
// OK. Haven't found a thing. Provide a default rect based on the current work
|
|
// area
|
|
SystemParametersInfo(SPI_GETWORKAREA,0,lpTrayRect,0);
|
|
lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
|
|
lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
|
|
}
|
|
|
|
// Check to see if the animation has been disabled
|
|
/*static */BOOL GetDoAnimateMinimize(VOID)
|
|
{
|
|
ANIMATIONINFO ai;
|
|
|
|
ai.cbSize=sizeof(ai);
|
|
SystemParametersInfo(SPI_GETANIMATION,sizeof(ai),&ai,0);
|
|
|
|
return ai.iMinAnimate?TRUE:FALSE;
|
|
}
|
|
|
|
VOID MinimizeWndToTray(HWND hWnd)
|
|
{
|
|
if(GetDoAnimateMinimize())
|
|
{
|
|
RECT rcFrom,rcTo;
|
|
|
|
// Get the rect of the window. It is safe to use the rect of the whole
|
|
// window - DrawAnimatedRects will only draw the caption
|
|
GetWindowRect(hWnd,&rcFrom);
|
|
GetTrayWndRect(&rcTo);
|
|
|
|
// Get the system to draw our animation for us
|
|
DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
|
|
}
|
|
|
|
// Add the tray icon. If we add it before the call to DrawAnimatedRects,
|
|
// the taskbar gets erased, but doesn't get redrawn until DAR finishes.
|
|
// This looks untidy, so call the functions in this order
|
|
|
|
// Hide the window
|
|
ShowWindow(hWnd,SW_HIDE);
|
|
}
|
|
|
|
VOID RestoreWndFromTray(HWND hWnd)
|
|
{
|
|
if(GetDoAnimateMinimize())
|
|
{
|
|
// Get the rect of the tray and the window. Note that the window rect
|
|
// is still valid even though the window is hidden
|
|
RECT rcFrom,rcTo;
|
|
GetTrayWndRect(&rcFrom);
|
|
GetWindowRect(hWnd,&rcTo);
|
|
|
|
// Get the system to draw our animation for us
|
|
DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
|
|
}
|
|
|
|
// Show the window, and make sure we're the foreground window
|
|
ShowWindow(hWnd,SW_SHOW);
|
|
SetActiveWindow(hWnd);
|
|
SetForegroundWindow(hWnd);
|
|
|
|
// Remove the tray icon. As described above, remove the icon after the
|
|
// call to DrawAnimatedRects, or the taskbar will not refresh itself
|
|
// properly until DAR finished
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Find next token in string
|
|
//
|
|
|
|
CHAR* StrNextTokA(CHAR* strg, const CHAR* tokens)
|
|
{
|
|
CHAR* n = NULL;
|
|
const CHAR* t = tokens;
|
|
while (t && *t) {
|
|
CHAR* const f = StrChrA(strg, *t);
|
|
if (!n || (f && (f < n))) {
|
|
n = f;
|
|
}
|
|
++t;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
WCHAR* StrNextTokW(WCHAR* strg, const WCHAR* tokens)
|
|
{
|
|
WCHAR* n = NULL;
|
|
const WCHAR* t = tokens;
|
|
while (t && *t) {
|
|
WCHAR* const f = StrChrW(strg, *t);
|
|
if (!n || (f && (f < n))) {
|
|
n = f;
|
|
}
|
|
++t;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
/// End of Helpers.c \\\
|