191
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
|
|
3 * All rights reserved. This program and the accompanying materials
|
|
4 * are made available under the terms of the Eclipse Public License v1.0
|
|
5 * which accompanies this distribution, and is available at
|
|
6 * http://www.eclipse.org/legal/epl-v10.html
|
|
7 *
|
|
8 * Contributors:
|
|
9 * IBM Corporation - initial API and implementation
|
|
10 * Port to the D Programming language:
|
|
11 * Frank Benoit <benoit@tionex.de>
|
|
12 *******************************************************************************/
|
|
13 module dwt.program.Program;
|
|
14
|
|
15 import dwt.DWT;
|
|
16 import dwt.graphics.Image;
|
|
17 import dwt.graphics.ImageData;
|
|
18 import dwt.internal.win32.OS;
|
|
19
|
|
20 import dwt.dwthelper.utils;
|
|
21 import dwt.dwthelper.Integer;
|
|
22 static import tango.text.convert.Utf;
|
|
23
|
|
24 /**
|
|
25 * Instances of this class represent programs and
|
|
26 * their associated file extensions in the operating
|
|
27 * system.
|
|
28 */
|
|
29 public final class Program {
|
|
30 char[] name;
|
|
31 char[] command;
|
|
32 char[] iconName;
|
|
33 char[] extension;
|
|
34 static const char[][] ARGUMENTS = ["%1"[], "%l", "%L"]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
|
35
|
|
36 /**
|
|
37 * Prevents uninitialized instances from being created outside the package.
|
|
38 */
|
|
39 this () {
|
|
40 }
|
|
41
|
|
42 static char[] assocQueryString (int assocStr, TCHAR[] key, bool expand) {
|
|
43 TCHAR[] pszOut = NewTCHARs(0, 1024);
|
|
44 uint[1] pcchOut;
|
|
45 pcchOut[0] = pszOut.length;
|
|
46 int result = OS.AssocQueryString(OS.ASSOCF_NOTRUNCATE, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
|
|
47 if (result is OS.E_POINTER) {
|
|
48 pszOut = NewTCHARs(0, pcchOut [0]);
|
|
49 result = OS.AssocQueryString(OS.ASSOCF_NOTRUNCATE, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
|
|
50 }
|
|
51 if (result is 0) {
|
|
52 if (!OS.IsWinCE && expand) {
|
|
53 int length_ = OS.ExpandEnvironmentStrings (pszOut.ptr, null, 0);
|
|
54 if (length_ !is 0) {
|
|
55 TCHAR[] lpDst = NewTCHARs (0, length_);
|
|
56 OS.ExpandEnvironmentStrings (pszOut.ptr, lpDst.ptr, length_);
|
|
57 return tango.text.convert.Utf.toString( lpDst[ 0 .. Math.max (0, length_ - 1) ] );
|
|
58 } else {
|
|
59 return "";
|
|
60 }
|
|
61 } else {
|
|
62 return tango.text.convert.Utf.toString( pszOut[ 0 .. Math.max (0, pcchOut [0] - 1)]);
|
|
63 }
|
|
64 }
|
|
65 return null;
|
|
66 }
|
|
67
|
|
68 /**
|
|
69 * Finds the program that is associated with an extension.
|
|
70 * The extension may or may not begin with a '.'. Note that
|
|
71 * a <code>Display</code> must already exist to guarantee that
|
|
72 * this method returns an appropriate result.
|
|
73 *
|
|
74 * @param extension the program extension
|
|
75 * @return the program or <code>null</code>
|
|
76 *
|
|
77 * @exception IllegalArgumentException <ul>
|
|
78 * <li>ERROR_NULL_ARGUMENT when extension is null</li>
|
|
79 * </ul>
|
|
80 */
|
|
81 public static Program findProgram (char[] extension) {
|
|
82 if (extension is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
|
|
83 if (extension.length is 0) return null;
|
|
84 if (extension.charAt (0) !is '.') extension = "." ~ extension; //$NON-NLS-1$
|
|
85 /* Use the character encoding for the default locale */
|
|
86 TCHAR[] key = StrToTCHARs (0, extension, true);
|
|
87 Program program = null;
|
|
88 if (OS.IsWinCE) {
|
|
89 void*[1] phkResult;
|
|
90 if (OS.RegOpenKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
|
|
91 return null;
|
|
92 }
|
|
93 uint [1] lpcbData;
|
|
94 int result = OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr);
|
|
95 if (result is 0) {
|
|
96 TCHAR[] lpData = NewTCHARs (0, lpcbData [0] / TCHAR.sizeof);
|
|
97 result = OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr);
|
|
98 if (result is 0) program = getProgram ( TCHARzToStr( lpData.ptr ), extension);
|
|
99 }
|
|
100 OS.RegCloseKey (phkResult [0]);
|
|
101 } else {
|
|
102 char[] command = assocQueryString (OS.ASSOCSTR_COMMAND, key, true);
|
|
103 if (command !is null) {
|
|
104 char[] name = null;
|
|
105 if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYDOCNAME, key, false);
|
|
106 if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYAPPNAME, key, false);
|
|
107 if (name is null) name = "";
|
|
108 char[] iconName = assocQueryString (OS.ASSOCSTR_DEFAULTICON, key, true);
|
|
109 if (iconName is null) iconName = "";
|
|
110 program = new Program ();
|
|
111 program.name = name;
|
|
112 program.command = command;
|
|
113 program.iconName = iconName;
|
|
114 program.extension = extension;
|
|
115 }
|
|
116 }
|
|
117 return program;
|
|
118 }
|
|
119
|
|
120 /**
|
|
121 * Answer all program extensions in the operating system. Note
|
|
122 * that a <code>Display</code> must already exist to guarantee
|
|
123 * that this method returns an appropriate result.
|
|
124 *
|
|
125 * @return an array of extensions
|
|
126 */
|
|
127 public static char[] [] getExtensions () {
|
|
128 char[] [] extensions = new char[] [1024];
|
|
129 /* Use the character encoding for the default locale */
|
|
130 TCHAR[] lpName = NewTCHARs (0, 1024);
|
|
131 uint [1] lpcName; lpcName[0] = lpName.length;
|
|
132 FILETIME ft;
|
|
133 int dwIndex = 0, count = 0;
|
|
134 while (OS.RegEnumKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
|
|
135 char[] extension = TCHARsToStr( lpName[0 .. lpcName[0] ]);
|
|
136 lpcName [0] = lpName.length;
|
|
137 if (extension.length > 0 && extension.charAt (0) is '.') {
|
|
138 if (count is extensions.length) {
|
|
139 char[][] newExtensions = new char[][]( extensions.length + 1024 );
|
|
140 System.arraycopy (extensions, 0, newExtensions, 0, extensions.length);
|
|
141 extensions = newExtensions;
|
|
142 }
|
|
143 extensions [count++] = extension;
|
|
144 }
|
|
145 dwIndex++;
|
|
146 }
|
|
147 if (count !is extensions.length) {
|
|
148 char[][] newExtension = new char[][]( count );
|
|
149 System.arraycopy (extensions, 0, newExtension, 0, count);
|
|
150 extensions = newExtension;
|
|
151 }
|
|
152 return extensions;
|
|
153 }
|
|
154
|
|
155 static char[] getKeyValue (char[] string, bool expand) {
|
|
156 /* Use the character encoding for the default locale */
|
|
157 TCHAR[] key = StrToTCHARs (0, string, true);
|
|
158 void* [1] phkResult;
|
|
159 if (OS.RegOpenKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
|
|
160 return null;
|
|
161 }
|
|
162 char[] result = null;
|
|
163 uint [1] lpcbData;
|
|
164 if (OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr) is 0) {
|
|
165 result = "";
|
|
166 int length_ = lpcbData [0] / TCHAR.sizeof;
|
|
167 if (length_ !is 0) {
|
|
168 /* Use the character encoding for the default locale */
|
|
169 TCHAR[] lpData = NewTCHARs (0, length_);
|
|
170 if (OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr) is 0) {
|
|
171 if (!OS.IsWinCE && expand) {
|
|
172 length_ = OS.ExpandEnvironmentStrings (lpData.ptr, null, 0);
|
|
173 if (length_ !is 0) {
|
|
174 TCHAR[] lpDst = NewTCHARs (0, length_);
|
|
175 OS.ExpandEnvironmentStrings (lpData.ptr, lpDst.ptr, length_);
|
|
176 result = tango.text.convert.Utf.toString ( lpDst[0 .. Math.max (0, length_ - 1) ] );
|
|
177 }
|
|
178 } else {
|
|
179 length_ = Math.max (0, lpData.length - 1);
|
|
180 result = tango.text.convert.Utf.toString ( lpData[0 .. length_]);
|
|
181 }
|
|
182 }
|
|
183 }
|
|
184 }
|
|
185 if (phkResult [0] !is null) OS.RegCloseKey (phkResult [0]);
|
|
186 return result;
|
|
187 }
|
|
188
|
|
189 static Program getProgram (char[] key, char[] extension) {
|
|
190
|
|
191 /* Name */
|
|
192 char[] name = getKeyValue (key, false);
|
|
193 if (name is null || name.length is 0) {
|
|
194 name = key;
|
|
195 }
|
|
196
|
|
197 /* Command */
|
|
198 char[] DEFAULT_COMMAND = "\\shell"; //$NON-NLS-1$
|
|
199 char[] defaultCommand = getKeyValue (key ~ DEFAULT_COMMAND, true);
|
|
200 if (defaultCommand is null || defaultCommand.length is 0) defaultCommand = "open"; //$NON-NLS-1$
|
|
201 char[] COMMAND = "\\shell\\" ~ defaultCommand ~ "\\command"; //$NON-NLS-1$
|
|
202 char[] command = getKeyValue (key ~ COMMAND, true);
|
|
203 if (command is null || command.length is 0) return null;
|
|
204
|
|
205 /* Icon */
|
|
206 char[] DEFAULT_ICON = "\\DefaultIcon"; //$NON-NLS-1$
|
|
207 char[] iconName = getKeyValue (key ~ DEFAULT_ICON, true);
|
|
208 if (iconName is null) iconName = ""; //$NON-NLS-1$
|
|
209
|
|
210 /* Program */
|
|
211 Program program = new Program ();
|
|
212 program.name = name;
|
|
213 program.command = command;
|
|
214 program.iconName = iconName;
|
|
215 program.extension = extension;
|
|
216 return program;
|
|
217 }
|
|
218
|
|
219 /**
|
|
220 * Answers all available programs in the operating system. Note
|
|
221 * that a <code>Display</code> must already exist to guarantee
|
|
222 * that this method returns an appropriate result.
|
|
223 *
|
|
224 * @return an array of programs
|
|
225 */
|
|
226 public static Program [] getPrograms () {
|
|
227 Program [] programs = new Program [1024];
|
|
228 /* Use the character encoding for the default locale */
|
|
229 TCHAR[] lpName = NewTCHARs (0, 1024);
|
|
230 uint [1] lpcName; lpcName[0] = lpName.length;
|
|
231 FILETIME ft;
|
|
232 int dwIndex = 0, count = 0;
|
|
233 while (OS.RegEnumKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
|
|
234 char[] path = tango.text.convert.Utf.toString ( lpName[0 .. lpcName [0]]);
|
|
235 lpcName [0] = lpName.length ;
|
|
236 Program program = getProgram (path, null);
|
|
237 if (program !is null) {
|
|
238 if (count is programs.length) {
|
|
239 Program [] newPrograms = new Program [programs.length + 1024];
|
|
240 System.arraycopy (programs, 0, newPrograms, 0, programs.length);
|
|
241 programs = newPrograms;
|
|
242 }
|
|
243 programs [count++] = program;
|
|
244 }
|
|
245 dwIndex++;
|
|
246 }
|
|
247 if (count !is programs.length) {
|
|
248 Program [] newPrograms = new Program [count];
|
|
249 System.arraycopy (programs, 0, newPrograms, 0, count);
|
|
250 programs = newPrograms;
|
|
251 }
|
|
252 return programs;
|
|
253 }
|
|
254
|
|
255 /**
|
|
256 * Launches the executable associated with the file in
|
|
257 * the operating system. If the file is an executable,
|
|
258 * then the executable is launched. Note that a <code>Display</code>
|
|
259 * must already exist to guarantee that this method returns
|
|
260 * an appropriate result.
|
|
261 *
|
|
262 * @param fileName the file or program name
|
|
263 * @return <code>true</code> if the file is launched, otherwise <code>false</code>
|
|
264 *
|
|
265 * @exception IllegalArgumentException <ul>
|
|
266 * <li>ERROR_NULL_ARGUMENT when fileName is null</li>
|
|
267 * </ul>
|
|
268 */
|
|
269 public static bool launch (char[] fileName) {
|
|
270 if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
|
|
271
|
|
272 /* Use the character encoding for the default locale */
|
|
273 auto hHeap = OS.GetProcessHeap ();
|
|
274 TCHAR[] buffer = StrToTCHARs (0, fileName, true);
|
|
275 int byteCount = buffer.length * TCHAR.sizeof;
|
|
276 auto lpFile = cast(wchar*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
|
|
277 OS.MoveMemory (lpFile, buffer.ptr, byteCount);
|
|
278 SHELLEXECUTEINFO info;
|
|
279 info.cbSize = SHELLEXECUTEINFO.sizeof;
|
|
280 info.lpFile = lpFile;
|
|
281 info.nShow = OS.SW_SHOW;
|
|
282 bool result = cast(bool) OS.ShellExecuteEx (&info);
|
|
283 if (lpFile !is null) OS.HeapFree (hHeap, 0, lpFile);
|
|
284 return result;
|
|
285 }
|
|
286
|
|
287 /**
|
|
288 * Executes the program with the file as the single argument
|
|
289 * in the operating system. It is the responsibility of the
|
|
290 * programmer to ensure that the file contains valid data for
|
|
291 * this program.
|
|
292 *
|
|
293 * @param fileName the file or program name
|
|
294 * @return <code>true</code> if the file is launched, otherwise <code>false</code>
|
|
295 *
|
|
296 * @exception IllegalArgumentException <ul>
|
|
297 * <li>ERROR_NULL_ARGUMENT when fileName is null</li>
|
|
298 * </ul>
|
|
299 */
|
|
300 public bool execute (char[] fileName) {
|
|
301 if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
|
|
302 int index = 0;
|
|
303 bool append = true;
|
|
304 char[] prefix = command, suffix = ""; //$NON-NLS-1$
|
|
305 while (index < ARGUMENTS.length) {
|
|
306 int i = command.indexOf (ARGUMENTS [index]);
|
|
307 if (i !is -1) {
|
|
308 append = false;
|
|
309 prefix = command.substring (0, i);
|
|
310 suffix = command.substring (i + ARGUMENTS [index].length , command.length );
|
|
311 break;
|
|
312 }
|
|
313 index++;
|
|
314 }
|
|
315 if (append) fileName = " \"" ~ fileName ~ "\"";
|
|
316 char[] commandLine = prefix ~ fileName ~ suffix;
|
|
317 auto hHeap = OS.GetProcessHeap ();
|
|
318 /* Use the character encoding for the default locale */
|
|
319 TCHAR[] buffer = StrToTCHARs (0, commandLine, true);
|
|
320 int byteCount = buffer.length * TCHAR.sizeof;
|
|
321 auto lpCommandLine = cast(TCHAR*)OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
|
|
322 OS.MoveMemory (lpCommandLine, buffer.ptr, byteCount);
|
|
323 STARTUPINFO lpStartupInfo;
|
|
324 lpStartupInfo.cb = STARTUPINFO.sizeof;
|
|
325 PROCESS_INFORMATION lpProcessInformation;
|
|
326 bool success = cast(bool) OS.CreateProcess (null, lpCommandLine, null, null, false, 0, null, null, &lpStartupInfo, &lpProcessInformation);
|
|
327 if (lpCommandLine !is null) OS.HeapFree (hHeap, 0, lpCommandLine);
|
|
328 if (lpProcessInformation.hProcess !is null) OS.CloseHandle (lpProcessInformation.hProcess);
|
|
329 if (lpProcessInformation.hThread !is null) OS.CloseHandle (lpProcessInformation.hThread);
|
|
330 return success;
|
|
331 }
|
|
332
|
|
333 /**
|
|
334 * Returns the receiver's image data. This is the icon
|
|
335 * that is associated with the receiver in the operating
|
|
336 * system.
|
|
337 *
|
|
338 * @return the image data for the program, may be null
|
|
339 */
|
|
340 public ImageData getImageData () {
|
|
341 if (extension !is null) {
|
|
342 SHFILEINFOW shfi;
|
|
343 int flags = OS.SHGFI_ICON | OS.SHGFI_SMALLICON | OS.SHGFI_USEFILEATTRIBUTES;
|
|
344 TCHAR[] pszPath = StrToTCHARs (0, extension, true);
|
|
345 OS.SHGetFileInfo (pszPath.ptr, OS.FILE_ATTRIBUTE_NORMAL, &shfi, SHFILEINFO.sizeof, flags);
|
|
346 if (shfi.hIcon !is null) {
|
|
347 Image image = Image.win32_new (null, DWT.ICON, shfi.hIcon);
|
|
348 ImageData imageData = image.getImageData ();
|
|
349 image.dispose ();
|
|
350 return imageData;
|
|
351 }
|
|
352 }
|
|
353 int nIconIndex = 0;
|
|
354 char[] fileName = iconName;
|
|
355 int index = iconName.indexOf (',');
|
|
356 if (index !is -1) {
|
|
357 fileName = iconName.substring (0, index);
|
|
358 char[] iconIndex = iconName.substring (index + 1, iconName.length ).trim ();
|
|
359 try {
|
|
360 nIconIndex = Integer.parseInt (iconIndex);
|
|
361 } catch (NumberFormatException e) {}
|
|
362 }
|
|
363 /* Use the character encoding for the default locale */
|
|
364 TCHAR[] lpszFile = StrToTCHARs (0, fileName, true);
|
|
365 HICON [1] phiconSmall, phiconLarge;
|
|
366 OS.ExtractIconEx (lpszFile.ptr, nIconIndex, phiconLarge.ptr, phiconSmall.ptr, 1);
|
|
367 if (phiconSmall [0] is null) return null;
|
|
368 Image image = Image.win32_new (null, DWT.ICON, phiconSmall [0]);
|
|
369 ImageData imageData = image.getImageData ();
|
|
370 image.dispose ();
|
|
371 return imageData;
|
|
372 }
|
|
373
|
|
374 /**
|
|
375 * Returns the receiver's name. This is as short and
|
|
376 * descriptive a name as possible for the program. If
|
|
377 * the program has no descriptive name, this string may
|
|
378 * be the executable name, path or empty.
|
|
379 *
|
|
380 * @return the name of the program
|
|
381 */
|
|
382 public char[] getName () {
|
|
383 return name;
|
|
384 }
|
|
385
|
|
386 /**
|
|
387 * Compares the argument to the receiver, and returns true
|
|
388 * if they represent the <em>same</em> object using a class
|
|
389 * specific comparison.
|
|
390 *
|
|
391 * @param other the object to compare with this object
|
|
392 * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
|
|
393 *
|
|
394 * @see #hashCode()
|
|
395 */
|
|
396 public override int opEquals(Object other) {
|
|
397 if (this is other) return true;
|
|
398 if ( auto program = cast(Program)other ) {
|
|
399 return name.equals(program.name) && command.equals(program.command)
|
|
400 && iconName.equals(program.iconName);
|
|
401 }
|
|
402 return false;
|
|
403 }
|
|
404
|
|
405 /**
|
|
406 * Returns an integer hash code for the receiver. Any two
|
|
407 * objects that return <code>true</code> when passed to
|
|
408 * <code>equals</code> must return the same value for this
|
|
409 * method.
|
|
410 *
|
|
411 * @return the receiver's hash
|
|
412 *
|
|
413 * @see #equals(Object)
|
|
414 */
|
|
415 public override hash_t toHash() {
|
|
416 return .toHash(name) ^ .toHash(command) ^ .toHash(iconName);
|
|
417 }
|
|
418
|
|
419 /**
|
|
420 * Returns a string containing a concise, human-readable
|
|
421 * description of the receiver.
|
|
422 *
|
|
423 * @return a string representation of the program
|
|
424 */
|
|
425 public char[] toString () {
|
|
426 return "Program {" ~ name ~ "}"; //$NON-NLS-1$ //$NON-NLS-2$
|
|
427 }
|
|
428
|
|
429 }
|