diff --git a/lexilla/Lexilla.vcxproj b/lexilla/Lexilla.vcxproj
index 707b43380..38d512edd 100644
--- a/lexilla/Lexilla.vcxproj
+++ b/lexilla/Lexilla.vcxproj
@@ -72,6 +72,7 @@
+
@@ -95,7 +96,6 @@
-
diff --git a/lexilla/Lexilla.vcxproj.filters b/lexilla/Lexilla.vcxproj.filters
index d6b568044..aa27fac13 100644
--- a/lexilla/Lexilla.vcxproj.filters
+++ b/lexilla/Lexilla.vcxproj.filters
@@ -272,8 +272,8 @@
lexers
-
- lexers_x
+
+ lexers
diff --git a/lexilla/lexers/LexMarkdown.cxx b/lexilla/lexers/LexMarkdown.cxx
new file mode 100644
index 000000000..ac2b9f9ec
--- /dev/null
+++ b/lexilla/lexers/LexMarkdown.cxx
@@ -0,0 +1,486 @@
+/******************************************************************
+ * LexMarkdown.cxx
+ *
+ * A simple Markdown lexer for scintilla.
+ *
+ * Includes highlighting for some extra features from the
+ * Pandoc implementation; strikeout, using '#.' as a default
+ * ordered list item marker, and delimited code blocks.
+ *
+ * Limitations:
+ *
+ * Standard indented code blocks are not highlighted at all,
+ * as it would conflict with other indentation schemes. Use
+ * delimited code blocks for blanket highlighting of an
+ * entire code block. Embedded HTML is not highlighted either.
+ * Blanket HTML highlighting has issues, because some Markdown
+ * implementations allow Markdown markup inside of the HTML. Also,
+ * there is a following blank line issue that can't be ignored,
+ * explained in the next paragraph. Embedded HTML and code
+ * blocks would be better supported with language specific
+ * highlighting.
+ *
+ * The highlighting aims to accurately reflect correct syntax,
+ * but a few restrictions are relaxed. Delimited code blocks are
+ * highlighted, even if the line following the code block is not blank.
+ * Requiring a blank line after a block, breaks the highlighting
+ * in certain cases, because of the way Scintilla ends up calling
+ * the lexer.
+ *
+ * Written by Jon Strait - jstrait@moonloop.net
+ *
+ * The License.txt file describes the conditions under which this
+ * software may be distributed.
+ *
+ *****************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "ILexer.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+
+#include "WordList.h"
+#include "LexAccessor.h"
+#include "Accessor.h"
+#include "StyleContext.h"
+#include "CharacterSet.h"
+#include "LexerModule.h"
+
+using namespace Lexilla;
+
+namespace {
+
+constexpr bool IsNewline(const int ch) {
+ // sc.GetRelative(i) returns '\0' if out of range
+ return (ch == '\n' || ch == '\r' || ch == '\0');
+}
+
+}
+
+// True if can follow ch down to the end with possibly trailing whitespace
+// Does not set the state SCE_MARKDOWN_LINE_BEGIN as to allow further processing
+static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU endPos, StyleContext &sc) {
+ Sci_Position i = 0;
+ while (sc.GetRelative(++i) == ch)
+ ;
+ // Skip over whitespace
+ while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos)
+ ++i;
+ if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) {
+ sc.SetState(state);
+ sc.Forward(i);
+ return true;
+ }
+ else return false;
+}
+
+// Set the state on text section from current to length characters,
+// then set the rest until the newline to default, except for any characters matching token
+static void SetStateAndZoom(const int state, const Sci_Position length, const int token, StyleContext &sc) {
+ sc.SetState(state);
+ sc.Forward(length);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ sc.Forward();
+ bool started = false;
+ while (sc.More() && !IsNewline(sc.ch)) {
+ if (sc.ch == token && !started) {
+ sc.SetState(state);
+ started = true;
+ }
+ else if (sc.ch != token) {
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ started = false;
+ }
+ sc.Forward();
+ }
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+}
+
+// Does the previous line have more than spaces and tabs?
+static bool HasPrevLineContent(StyleContext &sc) {
+ Sci_Position i = 0;
+ // Go back to the previous newline
+ while ((--i + (Sci_Position)sc.currentPos) >= 0 && !IsNewline(sc.GetRelative(i)))
+ ;
+ while ((--i + (Sci_Position)sc.currentPos) >= 0) {
+ const int ch = sc.GetRelative(i);
+ if (ch == '\n')
+ break;
+ if (!((ch == '\r' || IsASpaceOrTab(ch))))
+ return true;
+ }
+ return false;
+}
+
+static bool AtTermStart(StyleContext &sc) {
+ return sc.currentPos == 0 || sc.chPrev == 0 || isspacechar(sc.chPrev);
+}
+
+static bool IsCompleteStyleRegion(StyleContext &sc, const char *token) {
+ bool found = false;
+ const size_t start = strlen(token);
+ Sci_Position i = static_cast(start);
+ while (!IsNewline(sc.GetRelative(i))) {
+ // make sure an empty pair of single-char tokens doesn't match
+ // with a longer token: {*}{*} != {**}
+ if (sc.GetRelative(i) == *token && sc.GetRelative(i - 1) != *token) {
+ found = start > 1U ? sc.GetRelative(i + 1) == token[1] : true;
+ break;
+ }
+ i++;
+ }
+ return AtTermStart(sc) && found;
+}
+
+static bool IsValidHrule(const Sci_PositionU endPos, StyleContext &sc) {
+ int count = 1;
+ Sci_Position i = 0;
+ for (;;) {
+ ++i;
+ int c = sc.GetRelative(i);
+ if (c == sc.ch)
+ ++count;
+ // hit a terminating character
+ else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) {
+ // Are we a valid HRULE
+ if ((IsNewline(c) || sc.currentPos + i == endPos) &&
+ count >= 3 && !HasPrevLineContent(sc)) {
+ sc.SetState(SCE_MARKDOWN_HRULE);
+ sc.Forward(i);
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ return true;
+ }
+ else {
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ return false;
+ }
+ }
+ }
+}
+
+static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
+ WordList **, Accessor &styler) {
+ Sci_PositionU endPos = startPos + length;
+ int precharCount = 0;
+ bool isLinkNameDetecting = false;
+ // Don't advance on a new loop iteration and retry at the same position.
+ // Useful in the corner case of having to start at the beginning file position
+ // in the default state.
+ bool freezeCursor = false;
+
+ // property lexer.markdown.header.eolfill
+ // Set to 1 to highlight all ATX header text.
+ bool headerEOLFill = styler.GetPropertyInt("lexer.markdown.header.eolfill", 0) == 1;
+
+ StyleContext sc(startPos, static_cast(length), initStyle, styler);
+
+ while (sc.More()) {
+ // Skip past escaped characters
+ if (sc.ch == '\\') {
+ sc.Forward();
+ continue;
+ }
+
+ // A blockquotes resets the line semantics
+ if (sc.state == SCE_MARKDOWN_BLOCKQUOTE)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+
+ // Conditional state-based actions
+ if (sc.state == SCE_MARKDOWN_CODE2) {
+ if (sc.Match("``")) {
+ const int closingSpan = (sc.GetRelative(2) == '`') ? 3 : 2;
+ sc.Forward(closingSpan);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_CODE) {
+ if (sc.ch == '`' && sc.chPrev != ' ')
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ /* De-activated because it gets in the way of other valid indentation
+ * schemes, for example multiple paragraphs inside a list item.
+ // Code block
+ else if (sc.state == SCE_MARKDOWN_CODEBK) {
+ bool d = true;
+ if (IsNewline(sc.ch)) {
+ if (sc.chNext != '\t') {
+ for (int c = 1; c < 5; ++c) {
+ if (sc.GetRelative(c) != ' ')
+ d = false;
+ }
+ }
+ }
+ else if (sc.atLineStart) {
+ if (sc.ch != '\t' ) {
+ for (int i = 0; i < 4; ++i) {
+ if (sc.GetRelative(i) != ' ')
+ d = false;
+ }
+ }
+ }
+ if (!d)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ */
+ // Strong
+ else if (sc.state == SCE_MARKDOWN_STRONG1) {
+ if ((sc.Match("**") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_STRONG2) {
+ if ((sc.Match("__") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ // Emphasis
+ else if (sc.state == SCE_MARKDOWN_EM1) {
+ if ((sc.ch == '*' && sc.chPrev != ' ') || IsNewline(sc.chNext))
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.state == SCE_MARKDOWN_EM2) {
+ if ((sc.ch == '_' && sc.chPrev != ' ') || IsNewline(sc.chNext))
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.state == SCE_MARKDOWN_CODEBK) {
+ if (sc.atLineStart && sc.Match("~~~")) {
+ Sci_Position i = 1;
+ while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos)
+ i++;
+ sc.Forward(i);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_STRIKEOUT) {
+ if ((sc.Match("~~") && sc.chPrev != ' ') || IsNewline(sc.GetRelative(2))) {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) {
+ // Header
+ if (sc.Match("######")) {
+ if (headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_HEADER6);
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc);
+ }
+ else if (sc.Match("#####")) {
+ if (headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_HEADER5);
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc);
+ }
+ else if (sc.Match("####")) {
+ if (headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_HEADER4);
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
+ }
+ else if (sc.Match("###")) {
+ if (headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_HEADER3);
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc);
+ }
+ else if (sc.Match("##")) {
+ if (headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_HEADER2);
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc);
+ }
+ else if (sc.Match("#")) {
+ // Catch the special case of an unordered list
+ if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ else if (headerEOLFill) {
+ sc.SetState(SCE_MARKDOWN_HEADER1);
+ }
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc);
+ }
+ // Code block
+ else if (sc.Match("~~~")) {
+ if (!HasPrevLineContent(sc))
+ sc.SetState(SCE_MARKDOWN_CODEBK);
+ else
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch == '=') {
+ if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) {
+ if (!headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ else
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch == '-') {
+ if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) {
+ if (!headerEOLFill)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ else {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ }
+ else if (IsNewline(sc.ch))
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ else {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ }
+
+ // The header lasts until the newline
+ else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 ||
+ sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 ||
+ sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) {
+ if (headerEOLFill) {
+ if (sc.atLineStart) {
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ freezeCursor = true;
+ }
+ }
+ else if (IsNewline(sc.ch))
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+
+ // New state only within the initial whitespace
+ if (sc.state == SCE_MARKDOWN_PRECHAR) {
+ // Blockquote
+ if (sc.ch == '>' && precharCount < 5)
+ sc.SetState(SCE_MARKDOWN_BLOCKQUOTE);
+ /*
+ // Begin of code block
+ else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4))
+ sc.SetState(SCE_MARKDOWN_CODEBK);
+ */
+ // HRule - Total of three or more hyphens, asterisks, or underscores
+ // on a line by themselves
+ else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '_') && IsValidHrule(endPos, sc))
+ ;
+ // Unordered list
+ else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '+') && IsASpaceOrTab(sc.chNext)) {
+ sc.SetState(SCE_MARKDOWN_ULIST_ITEM);
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ // Ordered list
+ else if (IsADigit(sc.ch)) {
+ int digitCount = 0;
+ while (IsADigit(sc.GetRelative(++digitCount)))
+ ;
+ if (sc.GetRelative(digitCount) == '.' &&
+ IsASpaceOrTab(sc.GetRelative(digitCount + 1))) {
+ sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
+ sc.Forward(digitCount + 1);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ } else {
+ // a textual number at the margin should be plain text
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ // Alternate Ordered list
+ else if (sc.ch == '#' && sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
+ sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch != ' ' || precharCount > 2)
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ else
+ ++precharCount;
+ }
+
+ // Any link
+ if (sc.state == SCE_MARKDOWN_LINK) {
+ if (sc.Match("](") && sc.GetRelative(-1) != '\\') {
+ sc.Forward(2);
+ isLinkNameDetecting = true;
+ }
+ else if (sc.Match("]:") && sc.GetRelative(-1) != '\\') {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (!isLinkNameDetecting && sc.ch == ']' && sc.GetRelative(-1) != '\\') {
+ sc.Forward();
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (isLinkNameDetecting && sc.ch == ')' && sc.GetRelative(-1) != '\\') {
+ sc.Forward();
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ isLinkNameDetecting = false;
+ }
+ }
+
+ // New state anywhere in doc
+ if (sc.state == SCE_MARKDOWN_DEFAULT) {
+ if (sc.atLineStart && sc.ch == '#') {
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ freezeCursor = true;
+ }
+ // Links and Images
+ if (sc.Match("![")) {
+ sc.SetState(SCE_MARKDOWN_LINK);
+ sc.Forward(1);
+ }
+ else if (sc.ch == '[' && sc.GetRelative(-1) != '\\') {
+ sc.SetState(SCE_MARKDOWN_LINK);
+ }
+ // Code - also a special case for alternate inside spacing
+ else if (sc.Match("``") && sc.GetRelative(3) != ' ' && AtTermStart(sc)) {
+ const int openingSpan = (sc.GetRelative(2) == '`') ? 2 : 1;
+ sc.SetState(SCE_MARKDOWN_CODE2);
+ sc.Forward(openingSpan);
+ }
+ else if (sc.ch == '`' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "`")) {
+ sc.SetState(SCE_MARKDOWN_CODE);
+ }
+ // Strong
+ else if (sc.Match("**") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "**")) {
+ sc.SetState(SCE_MARKDOWN_STRONG1);
+ sc.Forward();
+ }
+ else if (sc.Match("__") && sc.GetRelative(2) != ' ' && IsCompleteStyleRegion(sc, "__")) {
+ sc.SetState(SCE_MARKDOWN_STRONG2);
+ sc.Forward();
+ }
+ // Emphasis
+ else if (sc.ch == '*' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "*")) {
+ sc.SetState(SCE_MARKDOWN_EM1);
+ }
+ else if (sc.ch == '_' && sc.chNext != ' ' && IsCompleteStyleRegion(sc, "_")) {
+ sc.SetState(SCE_MARKDOWN_EM2);
+ }
+ // Strikeout
+ else if (sc.Match("~~") && !(sc.GetRelative(2) == '~' || sc.GetRelative(2) == ' ') &&
+ IsCompleteStyleRegion(sc, "~~")) {
+ sc.SetState(SCE_MARKDOWN_STRIKEOUT);
+ sc.Forward();
+ }
+ // Beginning of line
+ else if (IsNewline(sc.ch)) {
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ }
+ // Advance if not holding back the cursor for this iteration.
+ if (!freezeCursor)
+ sc.Forward();
+ freezeCursor = false;
+ }
+ sc.Complete();
+}
+
+LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown");
diff --git a/lexilla/lexers_x/LexMarkdown.cxx b/lexilla/lexers_x/homebrew/LexMarkdown.cxx
similarity index 99%
rename from lexilla/lexers_x/LexMarkdown.cxx
rename to lexilla/lexers_x/homebrew/LexMarkdown.cxx
index 38c398e1e..9daee9913 100644
--- a/lexilla/lexers_x/LexMarkdown.cxx
+++ b/lexilla/lexers_x/homebrew/LexMarkdown.cxx
@@ -277,7 +277,7 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int
freezeCursor = true;
}
else if (sc.Match("####")) {
- SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
+ SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
freezeCursor = true;
}
else if (sc.Match("###")) {
diff --git a/lexilla/src/deps.mak b/lexilla/src/deps.mak
index 4f7d228b4..6282b581f 100644
--- a/lexilla/src/deps.mak
+++ b/lexilla/src/deps.mak
@@ -364,6 +364,18 @@ $(DIR_O)/LexMake.o: \
../lexlib/StyleContext.h \
../lexlib/CharacterSet.h \
../lexlib/LexerModule.h
+$(DIR_O)/LexMarkdown.o: \
+ ../lexers/LexMarkdown.cxx \
+ ../../scintilla/include/ILexer.h \
+ ../../scintilla/include/Sci_Position.h \
+ ../../scintilla/include/Scintilla.h \
+ ../include/SciLexer.h \
+ ../lexlib/WordList.h \
+ ../lexlib/LexAccessor.h \
+ ../lexlib/Accessor.h \
+ ../lexlib/StyleContext.h \
+ ../lexlib/CharacterSet.h \
+ ../lexlib/LexerModule.h
$(DIR_O)/LexMatlab.o: \
../lexers/LexMatlab.cxx \
../../scintilla/include/ILexer.h \
@@ -681,19 +693,6 @@ $(DIR_O)/LexKotlin.o: \
../include/SciLexer.h \
../lexers_x/StringUtils.h \
../lexers_x/LexerUtils.h
-$(DIR_O)/LexMarkdown.o: \
- ../lexers_x/LexMarkdown.cxx \
- ../../scintilla/include/ILexer.h \
- ../../scintilla/include/Sci_Position.h \
- ../../scintilla/include/Scintilla.h \
- ../include/SciLexer.h \
- ../lexlib/WordList.h \
- ../lexlib/LexAccessor.h \
- ../lexlib/Accessor.h \
- ../lexlib/StyleContext.h \
- ../lexers_x/CharSetX.h \
- ../lexlib/CharacterSet.h \
- ../lexlib/LexerModule.h
$(DIR_O)/LexPython.o: \
../lexers_x/LexPython.cxx \
../../scintilla/include/ILexer.h \
diff --git a/lexilla/src/lexilla.mak b/lexilla/src/lexilla.mak
index 48d2ecacf..16bc391c3 100644
--- a/lexilla/src/lexilla.mak
+++ b/lexilla/src/lexilla.mak
@@ -94,6 +94,7 @@ LEX_OBJS=\
$(DIR_O)\LexLaTeX.obj \
$(DIR_O)\LexLua.obj \
$(DIR_O)\LexMake.obj \
+ $(DIR_O)\LexMarkdown.obj \
$(DIR_O)\LexMatlab.obj \
$(DIR_O)\LexNim.obj \
$(DIR_O)\LexNsis.obj \
@@ -117,7 +118,6 @@ LEX_OBJS=\
$(DIR_O)\LexerUtils.obj \
$(DIR_O)\LexJSON.obj \
$(DIR_O)\LexKotlin.obj \
- $(DIR_O)\LexMarkdown.obj \
$(DIR_O)\LexPython.obj \
$(DIR_O)\LexTOML.obj \
diff --git a/lexilla/src/nmdeps.mak b/lexilla/src/nmdeps.mak
index 1dd98ae85..0e578d8d9 100644
--- a/lexilla/src/nmdeps.mak
+++ b/lexilla/src/nmdeps.mak
@@ -364,6 +364,18 @@ $(DIR_O)/LexMake.obj: \
../lexlib/StyleContext.h \
../lexlib/CharacterSet.h \
../lexlib/LexerModule.h
+$(DIR_O)/LexMarkdown.obj: \
+ ../lexers/LexMarkdown.cxx \
+ ../../scintilla/include/ILexer.h \
+ ../../scintilla/include/Sci_Position.h \
+ ../../scintilla/include/Scintilla.h \
+ ../include/SciLexer.h \
+ ../lexlib/WordList.h \
+ ../lexlib/LexAccessor.h \
+ ../lexlib/Accessor.h \
+ ../lexlib/StyleContext.h \
+ ../lexlib/CharacterSet.h \
+ ../lexlib/LexerModule.h
$(DIR_O)/LexMatlab.obj: \
../lexers/LexMatlab.cxx \
../../scintilla/include/ILexer.h \
@@ -681,19 +693,6 @@ $(DIR_O)/LexKotlin.obj: \
../include/SciLexer.h \
../lexers_x/StringUtils.h \
../lexers_x/LexerUtils.h
-$(DIR_O)/LexMarkdown.obj: \
- ../lexers_x/LexMarkdown.cxx \
- ../../scintilla/include/ILexer.h \
- ../../scintilla/include/Sci_Position.h \
- ../../scintilla/include/Scintilla.h \
- ../include/SciLexer.h \
- ../lexlib/WordList.h \
- ../lexlib/LexAccessor.h \
- ../lexlib/Accessor.h \
- ../lexlib/StyleContext.h \
- ../lexers_x/CharSetX.h \
- ../lexlib/CharacterSet.h \
- ../lexlib/LexerModule.h
$(DIR_O)/LexPython.obj: \
../lexers_x/LexPython.cxx \
../../scintilla/include/ILexer.h \
diff --git a/res/StdDarkModeScheme.ini b/res/StdDarkModeScheme.ini
index f1ebb8877..709528736 100644
--- a/res/StdDarkModeScheme.ini
+++ b/res/StdDarkModeScheme.ini
@@ -397,7 +397,7 @@ Preprocessor=fore:#F27E0D
[Markdown]
Strong=bold
Emphasis=italic
-Header 1=bold; fore:#272702; back:#848DCF; eolfilled
+Header 1=bold; fore:#969685; back:#5A67BE; eolfilled
Header 2=bold; fore:#A8CCDA; back:#1F6AB4; eolfilled
Header 3=bold; fore:#A8CCDA; back:#154B7F; eolfilled
Header 4=bold; fore:#A8CCDA; eolfilled
diff --git a/src/StyleLexers/EditLexer.c b/src/StyleLexers/EditLexer.c
index 7aab77e00..b1d8dee27 100644
--- a/src/StyleLexers/EditLexer.c
+++ b/src/StyleLexers/EditLexer.c
@@ -234,6 +234,10 @@ void Lexer_SetLexerSpecificProperties(const int lexerId) {
//SciCall_SetProperty("lexer.sql.allow.dotted.word", "0");
break;
+ case SCLEX_MARKDOWN:
+ SciCall_SetProperty("lexer.markdown.header.eolfill", "1");
+ break;
+
case SCLEX_NSIS:
SciCall_SetProperty("nsis.ignorecase", "1");
break;
diff --git a/src/StyleLexers/styleLexMARKDOWN.c b/src/StyleLexers/styleLexMARKDOWN.c
index ab3a6b686..9e6721fe2 100644
--- a/src/StyleLexers/styleLexMARKDOWN.c
+++ b/src/StyleLexers/styleLexMARKDOWN.c
@@ -14,7 +14,7 @@ EDITLEXER lexMARKDOWN =
{ {SCE_MARKDOWN_LINE_BEGIN}, IDS_LEX_STR_63317, L"Line Begin", L"", L"" },
{ {MULTI_STYLE(SCE_MARKDOWN_STRONG1,SCE_MARKDOWN_STRONG2,0,0)}, IDS_LEX_STR_63318, L"Strong", L"bold", L"" },
{ {MULTI_STYLE(SCE_MARKDOWN_EM1,SCE_MARKDOWN_EM2,0,0)}, IDS_LEX_STR_63319, L"Emphasis", L"italic", L"" },
- { {SCE_MARKDOWN_HEADER1}, IDS_LEX_STR_63320, L"Header 1", L"bold; fore:#FFFFE2; back:#3D3DD3; eolfilled", L"" },
+ { {SCE_MARKDOWN_HEADER1}, IDS_LEX_STR_63320, L"Header 1", L"bold; fore:#FFFFE2; back:#8BA4ED; eolfilled", L"" },
{ {SCE_MARKDOWN_HEADER2}, IDS_LEX_STR_63321, L"Header 2", L"bold; fore:#336193; back:#9DCEFF; eolfilled", L"" },
{ {SCE_MARKDOWN_HEADER3}, IDS_LEX_STR_63322, L"Header 3", L"bold; fore:#336193; back:#D9ECFF; eolfilled", L"" },
{ {SCE_MARKDOWN_HEADER4}, IDS_LEX_STR_63323, L"Header 4", L"bold; fore:#336193; eolfilled", L"" },
diff --git a/test/test_files/StyleLexers/styleLexCPP/Config.cpp b/test/test_files/StyleLexers/styleLexCPP/Config.cpp
index 5a4f0ef6d..66365521f 100644
--- a/test/test_files/StyleLexers/styleLexCPP/Config.cpp
+++ b/test/test_files/StyleLexers/styleLexCPP/Config.cpp
@@ -13,6 +13,17 @@ addindex
// TODO : fkdlkldfdl
// ----------------------------------------------------------------------------
+namespace {
+
+1
+2
+3
+5
+4
+6
+7
+8
+9
extern "C" {
#include "Version.h"
@@ -477,4 +488,24540 @@ extern "C" bool FindIniFile()
}
//=============================================================================
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================
+
+extern "C" {
+#include "Version.h"
+#include "Helpers.h"
+#include "Styles.h"
+#include "Dialogs.h"
+#include "Encoding.h"
+#include "Notepad3.h"
+#include "resource.h"
+}
+
+extern "C" const int g_FontQuality[4];
+extern "C" WININFO s_WinInfo;
+extern "C" WININFO s_DefWinInfo;
+
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V1;
+extern "C" const WCHAR* const TBBUTTON_DEFAULT_IDS_V2;
+
+extern "C" prefix_t s_mxSBPrefix[STATUS_SECTOR_COUNT];
+extern "C" prefix_t s_mxSBPostfix[STATUS_SECTOR_COUNT];
+extern "C" bool s_iStatusbarVisible[STATUS_SECTOR_COUNT];
+extern "C" int s_iStatusbarWidthSpec[STATUS_SECTOR_COUNT];
+extern "C" int s_vSBSOrder[STATUS_SECTOR_COUNT];
+
+extern "C" WCHAR s_tchToolbarBitmap[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapHot[MAX_PATH];
+extern "C" WCHAR s_tchToolbarBitmapDisabled[MAX_PATH];
+
+extern "C" bool s_bEnableSaveSettings;
+extern "C" int s_iToolBarTheme;
+
+extern "C" bool s_flagPosParam;
+extern "C" int s_flagWindowPos;
+extern "C" int s_flagReuseWindow;
+extern "C" int s_flagSingleFileInstance;
+extern "C" int s_flagMultiFileArg;
+extern "C" int s_flagShellUseSystemMRU;
+extern "C" int s_flagPrintFileAndLeave;
+
+
+// ----------------------------------------------------------------------------
+
+#include "SimpleIni.h"
+#include "Config.h"
+
+// ============================================================================
+
+static bool const s_bIsUTF8 = true;
+static bool const s_bUseMultiKey = false;
+static bool const s_bUseMultiLine = false;
+static bool const s_bSetSpaces = false;
+
+// ----------------------------------------------------------------------------
+
+static int s_iStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
+
+// ----------------------------------------------------------------------------
+
+#define SI_SUCCESS(RC) ((RC) >= SI_OK)
+
+// ============================================================================
+
+static CSimpleIni s_INI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+
+
+extern "C" bool LoadIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.Reset();
+ SI_Error const rc = s_INI.LoadFile(lpIniFilePath);
+ return SI_SUCCESS(rc);
+}
+
+extern "C" bool SaveIniFile(LPCWSTR lpIniFilePath)
+{
+ s_INI.SetSpaces(s_bSetSpaces);
+ SI_Error const rc = s_INI.SaveFile(lpIniFilePath, true);
+ if (SI_SUCCESS(rc)) {
+ s_INI.Reset(); // done
+ }
+ return SI_SUCCESS(rc);
+}
+
+extern "C" void ReleaseIniFile()
+{
+ s_INI.Reset();
+}
+
+
+//=============================================================================
+//
+// Manipulation of (cached) ini file
+//
+//=============================================================================
+
+
+extern "C" size_t IniSectionGetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString,
+ s_INI.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" int IniSectionGetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ bool bHasMultiple = false;
+ int const iValue = (int)s_INI.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+}
+// ============================================================================
+
+
+extern "C" double IniSectionGetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dDefault)
+{
+ bool bHasMultiple = false;
+ double const dValue = s_INI.GetDoubleValue(lpSectionName, lpKeyName, dDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return dValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionGetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ bool bHasMultiple = false;
+ bool const bValue = s_INI.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ SI_Error const rc = s_INI.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+extern "C" bool IniSectionSetHex(LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ SI_Error const rc = s_INI.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, true, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetDouble(LPCWSTR lpSectionName, LPCWSTR lpKeyName, double dValue)
+{
+ SI_Error const rc = s_INI.SetDoubleValue(lpSectionName, lpKeyName, dValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionSetBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ SI_Error const rc = s_INI.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionDelete(LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ return s_INI.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+}
+// ============================================================================
+
+
+extern "C" bool IniSectionClear(LPCWSTR lpSectionName, bool bRemoveEmpty)
+{
+
+ bool const ok = s_INI.Delete(lpSectionName, nullptr, bRemoveEmpty);
+ if (!bRemoveEmpty) {
+ SI_Error const rc = s_INI.SetValue(lpSectionName, nullptr, nullptr);
+ return SI_SUCCESS(rc);
+ }
+ return ok;
+}
+// ============================================================================
+
+
+extern "C" bool IniClearAllSections(LPCWSTR lpPrefix, bool bRemoveEmpty)
+{
+ size_t const len = StringCchLen(lpPrefix, 0);
+
+ CSimpleIni::TNamesDepend Sections;
+ s_INI.GetAllSections(Sections);
+ for (const auto& section : Sections)
+ {
+ if (StringCchCompareNI(section.pItem, len, lpPrefix, len) == 0)
+ {
+ s_INI.Delete(section.pItem, nullptr, bRemoveEmpty);
+ }
+ }
+ return true;
+}
+// ============================================================================
+
+
+// ============================================================================
+// ============================================================================
+
+
+extern "C" size_t IniFileGetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
+ LPWSTR lpReturnedString, size_t cchReturnedString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ StringCchCopyW(lpReturnedString, cchReturnedString, Ini.GetValue(lpSectionName, lpKeyName, lpDefault, &bHasMultiple));
+ //assert(!bHasMultiple);
+ }
+ return StringCchLenW(lpReturnedString, cchReturnedString);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetString(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ SI_Error const res = Ini.SetValue(lpSectionName, lpKeyName, lpString, nullptr, !s_bUseMultiKey);
+ rc = SI_SUCCESS(res) ? SI_OK : SI_FAIL;
+
+ if (SI_SUCCESS(rc)) {
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" int IniFileGetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ int const iValue = Ini.GetLongValue(lpSectionName, lpKeyName, (long)iDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return iValue;
+ }
+ return iDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetInt(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, int iValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetLongValue(lpSectionName, lpKeyName, (long)iValue, nullptr, false, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileGetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bDefault)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error const rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ bool bHasMultiple = false;
+ bool const bValue = Ini.GetBoolValue(lpSectionName, lpKeyName, bDefault, &bHasMultiple);
+ //assert(!bHasMultiple);
+ return bValue;
+ }
+ return bDefault;
+}
+// ============================================================================
+
+
+extern "C" bool IniFileSetBool(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bValue)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc)) {
+ Ini.SetBoolValue(lpSectionName, lpKeyName, bValue, nullptr, !s_bUseMultiKey);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+extern "C" bool IniFileDelete(LPCWSTR lpFilePath, LPCWSTR lpSectionName, LPCWSTR lpKeyName, bool bRemoveEmpty)
+{
+ CSimpleIni Ini(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
+ SI_Error rc = Ini.LoadFile(lpFilePath);
+ if (SI_SUCCESS(rc))
+ {
+ Ini.Delete(lpSectionName, lpKeyName, bRemoveEmpty);
+ Ini.SetSpaces(s_bSetSpaces);
+ rc = Ini.SaveFile(Globals.IniFile, true);
+ }
+ return SI_SUCCESS(rc);
+}
+// ============================================================================
+
+
+//=============================================================================
+//
+// _CheckIniFile()
+//
+static bool _CheckIniFile(LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(lpszFile, tchFileExpanded, COUNTOF(tchFileExpanded));
+
+ if (PathIsRelative(tchFileExpanded))
+ {
+ WCHAR tchBuild[MAX_PATH] = { L'\0' };
+ // program directory
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ StringCchCopy(PathFindFileName(tchBuild), COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // sub directory (.\np3\)
+ StringCchCopy(tchBuild, COUNTOF(tchBuild), lpszModule);
+ PathCchRemoveFileSpec(tchBuild, COUNTOF(tchBuild));
+ StringCchCat(tchBuild, COUNTOF(tchBuild), L"\\np3\\");
+ StringCchCat(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ // Application Data (%APPDATA%)
+ if (GetKnownFolderPath(FOLDERID_RoamingAppData, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ // Home (%HOMEPATH%) user's profile dir
+ if (GetKnownFolderPath(FOLDERID_Profile, tchBuild, COUNTOF(tchBuild))) {
+ PathCchAppend(tchBuild, COUNTOF(tchBuild), tchFileExpanded);
+ if (PathFileExists(tchBuild)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchBuild);
+ return true;
+ }
+ }
+ //~// in general search path
+ //~if (SearchPath(NULL,tchFileExpanded,L".ini",COUNTOF(tchBuild),tchBuild,NULL)) {
+ //~ StringCchCopy(lpszFile,MAX_PATH,tchBuild);
+ //~ return true;
+ //~}
+ }
+ else if (PathFileExists(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+static bool _CheckIniFileRedirect(LPWSTR lpszAppName, LPWSTR lpszKeyName, LPWSTR lpszFile, LPCWSTR lpszModule)
+{
+ WCHAR tch[MAX_PATH] = { L'\0' };
+ if (GetPrivateProfileString(lpszAppName, lpszKeyName, L"", tch, COUNTOF(tch), lpszFile)) {
+ if (_CheckIniFile(tch, lpszModule)) {
+ StringCchCopy(lpszFile, MAX_PATH, tch);
+ return true;
+ }
+ WCHAR tchFileExpanded[MAX_PATH] = { L'\0' };
+ ExpandEnvironmentStrings(tch, tchFileExpanded, COUNTOF(tchFileExpanded));
+ if (PathIsRelative(tchFileExpanded)) {
+ StringCchCopy(lpszFile, MAX_PATH, lpszModule);
+ StringCchCopy(PathFindFileName(lpszFile), MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ StringCchCopy(lpszFile, MAX_PATH, tchFileExpanded);
+ return true;
+ }
+ return false;
+}
+// ============================================================================
+
+
+extern "C" bool FindIniFile()
+{
+ bool bFound = false;
+ WCHAR tchPath[MAX_PATH] = { L'\0' };
+ WCHAR tchModule[MAX_PATH] = { L'\0' };
+
+ GetModuleFileName(NULL, tchModule, COUNTOF(tchModule));
+
+ // set env path to module dir
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ SetEnvironmentVariable(NOTEPAD3_MODULE_DIR_ENV_VAR, tchPath);
+
+ if (StrIsNotEmpty(Globals.IniFile)) {
+ if (StringCchCompareXI(Globals.IniFile, L"*?") == 0) {
+ return bFound;
+ }
+ if (!_CheckIniFile(Globals.IniFile, tchModule)) {
+ ExpandEnvironmentStringsEx(Globals.IniFile, COUNTOF(Globals.IniFile));
+ if (PathIsRelative(Globals.IniFile)) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), tchModule);
+ PathCchRemoveFileSpec(tchPath, COUNTOF(tchPath));
+ PathCchAppend(tchPath, COUNTOF(tchPath), Globals.IniFile);
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ }
+ }
+ else {
+ StringCchCopy(tchPath, COUNTOF(tchPath), PathFindFileName(tchModule));
+ PathCchRenameExtension(tchPath, COUNTOF(tchPath), L".ini");
+
+ bFound = _CheckIniFile(tchPath, tchModule);
+
+ if (!bFound) {
+ StringCchCopy(tchPath, COUNTOF(tchPath), L"Notepad3.ini");
+ bFound = _CheckIniFile(tchPath, tchModule);
+ }
+
+ if (bFound)
+ {
+ // allow two redirections: administrator -> user -> custom
+ if (_CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule))
+ {
+ _CheckIniFileRedirect(_W(SAPPNAME), _W(SAPPNAME) L".ini", tchPath, tchModule);
+ }
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchPath);
+ }
+ else {
+ StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), tchModule);
+ PathCchRenameExtension(Globals.IniFile, COUNTOF(Globals.IniFile), L".ini");
+ }
+ }
+
+ NormalizePathEx(Globals.IniFile, COUNTOF(Globals.IniFile), true, false);
+
+ return bFound;
+}
+//=============================================================================