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 }