001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.program;
011:
012: import org.eclipse.swt.internal.wpf.*;
013: import org.eclipse.swt.internal.win32.*;
014: import org.eclipse.swt.*;
015: import org.eclipse.swt.graphics.*;
016:
017: /**
018: * Instances of this class represent programs and
019: * their associated file extensions in the operating
020: * system.
021: */
022: public final class Program {
023: String name;
024: String command;
025: String iconName;
026: static final String[] ARGUMENTS = new String[] { "%1", "%l", "%L" };
027:
028: /**
029: * Prevents uninitialized instances from being created outside the package.
030: */
031: Program() {
032: }
033:
034: static int createDotNetString(String string) {
035: if (string == null)
036: return 0;
037: int length = string.length();
038: char[] buffer = new char[length + 1];
039: string.getChars(0, length, buffer, 0);
040: return OS.gcnew_String(buffer);
041: }
042:
043: static String createJavaString(int ptr) {
044: int charArray = OS.String_ToCharArray(ptr);
045: char[] chars = new char[OS.String_Length(ptr)];
046: OS.memcpy(chars, charArray, chars.length * 2);
047: OS.GCHandle_Free(charArray);
048: return new String(chars);
049: }
050:
051: /**
052: * Finds the program that is associated with an extension.
053: * The extension may or may not begin with a '.'. Note that
054: * a <code>Display</code> must already exist to guarantee that
055: * this method returns an appropriate result.
056: *
057: * @param extension the program extension
058: * @return the program or <code>null</code>
059: *
060: * @exception IllegalArgumentException <ul>
061: * <li>ERROR_NULL_ARGUMENT when extension is null</li>
062: * </ul>
063: */
064: public static Program findProgram(String extension) {
065: if (extension == null)
066: SWT.error(SWT.ERROR_NULL_ARGUMENT);
067: if (extension.length() == 0)
068: return null;
069: if (extension.charAt(0) != '.')
070: extension = "." + extension; //$NON-NLS-1$
071: if (extension.length() > 0xff)
072: return null;
073: int key = createDotNetString(extension);
074: int classesRoot = OS.Registry_ClassesRoot();
075: int registryKey = OS.RegistryKey_OpenSubKey(classesRoot, key);
076: OS.GCHandle_Free(key);
077: OS.GCHandle_Free(classesRoot);
078: if (registryKey == 0)
079: return null;
080: Program program = null;
081: int value = OS.RegistryKey_GetValue(registryKey, 0);
082: if (value != 0) {
083: program = getProgram(value);
084: OS.GCHandle_Free(value);
085: }
086: OS.GCHandle_Free(registryKey);
087: return program;
088: }
089:
090: /**
091: * Answer all program extensions in the operating system. Note
092: * that a <code>Display</code> must already exist to guarantee
093: * that this method returns an appropriate result.
094: *
095: * @return an array of extensions
096: */
097: public static String[] getExtensions() {
098: String[] extensions = new String[1024];
099: int classesRoot = OS.Registry_ClassesRoot();
100: int subKeys = OS.RegistryKey_GetSubKeyNames(classesRoot);
101: OS.GCHandle_Free(classesRoot);
102: int count = 0, length = OS.ICollection_Count(subKeys);
103: for (int i = 0; i < length; i++) {
104: int key = OS.IList_default(subKeys, i);
105: String extension = createJavaString(key);
106: OS.GCHandle_Free(key);
107: if (extension.length() > 0 && extension.charAt(0) == '.') {
108: if (count == extensions.length) {
109: String[] newExtensions = new String[extensions.length + 1024];
110: System.arraycopy(extensions, 0, newExtensions, 0,
111: extensions.length);
112: extensions = newExtensions;
113: }
114: extensions[count++] = extension;
115: }
116:
117: }
118: OS.GCHandle_Free(subKeys);
119: if (count != extensions.length) {
120: String[] newExtension = new String[count];
121: System.arraycopy(extensions, 0, newExtension, 0, count);
122: extensions = newExtension;
123: }
124: return extensions;
125: }
126:
127: static int getKeyValue(int key, boolean expand) {
128: int value = OS.RegistryKey_GetValue(key, 0);
129: if (value != 0) {
130: if (expand) {
131: int expandedValue = OS
132: .Environment_ExpandEnvironmentVariables(value);
133: OS.GCHandle_Free(value);
134: value = expandedValue;
135: }
136: }
137: return value;
138: }
139:
140: static Program getProgram(int key) {
141: int classesRoot = OS.Registry_ClassesRoot();
142: int registryKey = OS.RegistryKey_OpenSubKey(classesRoot, key);
143: OS.GCHandle_Free(classesRoot);
144: /* Name */
145: int name = getKeyValue(registryKey, false);
146: String programName = createJavaString(name == 0 ? key : name);
147: OS.GCHandle_Free(name);
148: /* Command */
149: int shellCommand = createDotNetString("shell");
150: int shellKey = OS.RegistryKey_OpenSubKey(registryKey,
151: shellCommand);
152: OS.GCHandle_Free(shellCommand);
153: int command = 0;
154: if (shellKey != 0) {
155: command = getKeyValue(shellKey, true);
156: if (command == 0) {
157: int openCommand = createDotNetString("open");
158: int openKey = OS.RegistryKey_OpenSubKey(shellKey,
159: openCommand);
160: if (openKey != 0) {
161: int commandCommand = createDotNetString("command");
162: int commandKey = OS.RegistryKey_OpenSubKey(openKey,
163: commandCommand);
164: if (commandKey != 0) {
165: command = getKeyValue(commandKey, true);
166: OS.GCHandle_Free(commandKey);
167: }
168: OS.GCHandle_Free(commandCommand);
169: OS.GCHandle_Free(openKey);
170: }
171: OS.GCHandle_Free(openCommand);
172: }
173: }
174: OS.GCHandle_Free(shellKey);
175: int iconName = 0;
176: if (command != 0) {
177: int defaultIconCommand = createDotNetString("DefaultIcon");
178: int defaultIconKey = OS.RegistryKey_OpenSubKey(registryKey,
179: defaultIconCommand);
180: if (defaultIconKey != 0) {
181: iconName = getKeyValue(defaultIconKey, true);
182: OS.GCHandle_Free(defaultIconKey);
183: }
184: OS.GCHandle_Free(defaultIconCommand);
185: }
186: OS.GCHandle_Free(registryKey);
187: if (command == 0)
188: return null;
189: Program program = new Program();
190: program.name = programName;
191: program.command = createJavaString(command);
192: OS.GCHandle_Free(command);
193: program.iconName = iconName != 0 ? createJavaString(iconName)
194: : "";
195: OS.GCHandle_Free(iconName);
196: return program;
197: }
198:
199: /**
200: * Answers all available programs in the operating system. Note
201: * that a <code>Display</code> must already exist to guarantee
202: * that this method returns an appropriate result.
203: *
204: * @return an array of programs
205: */
206: public static Program[] getPrograms() {
207: Program[] programs = new Program[1024];
208: int classesRoot = OS.Registry_ClassesRoot();
209: int subKeyNames = OS.RegistryKey_GetSubKeyNames(classesRoot);
210: OS.GCHandle_Free(classesRoot);
211: int count = 0;
212: int length = OS.ICollection_Count(subKeyNames);
213: for (int i = 0; i < length; i++) {
214: int keyName = OS.IList_default(subKeyNames, i);
215: Program program = getProgram(keyName);
216: OS.GCHandle_Free(keyName);
217: if (program != null) {
218: if (count == programs.length) {
219: Program[] newPrograms = new Program[programs.length + 1024];
220: System.arraycopy(programs, 0, newPrograms, 0,
221: programs.length);
222: programs = newPrograms;
223: }
224: programs[count++] = program;
225: }
226: }
227: OS.GCHandle_Free(subKeyNames);
228: if (count != programs.length) {
229: Program[] newPrograms = new Program[count];
230: System.arraycopy(programs, 0, newPrograms, 0, count);
231: programs = newPrograms;
232: }
233: return programs;
234: }
235:
236: /**
237: * Launches the executable associated with the file in
238: * the operating system. If the file is an executable,
239: * then the executable is launched. Note that a <code>Display</code>
240: * must already exist to guarantee that this method returns
241: * an appropriate result.
242: *
243: * @param fileName the file or program name
244: * @return <code>true</code> if the file is launched, otherwise <code>false</code>
245: *
246: * @exception IllegalArgumentException <ul>
247: * <li>ERROR_NULL_ARGUMENT when fileName is null</li>
248: * </ul>
249: */
250: public static boolean launch(String fileName) {
251: if (fileName == null)
252: SWT.error(SWT.ERROR_NULL_ARGUMENT);
253: int hHeap = Win32.GetProcessHeap();
254: int length = fileName.length();
255: char[] buffer = new char[length + 1];
256: fileName.getChars(0, length, buffer, 0);
257: int byteCount = buffer.length * 2;
258: int lpFile = Win32.HeapAlloc(hHeap, Win32.HEAP_ZERO_MEMORY,
259: byteCount);
260: Win32.MoveMemory(lpFile, buffer, byteCount);
261: SHELLEXECUTEINFOW info = new SHELLEXECUTEINFOW();
262: info.cbSize = SHELLEXECUTEINFOW.sizeof;
263: info.lpFile = lpFile;
264: info.nShow = Win32.SW_SHOW;
265: boolean result = Win32.ShellExecuteExW(info);
266: if (lpFile != 0)
267: Win32.HeapFree(hHeap, 0, lpFile);
268: return result;
269: }
270:
271: /**
272: * Executes the program with the file as the single argument
273: * in the operating system. It is the responsibility of the
274: * programmer to ensure that the file contains valid data for
275: * this program.
276: *
277: * @param fileName the file or program name
278: * @return <code>true</code> if the file is launched, otherwise <code>false</code>
279: *
280: * @exception IllegalArgumentException <ul>
281: * <li>ERROR_NULL_ARGUMENT when fileName is null</li>
282: * </ul>
283: */
284: public boolean execute(String fileName) {
285: if (fileName == null)
286: SWT.error(SWT.ERROR_NULL_ARGUMENT);
287: int index = 0;
288: boolean append = true;
289: String prefix = command, suffix = ""; //$NON-NLS-1$
290: while (index < ARGUMENTS.length) {
291: int i = command.indexOf(ARGUMENTS[index]);
292: if (i != -1) {
293: append = false;
294: prefix = command.substring(0, i);
295: suffix = command.substring(i
296: + ARGUMENTS[index].length(), command.length());
297: break;
298: }
299: index++;
300: }
301: if (append)
302: fileName = " \"" + fileName + "\"";
303: String commandLine = prefix + fileName + suffix;
304: int length = commandLine.length();
305: char[] buffer = new char[length + 1];
306: commandLine.getChars(0, length, buffer, 0);
307: STARTUPINFOW lpStartupInfo = new STARTUPINFOW();
308: lpStartupInfo.cb = STARTUPINFOW.sizeof;
309: PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION();
310: boolean success = Win32.CreateProcessW(0, buffer, 0, 0, false,
311: 0, 0, 0, lpStartupInfo, lpProcessInformation);
312: if (lpProcessInformation.hProcess != 0)
313: Win32.CloseHandle(lpProcessInformation.hProcess);
314: if (lpProcessInformation.hThread != 0)
315: Win32.CloseHandle(lpProcessInformation.hThread);
316: return success;
317: }
318:
319: /**
320: * Returns the receiver's image data. This is the icon
321: * that is associated with the receiver in the operating
322: * system.
323: *
324: * @return the image data for the program, may be null
325: */
326: public ImageData getImageData() {
327: int nIconIndex = 0;
328: String fileName = iconName;
329: int index = iconName.indexOf(',');
330: if (index != -1) {
331: fileName = iconName.substring(0, index);
332: String iconIndex = iconName.substring(index + 1,
333: iconName.length()).trim();
334: try {
335: nIconIndex = Integer.parseInt(iconIndex);
336: } catch (NumberFormatException e) {
337: }
338: }
339: int length = fileName.length();
340: char[] buffer = new char[length + 1];
341: fileName.getChars(0, length, buffer, 0);
342: int[] phiconSmall = new int[1], phiconLarge = null;
343: Win32.ExtractIconExW(buffer, nIconIndex, phiconLarge,
344: phiconSmall, 1);
345: if (phiconSmall[0] == 0)
346: return null;
347: int empty = OS.Int32Rect_Empty();
348: int source = OS.Imaging_CreateBitmapSourceFromHIcon(
349: phiconSmall[0], empty, 0);
350: Image image = Image.wpf_new(null, SWT.ICON, source);
351: OS.GCHandle_Free(empty);
352: ImageData imageData = image.getImageData();
353: image.dispose();
354: return imageData;
355: }
356:
357: /**
358: * Returns the receiver's name. This is as short and
359: * descriptive a name as possible for the program. If
360: * the program has no descriptive name, this string may
361: * be the executable name, path or empty.
362: *
363: * @return the name of the program
364: */
365: public String getName() {
366: return name;
367: }
368:
369: /**
370: * Compares the argument to the receiver, and returns true
371: * if they represent the <em>same</em> object using a class
372: * specific comparison.
373: *
374: * @param other the object to compare with this object
375: * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
376: *
377: * @see #hashCode()
378: */
379: public boolean equals(Object other) {
380: if (this == other)
381: return true;
382: if (other instanceof Program) {
383: final Program program = (Program) other;
384: return name.equals(program.name)
385: && command.equals(program.command)
386: && iconName.equals(program.iconName);
387: }
388: return false;
389: }
390:
391: /**
392: * Returns an integer hash code for the receiver. Any two
393: * objects that return <code>true</code> when passed to
394: * <code>equals</code> must return the same value for this
395: * method.
396: *
397: * @return the receiver's hash
398: *
399: * @see #equals(Object)
400: */
401: public int hashCode() {
402: return name.hashCode() ^ command.hashCode()
403: ^ iconName.hashCode();
404: }
405:
406: /**
407: * Returns a string containing a concise, human-readable
408: * description of the receiver.
409: *
410: * @return a string representation of the program
411: */
412: public String toString() {
413: return "Program {" + name + "}"; //$NON-NLS-1$ //$NON-NLS-2$
414: }
415:
416: }
|