1 /**
2  * PATH取得の共通処理
3  *
4  * Author: $(LINK2 https://twitter.com/dokutoku3, dokutoku)
5  * License: $(LINK2 https://creativecommons.org/publicdomain/zero/1.0/, CC0 1.0 Universal)
6  */
7 module remove_shortcut_arrow.path;
8 
9 
10 version (Windows) {
11 	private static import core.sys.windows.winbase;
12 	private static import core.sys.windows.windef;
13 }
14 
15 /**
16  * プログラムディレクトリ名
17  */
18 private enum program_name_path = "\\remove-shortcut-arrow\0";
19 
20 /**
21  * 出力icoファイルの相対PATH
22  */
23 private enum end_ico_path = "\\no-arrow.ico\0";
24 
25 /**
26  * 事前に組み立てられる文字列の長さ
27  */
28 private enum pre_str_length = (.program_name_path.length - "\0".length) + (.end_ico_path.length - "\0".length);
29 
30 /**
31  * WindowsのPATHに付与する謎の拡張表現
32  */
33 package enum windows_extra_path_prefix = "\\\\?\\\0"w;
34 
35 /**
36  * windows_extra_path_prefixの文字列としての長さ
37  */
38 package enum windows_extra_path_prefix_str_length = .windows_extra_path_prefix.length - "\0".length;
39 
40 /**
41  * REG_SZの最大長に制限する
42  */
43 package enum PATH_LIMIT = 1024;
44 
45 /**
46  * 出力するICOファイルの各種PATHを格納するためのバッファ
47  */
48 package struct program_path_buffer
49 {
50 	/**
51 	 * このプログラム用のディレクトリ
52 	 */
53 	wchar[.PATH_LIMIT] program_path = void;
54 
55 	/**
56 	 * icoファイルのフルPATH
57 	 */
58 	wchar[.PATH_LIMIT] ico_path = void;
59 }
60 
61 /**
62  * 優先度順に環境変数から値を取得する。
63  * 指定した環境変数が全部見つからなかったり、環境変数の値がおかしな値になっていたり、環境変数の値と事前に組み立てられる文字列の合計の長さがPATH_LIMITを超えていたりしない限り、この関数はまず失敗しない。
64  *
65  * Returns: 環境変数の値の長さ、0は失敗
66  */
67 version (Windows)
68 nothrow @nogc
69 private int get_program_directory(ref wchar[.PATH_LIMIT] program_path)
70 
71 	out(result)
72 	{
73 		if (result != 0) {
74 			assert(result < (program_path.length - .pre_str_length - .windows_extra_path_prefix_str_length - "\0".length));
75 		}
76 	}
77 
78 	do
79 	{
80 		static foreach (variable; ["ProgramData\0"w, "ALLUSERSPROFILE\0"w, "ProgramFiles\0"w, "SystemDrive\0"w, "SystemRoot\0"w, "windir\0"w]) {
81 			if (core.sys.windows.winbase.GetEnvironmentVariableW(&(variable[0]), &(program_path[0]), cast(core.sys.windows.windef.DWORD)(program_path.length - .pre_str_length - .windows_extra_path_prefix_str_length)) > 0) {
82 				int length = core.sys.windows.winbase.lstrlenW(&(program_path[0]));
83 
84 				if ((length > 0) && (program_path[length - 1] != '\\')) {
85 					return length;
86 				}
87 			}
88 		}
89 
90 		program_path[0] = '\0';
91 
92 		return 0;
93 	}
94 
95 /**
96  * 出力のためのicoファイルPATHを設定する。
97  */
98 version (Windows)
99 nothrow @nogc
100 package bool get_program_path(ref .program_path_buffer buffer)
101 
102 	do
103 	{
104 		{
105 			int length = .get_program_directory(buffer.program_path);
106 
107 			if (length == 0) {
108 				return false;
109 			}
110 
111 			if (length > (core.sys.windows.windef.MAX_PATH - .pre_str_length - "\0".length)) {
112 				buffer.ico_path = .windows_extra_path_prefix;
113 			} else {
114 				buffer.ico_path[0] = '\0';
115 			}
116 		}
117 
118 		core.sys.windows.winbase.lstrcatW(&(buffer.ico_path[0]), &(buffer.program_path[0]));
119 		core.sys.windows.winbase.lstrcatW(&(buffer.ico_path[0]), .program_name_path);
120 		buffer.program_path = buffer.ico_path;
121 		core.sys.windows.winbase.lstrcatW(&(buffer.ico_path[0]), .end_ico_path);
122 
123 		return true;
124 	}
125 
126 /**
127  * このライブラリ内で使うSystem32内のプログラム名の最大値
128  */
129 private enum MAX_PROGRAM_NAME_LENGTH = "\"\\ie4uinit.exe\" -ClearIconCache".length;
130 
131 /**
132  * System32フォルダにあるsystem32の絶対パスを取得する。
133  */
134 version (Windows)
135 nothrow @nogc
136 package int get_system32_path(ref wchar[core.sys.windows.windef.MAX_PATH] program_path)
137 
138 	do
139 	{
140 		static foreach (variable; ["SystemRoot\0"w, "windir\0"w]) {
141 			if (core.sys.windows.winbase.GetEnvironmentVariableW(&(variable[0]), &(program_path[0]), cast(core.sys.windows.windef.DWORD)(program_path.length - "\\System32".length - .MAX_PROGRAM_NAME_LENGTH)) > 0) {
142 				int length = core.sys.windows.winbase.lstrlenW(&(program_path[0]));
143 
144 				if ((length > 0) && (program_path[length - 1] != '\\')) {
145 					return length;
146 				}
147 			}
148 		}
149 
150 		return 0;
151 	}