mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
fix: INI file handling Notepad3 and Minipath
This commit is contained in:
parent
be7ee0924d
commit
36d116e243
1
.github/copilot-instructions.md
vendored
1
.github/copilot-instructions.md
vendored
@ -156,3 +156,4 @@ Notepad3 follows a **portable-app** design for its configuration file (`Notepad3
|
||||
- **Admin redirect**: An administrator can place `Notepad3.ini=<path>` in `[Notepad3]` section of the app-directory INI to redirect to a per-user path. Up to 2 levels of redirect are supported. Redirect targets **are** auto-created (the admin intended them to exist).
|
||||
- **Key paths**: `Paths.IniFile` = active writable INI (empty if none exists), `Paths.IniFileDefault` = fallback path for "Save Settings Now" recovery.
|
||||
- **Configuration code**: All INI init logic lives in `src\Config\Config.cpp` — `FindIniFile()` → `TestIniFile()` → `CreateIniFile()` → `LoadSettings()`.
|
||||
- **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`.
|
||||
|
||||
162
CLAUDE.md
Normal file
162
CLAUDE.md
Normal file
@ -0,0 +1,162 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Notepad3 is a Windows-only Win32 desktop text editor (C/C++) built on **Scintilla** (editing component) and **Lexilla** (syntax highlighting). It ships with companion tools **MiniPath** (file browser, Ctrl+M) and **grepWinNP3** (file search/grep, Ctrl+Shift+F). Licensed under BSD 3-Clause.
|
||||
|
||||
## Build Commands
|
||||
|
||||
```powershell
|
||||
# NuGet restore (required before first build)
|
||||
nuget restore Notepad3.sln
|
||||
|
||||
# Single platform builds
|
||||
Build\Build_x64.cmd [Release|Debug]
|
||||
Build\Build_Win32.cmd [Release|Debug]
|
||||
Build\Build_ARM64.cmd [Release|Debug]
|
||||
Build\Build_x64_AVX2.cmd [Release|Debug]
|
||||
|
||||
# All platforms at once
|
||||
Build\BuildAll.cmd [Release|Debug]
|
||||
|
||||
# MSBuild directly (used by CI)
|
||||
msbuild Notepad3.sln /m /p:Configuration=Release /p:Platform=x64
|
||||
|
||||
# Clean all outputs
|
||||
Build\Clean.cmd
|
||||
```
|
||||
|
||||
Default configuration is Release. Build scripts delegate to PowerShell in `Build\scripts\`.
|
||||
|
||||
### Versioning
|
||||
|
||||
Run `Version.ps1` before building to generate `src\VersionEx.h` from templates in `Versions\`. Format: `Major.YY.Mdd.Build` (build number persisted in `Versions\build.txt`).
|
||||
|
||||
### Tests
|
||||
|
||||
```cmd
|
||||
cd test
|
||||
TestFileVersion.cmd # Verifies built binary version info
|
||||
TestAhkNotepad3.cmd # AutoHotkey-based GUI tests (requires AutoHotkey)
|
||||
```
|
||||
|
||||
### CI
|
||||
|
||||
GitHub Actions (`.github/workflows/build.yml`) builds all four platforms (Win32, x64, x64_AVX2, ARM64) in Release on `windows-2022` runners, triggered on push/PR to master.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Modules (`src\`)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| **Notepad3.c/h** | Entry point (`wWinMain`), window procedure (`MainWndProc`), global state structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`) |
|
||||
| **Edit.c/h** | Text manipulation: find/replace (Oniguruma regex), encoding conversion, clipboard, indentation, sorting, bookmarks, folding, auto-complete |
|
||||
| **Styles.c/h** | Scintilla styling, lexer selection, theme management, margin configuration |
|
||||
| **Dialogs.c/h** | All dialog boxes, DPI-aware UI interactions, window placement |
|
||||
| **Config/Config.cpp/h** | INI file management, settings loading/saving, MRU list |
|
||||
| **Encoding.c/h** | Encoding detection and conversion (integrates uchardet) |
|
||||
| **SciCall.h** | Type-safe inline wrappers for Scintilla direct function calls (avoids `SendMessage` overhead) |
|
||||
| **DynStrg.c/h** | Custom dynamic wide-string type (`HSTRINGW`) with automatic buffer management |
|
||||
| **PathLib.c/h** | Path manipulation via opaque `HPATHL` handle |
|
||||
| **TypeDefs.h** | Core type definitions (`DocPos`, `DocLn`, `cpi_enc_t`), Windows version targeting, compiler macros |
|
||||
| **MuiLanguage.c/h** | Multi-language UI support, language DLL loading |
|
||||
|
||||
### Window Hierarchy
|
||||
|
||||
```
|
||||
MainWndProc (Notepad3.c)
|
||||
+-- Scintilla Edit Control (hwndEdit / IDC_EDIT)
|
||||
+-- Toolbar (via Rebar control)
|
||||
+-- Status Bar (16 configurable fields)
|
||||
```
|
||||
|
||||
### Vendored Dependencies
|
||||
|
||||
| Directory | Library | Purpose |
|
||||
|-----------|---------|---------|
|
||||
| `scintilla\` | Scintilla 5.5.8 | Editor component (NP3 patches in `np3_patches\`, docs in `doc\`) |
|
||||
| `lexilla\` | Lexilla 5.4.6 | Syntax highlighting (NP3 patches in `np3_patches\`, docs in `doc\`) |
|
||||
| `scintilla\oniguruma\` | Oniguruma | Regex engine for find/replace |
|
||||
| `src\uchardet\` | uchardet | Mozilla encoding detection |
|
||||
| `src\tinyexpr\` / `src\tinyexprcpp\` | TinyExpr | Expression evaluator (statusbar) |
|
||||
| `src\uthash\` | uthash | Hash table / dynamic array macros |
|
||||
| `src\crypto\` | Rijndael/SHA-256 | AES-256 encryption |
|
||||
| Boost (via `vcpkg.json`) | Boost Regex & IOStreams | Used by grepWinNP3 |
|
||||
|
||||
### Syntax Lexers (`src\StyleLexers\`)
|
||||
|
||||
50+ languages, each in a `styleLexXXX.c` file. All follow the `EDITLEXER` struct pattern from `EditLexer.h`:
|
||||
|
||||
```c
|
||||
EDITLEXER lexXXX = {
|
||||
SCLEX_XXX, // Scintilla lexer ID
|
||||
"lexerName", // Lexilla lexer name (case-sensitive)
|
||||
IDS_LEX_XXX_STR, // Resource string ID
|
||||
L"Config Name", // INI section name
|
||||
L"ext1; ext2", // Default file extensions
|
||||
L"", // Extension buffer (runtime)
|
||||
&KeyWords_XXX, // Keyword lists
|
||||
{ /* EDITSTYLE array */ }
|
||||
};
|
||||
```
|
||||
|
||||
To add a new lexer: create `styleLexNEW.c`, define the `EDITLEXER` struct, register in `Styles.c` lexer array, add localization string IDs to resource files.
|
||||
|
||||
### Localization (`language\`)
|
||||
|
||||
Resource-based MUI system with 27+ locales. Each locale has a `np3_LANG_COUNTRY\` directory with `.rc` files. Language packs are built as separate DLLs (separate projects in the solution).
|
||||
|
||||
### Configuration / Portable Design
|
||||
|
||||
- INI file alongside executable (`Notepad3.ini`), no registry usage
|
||||
- **No auto-creation**: runs with defaults if no INI exists; user explicitly creates via "Save Settings Now"
|
||||
- **Admin redirect**: `Notepad3.ini=<path>` in `[Notepad3]` section redirects to per-user path (up to 2 levels)
|
||||
- Key paths: `Paths.IniFile` (active writable INI), `Paths.IniFileDefault` (fallback for recovery)
|
||||
- INI init flow: `FindIniFile()` -> `TestIniFile()` -> `CreateIniFile()` -> `LoadSettings()`
|
||||
- **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`.
|
||||
|
||||
### DarkMode (`src\DarkMode\`)
|
||||
|
||||
Windows 10/11 dark mode via IAT (Import Address Table) hooks. Includes stub DLLs for uxtheme and user32.
|
||||
|
||||
## Code Conventions
|
||||
|
||||
### Formatting
|
||||
|
||||
- LLVM-based `.clang-format` in `src\` — 4-space indentation, Stroustrup brace style, left-aligned pointers, no column limit, no include sorting
|
||||
- `.editorconfig` enforces UTF-8/CRLF for source, 4-space indent for C/C++; Lexilla code uses tabs (preserved from upstream)
|
||||
- String safety via `strsafe.h` throughout; deprecated string functions are disabled
|
||||
|
||||
### Type Conventions
|
||||
|
||||
- `DocPos` / `DocPosU` / `DocLn` for Scintilla document positions and line numbers (not raw `int`)
|
||||
- `cpi_enc_t` for encoding identifiers
|
||||
- `HSTRINGW` and `HPATHL` (opaque handle types) instead of raw `WCHAR*` buffers
|
||||
- `NOMINMAX` is defined globally — use `min()`/`max()` macros or typed equivalents
|
||||
|
||||
### Scintilla Interaction
|
||||
|
||||
Always use `SciCall.h` wrappers (e.g. `SciCall_GetTextLength()`) instead of raw `SendMessage(hwnd, SCI_XXX, ...)`. Add missing wrappers to `SciCall.h` if needed.
|
||||
|
||||
Wrapper macros follow the naming `DeclareSciCall{V|R}{0|01|1|2}`:
|
||||
- **V** = void return, **R** = has return value
|
||||
- **0** = no params, **1** = one param (wParam), **2** = two params, **01** = lParam only (wParam=0)
|
||||
- The `msg` argument is the suffix after `SCI_` (e.g. `UNDO` for `SCI_UNDO`)
|
||||
|
||||
```c
|
||||
DeclareSciCallV0(Undo, UNDO); // SciCall_Undo()
|
||||
DeclareSciCallR0(GetTextLength, GETTEXTLENGTH, DocPos); // DocPos SciCall_GetTextLength()
|
||||
DeclareSciCallV1(SetTechnology, SETTECHNOLOGY, int, technology); // SciCall_SetTechnology(int)
|
||||
DeclareSciCallR1(SupportsFeature, SUPPORTSFEATURE, bool, int, feature); // bool SciCall_SupportsFeature(int)
|
||||
```
|
||||
|
||||
### Global State
|
||||
|
||||
Application state is centralized in global structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`) defined in `Notepad3.c`. Access these through their defined interfaces rather than adding new globals.
|
||||
|
||||
### Undo/Redo Transactions
|
||||
|
||||
Use `_BEGIN_UNDO_ACTION_` / `_END_UNDO_ACTION_` macros (defined in `Notepad3.h`) to group Scintilla operations into single undo steps. These also handle notification limiting during bulk edits.
|
||||
@ -648,32 +648,34 @@ void InitDefaultSettings()
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CreateIniFile()
|
||||
// CreateIniFileEx()
|
||||
//
|
||||
//
|
||||
int CreateIniFile()
|
||||
static int CreateIniFileEx(LPCWSTR lpszPath)
|
||||
{
|
||||
int result = 0;
|
||||
if (g_wchIniFile[0] != L'\0') {
|
||||
WCHAR* pwchTail = StrRChrW(g_wchIniFile, NULL, L'\\');
|
||||
if (lpszPath[0] != L'\0') {
|
||||
|
||||
WCHAR tchDir[MAX_PATH];
|
||||
lstrcpy(tchDir, lpszPath);
|
||||
WCHAR* pwchTail = StrRChrW(tchDir, NULL, L'\\');
|
||||
|
||||
if (pwchTail) {
|
||||
*pwchTail = 0;
|
||||
SHCreateDirectoryEx(NULL, g_wchIniFile, NULL);
|
||||
*pwchTail = L'\\';
|
||||
SHCreateDirectoryEx(NULL, tchDir, NULL);
|
||||
}
|
||||
|
||||
DWORD dwFileSize = 0UL;
|
||||
|
||||
if (!PathIsExistingFile(g_wchIniFile)) {
|
||||
HANDLE hFile = CreateFile(g_wchIniFile,
|
||||
if (!PathIsExistingFile(lpszPath)) {
|
||||
HANDLE hFile = CreateFile(lpszPath,
|
||||
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
} else {
|
||||
HANDLE hFile = CreateFile(g_wchIniFile,
|
||||
HANDLE hFile = CreateFile(lpszPath,
|
||||
GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
@ -685,7 +687,7 @@ int CreateIniFile()
|
||||
}
|
||||
|
||||
if ((dwFileSize == 0) && (dwFileSize != INVALID_FILE_SIZE)) {
|
||||
result = IniFileSetString(g_wchIniFile, L"minipath", NULL, NULL);
|
||||
result = IniFileSetString(lpszPath, L"minipath", NULL, NULL);
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
@ -694,6 +696,17 @@ int CreateIniFile()
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CreateIniFile()
|
||||
//
|
||||
//
|
||||
int CreateIniFile()
|
||||
{
|
||||
return CreateIniFileEx(g_wchIniFile);
|
||||
}
|
||||
//=============================================================================
|
||||
|
||||
|
||||
@ -764,11 +777,12 @@ int CheckIniFileRedirect(LPCWSTR lpszAppName, LPCWSTR lpszKeyName, LPWSTR lpszFi
|
||||
if (PathIsRelative(tchFileExpanded)) {
|
||||
lstrcpy(lpszFile, lpszModule);
|
||||
lstrcpy(PathFindFileName(lpszFile), tchFileExpanded);
|
||||
return(1);
|
||||
} else {
|
||||
lstrcpy(lpszFile, tchFileExpanded);
|
||||
return(1);
|
||||
}
|
||||
// Redirect target doesn't exist — try to create it
|
||||
CreateIniFileEx(lpszFile);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
[Notepad3]
|
||||
Notepad3.ini=%NOTEPAD3_PORTABLE_SETTINGS%\Notepad3.ini
|
||||
[Settings2]
|
||||
DefaultDirectory=%CSIDL:MYDOCUMENTS%
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
[Notepad3]
|
||||
Notepad3.ini=%NOTEPAD3_PORTABLE_SETTINGS%\Notepad3.ini
|
||||
[Settings2]
|
||||
DefaultDirectory=%CSIDL:MYDOCUMENTS%
|
||||
|
||||
@ -990,10 +990,21 @@ static bool _CheckAndSetIniFile(HPATHL hpth_in_out)
|
||||
// ============================================================================
|
||||
|
||||
|
||||
static bool _HandleIniFileRedirect(LPCWSTR lpszSecName, LPCWSTR lpszKeyName, HPATHL hpth_in_out)
|
||||
static bool _HandleIniFileRedirect(LPCWSTR lpszSecName, LPCWSTR lpszKeyName, HPATHL hpth_in_out, int maxDepth)
|
||||
{
|
||||
bool result = false;
|
||||
if (Path_IsExistingFile(hpth_in_out)) {
|
||||
for (int depth = 0; depth < maxDepth; ++depth) {
|
||||
if (!Path_IsExistingFile(hpth_in_out)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// pick up DefaultDirectory from each redirecting INI (later files override earlier ones)
|
||||
WCHAR defDir[PATHLONG_MAX_CCH] = { L'\0' };
|
||||
if (IniFileGetString(hpth_in_out, Constants.Settings2_Section, L"DefaultDirectory", L"", defDir, COUNTOF(defDir))) {
|
||||
Path_Reset(Settings2.DefaultDirectory, defDir);
|
||||
Path_ExpandEnvStrings(Settings2.DefaultDirectory);
|
||||
}
|
||||
|
||||
HPATHL hredirect = Path_Allocate(NULL);
|
||||
LPWSTR const buf = Path_WriteAccessBuf(hredirect, PATHLONG_MAX_CCH);
|
||||
if (IniFileGetString(hpth_in_out, lpszSecName, lpszKeyName, L"", buf, PATHLONG_MAX_CCH)) {
|
||||
@ -1020,6 +1031,10 @@ static bool _HandleIniFileRedirect(LPCWSTR lpszSecName, LPCWSTR lpszKeyName, HPA
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
Path_Release(hredirect);
|
||||
break; // no redirect entry found, stop chaining
|
||||
}
|
||||
Path_Release(hredirect);
|
||||
}
|
||||
return result;
|
||||
@ -1055,11 +1070,8 @@ extern "C" bool FindIniFile()
|
||||
}
|
||||
|
||||
if (bFound) {
|
||||
// allow two redirections: administrator -> user -> custom
|
||||
// 1st:
|
||||
if (_HandleIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", Paths.IniFile)) {
|
||||
// 2nd:
|
||||
_HandleIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", Paths.IniFile);
|
||||
// allow up to two redirections: administrator -> user -> custom
|
||||
if (_HandleIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", Paths.IniFile, 2)) {
|
||||
bFound = _CheckAndSetIniFile(Paths.IniFile);
|
||||
}
|
||||
|
||||
@ -1258,11 +1270,15 @@ void LoadSettings()
|
||||
StrTrim(Settings2.DefaultExtension, L" \t.");
|
||||
|
||||
IniSectionGetStringNoQuotes(IniSecSettings2, L"DefaultDirectory", L"", pPathBuffer, PATHLONG_MAX_CCH);
|
||||
Path_Reset(Settings2.DefaultDirectory, pPathBuffer);
|
||||
Path_ExpandEnvStrings(Settings2.DefaultDirectory);
|
||||
if (StrIsNotEmpty(pPathBuffer)) {
|
||||
Path_Reset(Settings2.DefaultDirectory, pPathBuffer);
|
||||
Path_ExpandEnvStrings(Settings2.DefaultDirectory);
|
||||
}
|
||||
|
||||
IniSectionGetStringNoQuotes(IniSecSettings2, L"FileDlgFilters", L"", pPathBuffer, XHUGE_BUFFER);
|
||||
StrgReset(Settings2.FileDlgFilters, pPathBuffer);
|
||||
if (StrIsNotEmpty(pPathBuffer)) {
|
||||
StrgReset(Settings2.FileDlgFilters, pPathBuffer);
|
||||
}
|
||||
|
||||
// handle deprecated (typo) key 'FileCheckInverval'
|
||||
constexpr const LONG64 NOTSETFCI = -111LL;
|
||||
|
||||
101
src/PathLib.c
101
src/PathLib.c
@ -182,6 +182,8 @@ LPCWSTR const PATHPARENT_PREFIX = L"..\\";
|
||||
LPCWSTR const PATHDSPL_INFIX = L" ... ";
|
||||
|
||||
LPCWSTR const PATH_CSIDL_MYDOCUMENTS = L"%CSIDL:MYDOCUMENTS%";
|
||||
LPCWSTR const PATH_CSIDL_DESKTOP = L"%CSIDL:DESKTOP%";
|
||||
LPCWSTR const PATH_CSIDL_FAVORITES = L"%CSIDL:FAVORITES%";
|
||||
|
||||
|
||||
// TODO: ...
|
||||
@ -1089,7 +1091,39 @@ void PTHAPI Path_ExpandEnvStrings(HPATHL hpth_in_out)
|
||||
HSTRINGW hstr_io = ToHStrgW(hpth_in_out);
|
||||
if (!hstr_io)
|
||||
return;
|
||||
|
||||
|
||||
// resolve %CSIDL:MYDOCUMENTS% before standard env-var expansion
|
||||
if (StrgFind(hstr_io, PATH_CSIDL_MYDOCUMENTS, 0) >= 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Documents, hfld_pth)) {
|
||||
if (!Path_GetCurrentDirectory(hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
}
|
||||
StrgReplace(hstr_io, PATH_CSIDL_MYDOCUMENTS, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
// resolve %CSIDL:DESKTOP%
|
||||
if (StrgFind(hstr_io, PATH_CSIDL_DESKTOP, 0) >= 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Desktop, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(hstr_io, PATH_CSIDL_DESKTOP, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
// resolve %CSIDL:FAVORITES%
|
||||
if (StrgFind(hstr_io, PATH_CSIDL_FAVORITES, 0) >= 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Favorites, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(hstr_io, PATH_CSIDL_FAVORITES, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
ExpandEnvironmentStrgs(hstr_io, true);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1821,6 +1855,25 @@ bool PTHAPI Path_CanonicalizeEx(HPATHL hpth_in_out, const HPATHL hdir_rel_base)
|
||||
StrgReplace(hstr_io, PATH_CSIDL_MYDOCUMENTS, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
if (StrgFind(hstr_io, PATH_CSIDL_DESKTOP, 0) == 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Desktop, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(hstr_io, PATH_CSIDL_DESKTOP, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
if (StrgFind(hstr_io, PATH_CSIDL_FAVORITES, 0) == 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Favorites, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(hstr_io, PATH_CSIDL_FAVORITES, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
ExpandEnvironmentStrgs(hstr_io, true);
|
||||
|
||||
bool res = false;
|
||||
@ -2059,6 +2112,16 @@ void PTHAPI Path_RelativeToApp(HPATHL hpth_in_out, bool bSrcIsFile, bool bUnexpa
|
||||
}
|
||||
}
|
||||
|
||||
HPATHL const hdesktop_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Desktop, hdesktop_pth)) {
|
||||
Path_GetAppDirectory(hdesktop_pth);
|
||||
}
|
||||
|
||||
HPATHL const hfavorites_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Favorites, hfavorites_pth)) {
|
||||
Path_GetAppDirectory(hfavorites_pth);
|
||||
}
|
||||
|
||||
HPATHL const hprgs_pth = Path_Allocate(NULL);
|
||||
#ifdef _WIN64
|
||||
if (!Path_GetKnownFolder(&FOLDERID_ProgramFiles, hprgs_pth)) {
|
||||
@ -2075,14 +2138,28 @@ void PTHAPI Path_RelativeToApp(HPATHL hpth_in_out, bool bSrcIsFile, bool bUnexpa
|
||||
bool const bPathIsRelative = _Path_IsRelative(hpth_in_out);
|
||||
bool const bAppPathIsUsrDoc = Path_IsPrefix(husrdoc_pth, happdir_pth);
|
||||
bool const bPathIsPrefixUsrDoc = Path_IsPrefix(husrdoc_pth, hpth_in_out);
|
||||
bool const bAppPathIsDesktop = Path_IsPrefix(hdesktop_pth, happdir_pth);
|
||||
bool const bPathIsPrefixDesktop = Path_IsPrefix(hdesktop_pth, hpth_in_out);
|
||||
bool const bAppPathIsFavorites = Path_IsPrefix(hfavorites_pth, happdir_pth);
|
||||
bool const bPathIsPrefixFavorites = Path_IsPrefix(hfavorites_pth, hpth_in_out);
|
||||
DWORD dwAttrTo = (bSrcIsFile) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DIRECTORY;
|
||||
|
||||
|
||||
HPATHL htmp_pth = Path_Allocate(NULL);
|
||||
if (bUnexpandMyDocs && !bPathIsRelative && !bAppPathIsUsrDoc && bPathIsPrefixUsrDoc
|
||||
&& _Path_RelativePathTo(htmp_pth, husrdoc_pth, FILE_ATTRIBUTE_DIRECTORY, hpth_in_out, dwAttrTo)) {
|
||||
Path_Reset(hpth_in_out, PATH_CSIDL_MYDOCUMENTS);
|
||||
Path_Append(hpth_in_out, Path_Get(htmp_pth));
|
||||
}
|
||||
else if (bUnexpandMyDocs && !bPathIsRelative && !bAppPathIsDesktop && bPathIsPrefixDesktop
|
||||
&& _Path_RelativePathTo(htmp_pth, hdesktop_pth, FILE_ATTRIBUTE_DIRECTORY, hpth_in_out, dwAttrTo)) {
|
||||
Path_Reset(hpth_in_out, PATH_CSIDL_DESKTOP);
|
||||
Path_Append(hpth_in_out, Path_Get(htmp_pth));
|
||||
}
|
||||
else if (bUnexpandMyDocs && !bPathIsRelative && !bAppPathIsFavorites && bPathIsPrefixFavorites
|
||||
&& _Path_RelativePathTo(htmp_pth, hfavorites_pth, FILE_ATTRIBUTE_DIRECTORY, hpth_in_out, dwAttrTo)) {
|
||||
Path_Reset(hpth_in_out, PATH_CSIDL_FAVORITES);
|
||||
Path_Append(hpth_in_out, Path_Get(htmp_pth));
|
||||
}
|
||||
else if (!bPathIsRelative && !Path_CommonPrefix(happdir_pth, hprgs_pth, NULL)) {
|
||||
if (_Path_RelativePathTo(htmp_pth, happdir_pth, FILE_ATTRIBUTE_DIRECTORY, hpth_in_out, dwAttrTo)) {
|
||||
Path_Swap(hpth_in_out, htmp_pth);
|
||||
@ -2091,6 +2168,8 @@ void PTHAPI Path_RelativeToApp(HPATHL hpth_in_out, bool bSrcIsFile, bool bUnexpa
|
||||
|
||||
Path_Release(htmp_pth);
|
||||
Path_Release(hprgs_pth);
|
||||
Path_Release(hfavorites_pth);
|
||||
Path_Release(hdesktop_pth);
|
||||
Path_Release(husrdoc_pth);
|
||||
Path_Release(happdir_pth);
|
||||
|
||||
@ -2225,6 +2304,24 @@ void PTHAPI Path_AbsoluteFromApp(HPATHL hpth_in_out, bool bExpandEnv)
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
if (StrgFind(hstr_in_out, PATH_CSIDL_DESKTOP, 0) == 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Desktop, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(htmp_str, PATH_CSIDL_DESKTOP, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
if (StrgFind(hstr_in_out, PATH_CSIDL_FAVORITES, 0) == 0) {
|
||||
HPATHL hfld_pth = Path_Allocate(NULL);
|
||||
if (!Path_GetKnownFolder(&FOLDERID_Favorites, hfld_pth)) {
|
||||
Path_GetAppDirectory(hfld_pth);
|
||||
}
|
||||
StrgReplace(htmp_str, PATH_CSIDL_FAVORITES, PathGet(hfld_pth));
|
||||
Path_Release(hfld_pth);
|
||||
}
|
||||
|
||||
if (bExpandEnv) {
|
||||
Path_ExpandEnvStrings(htmp_pth);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user