root/dwt/program/Program.d

Revision 246:fd9c62a2998e, 16.3 kB (checked in by Frank Benoit <benoit@tionex.de>, 6 months ago)

Updater SWT 3.4M7 to 3.4

Line 
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 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 static import tango.text.convert.Utf;
22
23 /**
24  * Instances of this class represent programs and
25  * their associated file extensions in the operating
26  * system.
27  *
28  * @see <a href="http://www.eclipse.org/swt/snippets/#program">Program snippets</a>
29  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
30  */
31 public final class Program {
32     String name;
33     String command;
34     String iconName;
35     String extension;
36     static const String[] ARGUMENTS = ["%1"[], "%l", "%L"]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
37
38 /**
39  * Prevents uninitialized instances from being created outside the package.
40  */
41 this () {
42 }
43
44 static String assocQueryString (int assocStr, TCHAR[] key, bool expand) {
45     TCHAR[] pszOut = NewTCHARs(0, 1024);
46     uint[1] pcchOut;
47     pcchOut[0] = pszOut.length;
48     int flags = OS.ASSOCF_NOTRUNCATE | OS.ASSOCF_INIT_IGNOREUNKNOWN;
49     int result = OS.AssocQueryString (flags, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
50     if (result is OS.E_POINTER) {
51         pszOut = NewTCHARs(0, pcchOut [0]);
52         result = OS.AssocQueryString (flags, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
53     }
54     if (result is 0) {
55         if (!OS.IsWinCE && expand) {
56             int length_ = OS.ExpandEnvironmentStrings (pszOut.ptr, null, 0);
57             if (length_ !is 0) {
58                 TCHAR[] lpDst = NewTCHARs (0, length_);
59                 OS.ExpandEnvironmentStrings (pszOut.ptr, lpDst.ptr, length_);
60                 return tango.text.convert.Utf.toString( lpDst[ 0 .. Math.max (0, length_ - 1) ] );
61             } else {
62                 return "";
63             }
64         } else {
65             return tango.text.convert.Utf.toString( pszOut[ 0 .. Math.max (0, pcchOut [0] - 1)]);
66         }
67     }
68     return null;
69 }
70
71 /**
72  * Finds the program that is associated with an extension.
73  * The extension may or may not begin with a '.'.  Note that
74  * a <code>Display</code> must already exist to guarantee that
75  * this method returns an appropriate result.
76  *
77  * @param extension the program extension
78  * @return the program or <code>null</code>
79  *
80  */
81 public static Program findProgram (String extension) {
82     // DWT extension: allow null string
83     //if (extension is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
84     if (extension.length is 0) return null;
85     if (extension.charAt (0) !is '.') extension = "." ~ extension; //$NON-NLS-1$
86     /* Use the character encoding for the default locale */
87     TCHAR[] key = StrToTCHARs (0, extension, true);
88     Program program = null;
89     if (OS.IsWinCE) {
90         void*[1] phkResult;
91         if (OS.RegOpenKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
92             return null;
93         }
94         uint [1] lpcbData;
95         int result = OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr);
96         if (result is 0) {
97             TCHAR[] lpData = NewTCHARs (0, lpcbData [0] / TCHAR.sizeof);
98             result = OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr);
99             if (result is 0) program = getProgram ( TCHARzToStr( lpData.ptr ), extension);
100         }
101         OS.RegCloseKey (phkResult [0]);
102     } else {
103         String command = assocQueryString (OS.ASSOCSTR_COMMAND, key, true);
104         if (command !is null) {
105             String name = null;
106             if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYDOCNAME, key, false);
107             if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYAPPNAME, key, false);
108             if (name is null) name = "";
109             String iconName = assocQueryString (OS.ASSOCSTR_DEFAULTICON, key, true);
110             if (iconName is null) iconName = "";
111             program = new Program ();
112             program.name = name;
113             program.command = command;
114             program.iconName = iconName;
115             program.extension = extension;
116         }
117     }
118     return program;
119 }
120
121 /**
122  * Answer all program extensions in the operating system.  Note
123  * that a <code>Display</code> must already exist to guarantee
124  * that this method returns an appropriate result.
125  *
126  * @return an array of extensions
127  */
128 public static String [] getExtensions () {
129     String [] extensions = new String [1024];
130     /* Use the character encoding for the default locale */
131     TCHAR[] lpName = NewTCHARs (0, 1024);
132     uint [1] lpcName; lpcName[0] = lpName.length;
133     FILETIME ft;
134     int dwIndex = 0, count = 0;
135     while (OS.RegEnumKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
136         String extension = TCHARsToStr( lpName[0 .. lpcName[0] ]);
137         lpcName [0] = lpName.length;
138         if (extension.length > 0 && extension.charAt (0) is '.') {
139             if (count is extensions.length) {
140                 String[] newExtensions = new String[]( extensions.length + 1024 );
141                 System.arraycopy (extensions, 0, newExtensions, 0, extensions.length);
142                 extensions = newExtensions;
143             }
144             extensions [count++] = extension;
145         }
146         dwIndex++;
147     }
148     if (count !is extensions.length) {
149         String[] newExtension = new String[]( count );
150         System.arraycopy (extensions, 0, newExtension, 0, count);
151         extensions = newExtension;
152     }
153     return extensions;
154 }
155
156 static String getKeyValue (String string, bool expand) {
157     /* Use the character encoding for the default locale */
158     TCHAR[] key = StrToTCHARs (0, string, true);
159     void* [1] phkResult;
160     if (OS.RegOpenKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
161         return null;
162     }
163     String result = null;
164     uint [1] lpcbData;
165     if (OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr) is 0) {
166         result = "";
167         int length_ = lpcbData [0] / TCHAR.sizeof;
168         if (length_ !is 0) {
169             /* Use the character encoding for the default locale */
170             TCHAR[] lpData = NewTCHARs (0, length_);
171             if (OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr) is 0) {
172                 if (!OS.IsWinCE && expand) {
173                     length_ = OS.ExpandEnvironmentStrings (lpData.ptr, null, 0);
174                     if (length_ !is 0) {
175                         TCHAR[] lpDst = NewTCHARs (0, length_);
176                         OS.ExpandEnvironmentStrings (lpData.ptr, lpDst.ptr, length_);
177                         result = tango.text.convert.Utf.toString ( lpDst[0 .. Math.max (0, length_ - 1) ] );
178                     }
179                 } else {
180                     length_ = Math.max (0, lpData.length - 1);
181                     result = tango.text.convert.Utf.toString ( lpData[0 .. length_]);
182                 }
183             }
184         }
185     }
186     if (phkResult [0] !is null) OS.RegCloseKey (phkResult [0]);
187     return result;
188 }
189
190 static Program getProgram (String key, String extension) {
191
192     /* Name */
193     String name = getKeyValue (key, false);
194     if (name is null || name.length is 0) {
195         name = key;
196     }
197
198     /* Command */
199     String DEFAULT_COMMAND = "\\shell"; //$NON-NLS-1$
200     String defaultCommand = getKeyValue (key ~ DEFAULT_COMMAND, true);
201     if (defaultCommand is null || defaultCommand.length is 0) defaultCommand = "open"; //$NON-NLS-1$
202     String COMMAND = "\\shell\\" ~ defaultCommand ~ "\\command"; //$NON-NLS-1$
203     String command = getKeyValue (key ~ COMMAND, true);
204     if (command is null || command.length is 0) return null;
205
206     /* Icon */
207     String DEFAULT_ICON = "\\DefaultIcon"; //$NON-NLS-1$
208     String iconName = getKeyValue (key ~ DEFAULT_ICON, true);
209     if (iconName is null) iconName = ""; //$NON-NLS-1$
210
211     /* Program */
212     Program program = new Program ();
213     program.name = name;
214     program.command = command;
215     program.iconName = iconName;
216     program.extension = extension;
217     return program;
218 }
219
220 /**
221  * Answers all available programs in the operating system.  Note
222  * that a <code>Display</code> must already exist to guarantee
223  * that this method returns an appropriate result.
224  *
225  * @return an array of programs
226  */
227 public static Program [] getPrograms () {
228     Program [] programs = new Program [1024];
229     /* Use the character encoding for the default locale */
230     TCHAR[] lpName = NewTCHARs (0, 1024);
231     uint [1] lpcName; lpcName[0] = lpName.length;
232     FILETIME ft;
233     int dwIndex = 0, count = 0;
234     while (OS.RegEnumKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
235         String path = tango.text.convert.Utf.toString ( lpName[0 .. lpcName [0]]);
236         lpcName [0] = lpName.length ;
237         Program program = getProgram (path, null);
238         if (program !is null) {
239             if (count is programs.length) {
240                 Program [] newPrograms = new Program [programs.length + 1024];
241                 System.arraycopy (programs, 0, newPrograms, 0, programs.length);
242                 programs = newPrograms;
243             }
244             programs [count++] = program;
245         }
246         dwIndex++;
247     }
248     if (count !is programs.length) {
249         Program [] newPrograms = new Program [count];
250         System.arraycopy (programs, 0, newPrograms, 0, count);
251         programs = newPrograms;
252     }
253     return programs;
254 }
255
256 /**
257  * Launches the operating system executable associated with the file or
258  * URL (http:// or https://).  If the file is an executable then the
259  * executable is launched.  Note that a <code>Display</code> must already
260  * exist to guarantee that this method returns an appropriate result.
261  *
262  * @param fileName the file or program name or URL (http:// or https://)
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 (String 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 (String fileName) {
301     if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
302     int index = 0;
303     bool append = true;
304     String 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     String 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     String fileName = iconName;
355     int index = iconName.indexOf (',');
356     if (index !is -1) {
357         fileName = iconName.substring (0, index);
358         String iconIndex = iconName.substring (index + 1, iconName.length ).trim ();
359         try {
360             nIconIndex = Integer.parseInt (iconIndex);
361         } catch (NumberFormatException e) {}
362     }
363     int length = fileName.length;
364     if (length !is 0 && fileName.charAt (0) is '\"') {
365         if (fileName.charAt (length - 1) is '\"') {
366             fileName = fileName.substring (1, length - 1);
367         }
368     }
369     /* Use the character encoding for the default locale */
370     TCHAR[] lpszFile = StrToTCHARs (0, fileName, true);
371     HICON [1] phiconSmall, phiconLarge;
372     OS.ExtractIconEx (lpszFile.ptr, nIconIndex, phiconLarge.ptr, phiconSmall.ptr, 1);
373     if (phiconSmall [0] is null) return null;
374     Image image = Image.win32_new (null, DWT.ICON, phiconSmall [0]);
375     ImageData imageData = image.getImageData ();
376     image.dispose ();
377     return imageData;
378 }
379
380 /**
381  * Returns the receiver's name.  This is as short and
382  * descriptive a name as possible for the program.  If
383  * the program has no descriptive name, this string may
384  * be the executable name, path or empty.
385  *
386  * @return the name of the program
387  */
388 public String getName () {
389     return name;
390 }
391
392 /**
393  * Compares the argument to the receiver, and returns true
394  * if they represent the <em>same</em> object using a class
395  * specific comparison.
396  *
397  * @param other the object to compare with this object
398  * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
399  *
400  * @see #hashCode()
401  */
402 public override int opEquals(Object other) {
403     if (this is other) return true;
404     if ( auto program = cast(Program)other ) {
405         return name.equals(program.name) && command.equals(program.command)
406             && iconName.equals(program.iconName);
407     }
408     return false;
409 }
410
411 /**
412  * Returns an integer hash code for the receiver. Any two
413  * objects that return <code>true</code> when passed to
414  * <code>equals</code> must return the same value for this
415  * method.
416  *
417  * @return the receiver's hash
418  *
419  * @see #equals(Object)
420  */
421 public override hash_t toHash() {
422     return .toHash(name) ^ .toHash(command) ^ .toHash(iconName);
423 }
424
425 /**
426  * Returns a string containing a concise, human-readable
427  * description of the receiver.
428  *
429  * @return a string representation of the program
430  */
431 public String toString () {
432     return "Program {" ~ name ~ "}"; //$NON-NLS-1$ //$NON-NLS-2$
433 }
434
435 }
Note: See TracBrowser for help on using the browser.