changeset 191:528e7db39d9e

now really
author Frank Benoit <benoit@tionex.de>
date Mon, 17 Mar 2008 00:52:21 +0100
parents 72ef824d4983
children 135517d29564
files dwt/program/Program.d
diffstat 1 files changed, 433 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/program/Program.d	Mon Mar 17 00:52:21 2008 +0100
@@ -0,0 +1,433 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D Programming language:
+ *      Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwt.program.Program;
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.internal.win32.OS;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Integer;
+static import tango.text.convert.Utf;
+
+version(build){
+    pragma(link, "shlwapi");
+}
+
+/**
+ * Instances of this class represent programs and
+ * their associated file extensions in the operating
+ * system.
+ */
+public final class Program {
+    char[] name;
+    char[] command;
+    char[] iconName;
+    char[] extension;
+    static const char[][] ARGUMENTS = ["%1"[], "%l", "%L"]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+this () {
+}
+
+static char[] assocQueryString (int assocStr, TCHAR[] key, bool expand) {
+    TCHAR[] pszOut = NewTCHARs(0, 1024);
+    uint[1] pcchOut;
+    pcchOut[0] = pszOut.length;
+    int result = OS.AssocQueryString(OS.ASSOCF_NOTRUNCATE, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
+    if (result is OS.E_POINTER) {
+        pszOut = NewTCHARs(0, pcchOut [0]);
+        result = OS.AssocQueryString(OS.ASSOCF_NOTRUNCATE, assocStr, key.ptr, null, pszOut.ptr, pcchOut.ptr);
+    }
+    if (result is 0) {
+        if (!OS.IsWinCE && expand) {
+            int length_ = OS.ExpandEnvironmentStrings (pszOut.ptr, null, 0);
+            if (length_ !is 0) {
+                TCHAR[] lpDst = NewTCHARs (0, length_);
+                OS.ExpandEnvironmentStrings (pszOut.ptr, lpDst.ptr, length_);
+                return tango.text.convert.Utf.toString( lpDst[ 0 .. Math.max (0, length_ - 1) ] );
+            } else {
+                return "";
+            }
+        } else {
+            return tango.text.convert.Utf.toString( pszOut[ 0 .. Math.max (0, pcchOut [0] - 1)]);
+        }
+    }
+    return null;
+}
+
+/**
+ * Finds the program that is associated with an extension.
+ * The extension may or may not begin with a '.'.  Note that
+ * a <code>Display</code> must already exist to guarantee that
+ * this method returns an appropriate result.
+ *
+ * @param extension the program extension
+ * @return the program or <code>null</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ *      <li>ERROR_NULL_ARGUMENT when extension is null</li>
+ *  </ul>
+ */
+public static Program findProgram (char[] extension) {
+    if (extension is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    if (extension.length is 0) return null;
+    if (extension.charAt (0) !is '.') extension = "." ~ extension; //$NON-NLS-1$
+    /* Use the character encoding for the default locale */
+    TCHAR[] key = StrToTCHARs (0, extension, true);
+    Program program = null;
+    if (OS.IsWinCE) {
+        void*[1] phkResult;
+        if (OS.RegOpenKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
+            return null;
+        }
+        uint [1] lpcbData;
+        int result = OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr);
+        if (result is 0) {
+            TCHAR[] lpData = NewTCHARs (0, lpcbData [0] / TCHAR.sizeof);
+            result = OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr);
+            if (result is 0) program = getProgram ( TCHARzToStr( lpData.ptr ), extension);
+        }
+        OS.RegCloseKey (phkResult [0]);
+    } else {
+        char[] command = assocQueryString (OS.ASSOCSTR_COMMAND, key, true);
+        if (command !is null) {
+            char[] name = null;
+            if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYDOCNAME, key, false);
+            if (name is null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYAPPNAME, key, false);
+            if (name is null) name = "";
+            char[] iconName = assocQueryString (OS.ASSOCSTR_DEFAULTICON, key, true);
+            if (iconName is null) iconName = "";
+            program = new Program ();
+            program.name = name;
+            program.command = command;
+            program.iconName = iconName;
+            program.extension = extension;
+        }
+    }
+    return program;
+}
+
+/**
+ * Answer all program extensions in the operating system.  Note
+ * that a <code>Display</code> must already exist to guarantee
+ * that this method returns an appropriate result.
+ *
+ * @return an array of extensions
+ */
+public static char[] [] getExtensions () {
+    char[] [] extensions = new char[] [1024];
+    /* Use the character encoding for the default locale */
+    TCHAR[] lpName = NewTCHARs (0, 1024);
+    uint [1] lpcName; lpcName[0] = lpName.length;
+    FILETIME ft;
+    int dwIndex = 0, count = 0;
+    while (OS.RegEnumKeyEx ( cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
+        char[] extension = TCHARsToStr( lpName[0 .. lpcName[0] ]);
+        lpcName [0] = lpName.length;
+        if (extension.length > 0 && extension.charAt (0) is '.') {
+            if (count is extensions.length) {
+                char[][] newExtensions = new char[][]( extensions.length + 1024 );
+                System.arraycopy (extensions, 0, newExtensions, 0, extensions.length);
+                extensions = newExtensions;
+            }
+            extensions [count++] = extension;
+        }
+        dwIndex++;
+    }
+    if (count !is extensions.length) {
+        char[][] newExtension = new char[][]( count );
+        System.arraycopy (extensions, 0, newExtension, 0, count);
+        extensions = newExtension;
+    }
+    return extensions;
+}
+
+static char[] getKeyValue (char[] string, bool expand) {
+    /* Use the character encoding for the default locale */
+    TCHAR[] key = StrToTCHARs (0, string, true);
+    void* [1] phkResult;
+    if (OS.RegOpenKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, key.ptr, 0, OS.KEY_READ, phkResult.ptr) !is 0) {
+        return null;
+    }
+    char[] result = null;
+    uint [1] lpcbData;
+    if (OS.RegQueryValueEx (phkResult [0], null, null, null, null, lpcbData.ptr) is 0) {
+        result = "";
+        int length_ = lpcbData [0] / TCHAR.sizeof;
+        if (length_ !is 0) {
+            /* Use the character encoding for the default locale */
+            TCHAR[] lpData = NewTCHARs (0, length_);
+            if (OS.RegQueryValueEx (phkResult [0], null, null, null, cast(ubyte*)lpData.ptr, lpcbData.ptr) is 0) {
+                if (!OS.IsWinCE && expand) {
+                    length_ = OS.ExpandEnvironmentStrings (lpData.ptr, null, 0);
+                    if (length_ !is 0) {
+                        TCHAR[] lpDst = NewTCHARs (0, length_);
+                        OS.ExpandEnvironmentStrings (lpData.ptr, lpDst.ptr, length_);
+                        result = tango.text.convert.Utf.toString ( lpDst[0 .. Math.max (0, length_ - 1) ] );
+                    }
+                } else {
+                    length_ = Math.max (0, lpData.length - 1);
+                    result = tango.text.convert.Utf.toString ( lpData[0 .. length_]);
+                }
+            }
+        }
+    }
+    if (phkResult [0] !is null) OS.RegCloseKey (phkResult [0]);
+    return result;
+}
+
+static Program getProgram (char[] key, char[] extension) {
+
+    /* Name */
+    char[] name = getKeyValue (key, false);
+    if (name is null || name.length is 0) {
+        name = key;
+    }
+
+    /* Command */
+    char[] DEFAULT_COMMAND = "\\shell"; //$NON-NLS-1$
+    char[] defaultCommand = getKeyValue (key ~ DEFAULT_COMMAND, true);
+    if (defaultCommand is null || defaultCommand.length is 0) defaultCommand = "open"; //$NON-NLS-1$
+    char[] COMMAND = "\\shell\\" ~ defaultCommand ~ "\\command"; //$NON-NLS-1$
+    char[] command = getKeyValue (key ~ COMMAND, true);
+    if (command is null || command.length is 0) return null;
+
+    /* Icon */
+    char[] DEFAULT_ICON = "\\DefaultIcon"; //$NON-NLS-1$
+    char[] iconName = getKeyValue (key ~ DEFAULT_ICON, true);
+    if (iconName is null) iconName = ""; //$NON-NLS-1$
+
+    /* Program */
+    Program program = new Program ();
+    program.name = name;
+    program.command = command;
+    program.iconName = iconName;
+    program.extension = extension;
+    return program;
+}
+
+/**
+ * Answers all available programs in the operating system.  Note
+ * that a <code>Display</code> must already exist to guarantee
+ * that this method returns an appropriate result.
+ *
+ * @return an array of programs
+ */
+public static Program [] getPrograms () {
+    Program [] programs = new Program [1024];
+    /* Use the character encoding for the default locale */
+    TCHAR[] lpName = NewTCHARs (0, 1024);
+    uint [1] lpcName; lpcName[0] = lpName.length;
+    FILETIME ft;
+    int dwIndex = 0, count = 0;
+    while (OS.RegEnumKeyEx (cast(void*)OS.HKEY_CLASSES_ROOT, dwIndex, lpName.ptr, lpcName.ptr, null, null, null, &ft) !is OS.ERROR_NO_MORE_ITEMS) {
+        char[] path = tango.text.convert.Utf.toString ( lpName[0 .. lpcName [0]]);
+        lpcName [0] = lpName.length ;
+        Program program = getProgram (path, null);
+        if (program !is null) {
+            if (count is programs.length) {
+                Program [] newPrograms = new Program [programs.length + 1024];
+                System.arraycopy (programs, 0, newPrograms, 0, programs.length);
+                programs = newPrograms;
+            }
+            programs [count++] = program;
+        }
+        dwIndex++;
+    }
+    if (count !is programs.length) {
+        Program [] newPrograms = new Program [count];
+        System.arraycopy (programs, 0, newPrograms, 0, count);
+        programs = newPrograms;
+    }
+    return programs;
+}
+
+/**
+ * Launches the executable associated with the file in
+ * the operating system.  If the file is an executable,
+ * then the executable is launched.  Note that a <code>Display</code>
+ * must already exist to guarantee that this method returns
+ * an appropriate result.
+ *
+ * @param fileName the file or program name
+ * @return <code>true</code> if the file is launched, otherwise <code>false</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT when fileName is null</li>
+ * </ul>
+ */
+public static bool launch (char[] fileName) {
+    if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+
+    /* Use the character encoding for the default locale */
+    auto hHeap = OS.GetProcessHeap ();
+    TCHAR[] buffer = StrToTCHARs (0, fileName, true);
+    int byteCount = buffer.length * TCHAR.sizeof;
+    auto lpFile = cast(wchar*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+    OS.MoveMemory (lpFile, buffer.ptr, byteCount);
+    SHELLEXECUTEINFO info;
+    info.cbSize = SHELLEXECUTEINFO.sizeof;
+    info.lpFile = lpFile;
+    info.nShow = OS.SW_SHOW;
+    bool result = cast(bool) OS.ShellExecuteEx (&info);
+    if (lpFile !is null) OS.HeapFree (hHeap, 0, lpFile);
+    return result;
+}
+
+/**
+ * Executes the program with the file as the single argument
+ * in the operating system.  It is the responsibility of the
+ * programmer to ensure that the file contains valid data for
+ * this program.
+ *
+ * @param fileName the file or program name
+ * @return <code>true</code> if the file is launched, otherwise <code>false</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT when fileName is null</li>
+ * </ul>
+ */
+public bool execute (char[] fileName) {
+    if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    int index = 0;
+    bool append = true;
+    char[] prefix = command, suffix = ""; //$NON-NLS-1$
+    while (index < ARGUMENTS.length) {
+        int i = command.indexOf (ARGUMENTS [index]);
+        if (i !is -1) {
+            append = false;
+            prefix = command.substring (0, i);
+            suffix = command.substring (i + ARGUMENTS [index].length , command.length );
+            break;
+        }
+        index++;
+    }
+    if (append) fileName = " \"" ~ fileName ~ "\"";
+    char[] commandLine = prefix ~ fileName ~ suffix;
+    auto hHeap = OS.GetProcessHeap ();
+    /* Use the character encoding for the default locale */
+    TCHAR[] buffer = StrToTCHARs (0, commandLine, true);
+    int byteCount = buffer.length  * TCHAR.sizeof;
+    auto lpCommandLine = cast(TCHAR*)OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+    OS.MoveMemory (lpCommandLine, buffer.ptr, byteCount);
+    STARTUPINFO lpStartupInfo;
+    lpStartupInfo.cb = STARTUPINFO.sizeof;
+    PROCESS_INFORMATION lpProcessInformation;
+    bool success = cast(bool) OS.CreateProcess (null, lpCommandLine, null, null, false, 0, null, null, &lpStartupInfo, &lpProcessInformation);
+    if (lpCommandLine !is null) OS.HeapFree (hHeap, 0, lpCommandLine);
+    if (lpProcessInformation.hProcess !is null) OS.CloseHandle (lpProcessInformation.hProcess);
+    if (lpProcessInformation.hThread !is null) OS.CloseHandle (lpProcessInformation.hThread);
+    return success;
+}
+
+/**
+ * Returns the receiver's image data.  This is the icon
+ * that is associated with the receiver in the operating
+ * system.
+ *
+ * @return the image data for the program, may be null
+ */
+public ImageData getImageData () {
+    if (extension !is null) {
+        SHFILEINFOW shfi;
+        int flags = OS.SHGFI_ICON | OS.SHGFI_SMALLICON | OS.SHGFI_USEFILEATTRIBUTES;
+        TCHAR[] pszPath = StrToTCHARs (0, extension, true);
+        OS.SHGetFileInfo (pszPath.ptr, OS.FILE_ATTRIBUTE_NORMAL, &shfi, SHFILEINFO.sizeof, flags);
+        if (shfi.hIcon !is null) {
+            Image image = Image.win32_new (null, DWT.ICON, shfi.hIcon);
+            ImageData imageData = image.getImageData ();
+            image.dispose ();
+            return imageData;
+        }
+    }
+    int nIconIndex = 0;
+    char[] fileName = iconName;
+    int index = iconName.indexOf (',');
+    if (index !is -1) {
+        fileName = iconName.substring (0, index);
+        char[] iconIndex = iconName.substring (index + 1, iconName.length ).trim ();
+        try {
+            nIconIndex = Integer.parseInt (iconIndex);
+        } catch (NumberFormatException e) {}
+    }
+    /* Use the character encoding for the default locale */
+    TCHAR[] lpszFile = StrToTCHARs (0, fileName, true);
+    HICON [1] phiconSmall, phiconLarge;
+    OS.ExtractIconEx (lpszFile.ptr, nIconIndex, phiconLarge.ptr, phiconSmall.ptr, 1);
+    if (phiconSmall [0] is null) return null;
+    Image image = Image.win32_new (null, DWT.ICON, phiconSmall [0]);
+    ImageData imageData = image.getImageData ();
+    image.dispose ();
+    return imageData;
+}
+
+/**
+ * Returns the receiver's name.  This is as short and
+ * descriptive a name as possible for the program.  If
+ * the program has no descriptive name, this string may
+ * be the executable name, path or empty.
+ *
+ * @return the name of the program
+ */
+public char[] getName () {
+    return name;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param other the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode()
+ */
+public override int opEquals(Object other) {
+    if (this is other) return true;
+    if ( auto program = cast(Program)other ) {
+        return name.equals(program.name) && command.equals(program.command)
+            && iconName.equals(program.iconName);
+    }
+    return false;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+public override hash_t toHash() {
+    return .toHash(name) ^ .toHash(command) ^ .toHash(iconName);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the program
+ */
+public char[] toString () {
+    return "Program {" ~ name ~ "}"; //$NON-NLS-1$ //$NON-NLS-2$
+}
+
+}