/** * Copyright (C) 2006 Aelitis, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 63.529,40 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package org.gudy.azureus2.ui.swt.win32; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Shell; import org.gudy.azureus2.core3.util.AEThread2; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.platform.win32.access.AEWin32Access; import org.gudy.azureus2.platform.win32.access.AEWin32Manager; import org.gudy.azureus2.platform.win32.access.impl.AEWin32AccessImpl; import org.gudy.azureus2.platform.win32.access.impl.AEWin32AccessInterface; import com.aelitis.azureus.core.drivedetector.*; /** * @author TuxPaper * @created Nov 29, 2006 * * Note: You can safely exclude this class from the build path. * All calls to this class use (or at least should use) reflection */ public class Win32UIEnhancer { public static final boolean DEBUG = false; public static final int SHGFI_ICON = 0x000000100; public static final int SHGFI_SMALLICON= 0x1; public static final int SHGFI_USEFILEATTRIBUTES = 0x000000010; public static final int SHGFI_LARGEICON = 0x2; public static final int WM_DEVICECHANGE = 0x219; public static final int DBT_DEVICEARRIVAL = 0x8000; public static final int DBT_DEVICEREMOVECOMPLETE = 0x8004; public static final int DBT_DEVTYP_VOLUME = 0x2; public static final int FILE_ATTRIBUTE_NORMAL = 0x00000080; private static int messageProcInt; private static long messageProcLong; private static Object /* Callback */messageCallback; private static DriveDetectedInfo loc; private static Class<?> claOS; private static boolean useLong; private static Class<?> claCallback; private static Constructor<?> constCallBack; private static Method mCallback_getAddress; private static Method mSetWindowLongPtr; private static int OS_GWLP_WNDPROC; private static Method mOS_memmove_byte; private static Method mOS_memmove_int; private static boolean isUnicode; private static Class<?> claSHFILEINFO; private static Class<?> claSHFILEINFOA; private static Class<?> claSHFILEINFOW; private static Class<?> claTCHAR; private static Method mSHGetFileInfo; private static Method mImage_win32_new; private static Constructor<?> constTCHAR3; private static int SHFILEINFO_sizeof; static { try { claOS = Class.forName("org.eclipse.swt.internal.win32.OS"); isUnicode = claOS.getDeclaredField("IsUnicode").getBoolean(null); claSHFILEINFO = Class.forName("org.eclipse.swt.internal.win32.SHFILEINFO"); SHFILEINFO_sizeof = claSHFILEINFO.getField("sizeof").getInt(null); claSHFILEINFOA = Class.forName("org.eclipse.swt.internal.win32.SHFILEINFOA"); claSHFILEINFOW = Class.forName("org.eclipse.swt.internal.win32.SHFILEINFOW"); claTCHAR = Class.forName("org.eclipse.swt.internal.win32.TCHAR"); // public TCHAR (int codePage, String string, boolean terminate) { constTCHAR3 = claTCHAR.getConstructor(new Class[] { int.class, String.class, boolean.class }); //public static long /*int*/ SHGetFileInfo (TCHAR pszPath, int dwFileAttributes, SHFILEINFO psfi, int cbFileInfo, int uFlags) mSHGetFileInfo = claOS.getMethod("SHGetFileInfo", new Class<?>[] { claTCHAR, int.class, claSHFILEINFO, int.class, int.class, }); // public Callback (Object object, String method, int argCount) claCallback = Class.forName("org.eclipse.swt.internal.Callback"); constCallBack = claCallback.getDeclaredConstructor(new Class[] { Object.class, String.class, int.class }); // public long /*int*/ getAddress () mCallback_getAddress = claCallback.getDeclaredMethod("getAddress", new Class[] {}); try { //int /*long*/ SetWindowLongPtr (int /*long*/ hWnd, int nIndex, int /*long*/ dwNewLong) { mSetWindowLongPtr = claOS.getMethod("SetWindowLongPtr", new Class[] { int.class, int.class, int.class }); useLong = false; mOS_memmove_byte = claOS.getMethod("memmove", new Class[] { byte[].class, int.class, int.class }); mOS_memmove_int = claOS.getMethod("memmove", new Class[] { int[].class, int.class, int.class }); mImage_win32_new = Image.class.getMethod("win32_new", new Class[] { Device.class, int.class, int.class }); } catch (Exception e) { //e.printStackTrace(); mSetWindowLongPtr = claOS.getMethod("SetWindowLongPtr", new Class[] { long.class, int.class, long.class }); useLong = true; mOS_memmove_byte = claOS.getMethod("memmove", new Class[] { byte[].class, long.class, long.class }); mOS_memmove_int = claOS.getMethod("memmove", new Class[] { int[].class, long.class, long.class }); mImage_win32_new = Image.class.getMethod("win32_new", new Class[] { Device.class, int.class, long.class }); } //OS.GWLP_WNDPROC OS_GWLP_WNDPROC = ((Integer) claOS.getField("GWLP_WNDPROC").get(null)).intValue(); } catch (Throwable e) { e.printStackTrace(); } } public static Image getFileIcon(File file, boolean big) { try { int flags = SHGFI_ICON; flags |= big ? SHGFI_LARGEICON : SHGFI_SMALLICON; if (!file.exists()) { flags |= SHGFI_USEFILEATTRIBUTES; } Object shfi; if (isUnicode) { shfi = claSHFILEINFOW.newInstance(); } else { shfi = claSHFILEINFOA.newInstance(); } Object pszPath = constTCHAR3.newInstance(0, file.getAbsolutePath(), true); mSHGetFileInfo.invoke(null, new Object[] { pszPath, file.isDirectory() ? 16 : FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO_sizeof, flags }); Field fldHIcon = claSHFILEINFO.getField("hIcon"); if (fldHIcon.getLong(shfi) == 0) { return null; } Image image = null; if (useLong) { image = (Image) mImage_win32_new.invoke(null, new Object[] { null, SWT.ICON, fldHIcon.getLong(shfi) }); } else { image = (Image) mImage_win32_new.invoke(null, new Object[] { null, SWT.ICON, fldHIcon.getInt(shfi) }); } return image; } catch (Exception e) { return null; } } public static void initMainShell(Shell shell) { //Canvas canvas = new Canvas(shell, SWT.NO_BACKGROUND | SWT.NO_TRIM); //canvas.setVisible(false); Shell subshell = new Shell(shell); try { messageCallback = constCallBack.newInstance(new Object[] { Win32UIEnhancer.class, "messageProc2", 4 }); Object oHandle = subshell.getClass().getField("handle").get(subshell); if (useLong) { Number n = (Number) mCallback_getAddress.invoke(messageCallback, new Object[] {}); messageProcLong = n.longValue(); if (messageProcLong != 0) { mSetWindowLongPtr.invoke(null, new Object[] { oHandle, OS_GWLP_WNDPROC, messageProcLong }); } } else { Number n = (Number) mCallback_getAddress.invoke(messageCallback, new Object[] {}); messageProcInt = n.intValue(); if (messageProcInt != 0) { mSetWindowLongPtr.invoke(null, new Object[] { oHandle, OS_GWLP_WNDPROC, messageProcInt }); } } } catch (Exception ex) { ex.printStackTrace(); } new AEThread2( "Async:USB" ) { public void run() { if ( Constants.isWindows7OrHigher ){ String version = AEWin32Manager.getAccessor( false ).getVersion(); if ( Constants.compareVersions( "1.21", version ) > 0 ){ // bug fixed in 1.21 whereby some win7 users got crashes return; } } Map<File, Map> drives = AEWin32Manager.getAccessor(false).getAllDrives(); if (drives != null) { for (File file : drives.keySet()) { Map driveInfo = drives.get(file); boolean isWritableUSB = AEWin32Manager.getAccessor(false).isUSBDrive(driveInfo); driveInfo.put("isWritableUSB", isWritableUSB); DriveDetectorFactory.getDeviceDetector().driveDetected(file, driveInfo); } } } }.start(); } static int /*long*/messageProc2(int /*long*/hwnd, int /*long*/msg, int /*long*/wParam, int /*long*/lParam) { return (int) messageProc2(hwnd, msg, (long) wParam, (long) lParam); } static long /*int*/messageProc2(long /*int*/hwnd, long /*int*/msg, long /*int*/wParam, long /*int*/lParam) { try { // I'll clean this up soon switch ((int) /*64*/msg) { case WM_DEVICECHANGE: if (wParam == DBT_DEVICEARRIVAL) { int[] st = new int[3]; if (useLong) { mOS_memmove_int.invoke(null, new Object[] { st, lParam, (long) 12 }); } else { mOS_memmove_int.invoke(null, new Object[] { st, (int) lParam, (int) 12 }); } if (DEBUG) { System.out.println("Arrival: " + st[0] + "/" + st[1] + "/" + st[2]); } if (st[1] == DBT_DEVTYP_VOLUME) { if (DEBUG) { System.out.println("NEW VOLUME!"); } byte b[] = new byte[st[0]]; if (useLong) { mOS_memmove_byte.invoke(null, new Object[] { b, lParam, (int) st[0] }); } else { mOS_memmove_byte.invoke(null, new Object[] { b, (int) lParam, (int) st[0] }); } long unitMask = (b[12] & 255) + ((b[13] & 255) << 8) + ((b[14] & 255) << 16) + ((b[15] & 3) << 24); char letter = '?'; for (int i = 0; i < 26; i++) { if (((1 << i) & unitMask) > 0) { letter = (char) ('A' + i); if (DEBUG) { System.out.println("Drive " + letter + ";mask=" + unitMask); } Map driveInfo = AEWin32AccessInterface.getDriveInfo(letter); boolean isWritableUSB = AEWin32Manager.getAccessor(false).isUSBDrive(driveInfo); driveInfo.put("isWritableUSB", isWritableUSB); DriveDetector driveDetector = DriveDetectorFactory.getDeviceDetector(); driveDetector.driveDetected(new File(letter + ":\\"), driveInfo); } } } } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { int[] st = new int[3]; if (useLong) { mOS_memmove_int.invoke(null, new Object[] { st, lParam, (long) 12 }); } else { mOS_memmove_int.invoke(null, new Object[] { st, (int) lParam, (int) 12 }); } if (DEBUG) { System.out.println("Remove: " + st[0] + "/" + st[1] + "/" + st[2]); } if (st[1] == DBT_DEVTYP_VOLUME) { if (DEBUG) { System.out.println("REMOVE VOLUME!"); } byte b[] = new byte[st[0]]; if (useLong) { mOS_memmove_byte.invoke(null, new Object[] { b, lParam, (int) st[0] }); } else { mOS_memmove_byte.invoke(null, new Object[] { b, (int) lParam, (int) st[0] }); } long unitMask = (b[12] & 255) + ((b[13] & 255) << 8) + ((b[14] & 255) << 16) + ((b[15] & 3) << 24); char letter = '?'; DriveDetector driveDetector = DriveDetectorFactory.getDeviceDetector(); for (int i = 0; i < 26; i++) { if (((1 << i) & unitMask) > 0) { letter = (char) ('A' + i); if (DEBUG) { System.out.println("Drive " + letter + ";mask=" + unitMask); } driveDetector.driveRemoved(new File(letter + ":\\")); } } Map<File, Map> drives = AEWin32Manager.getAccessor(false).getAllDrives(); if (drives != null) { DriveDetectedInfo[] existingDrives = driveDetector.getDetectedDriveInfo(); for (DriveDetectedInfo existingDrive : existingDrives) { File existingDriveFile = existingDrive.getLocation(); boolean found = drives.containsKey(existingDriveFile); if (!found) { if (DEBUG) { System.out.println("Fixup: Remove Drive " + existingDriveFile); } driveDetector.driveRemoved(existingDriveFile); } } } } } if (DEBUG) { System.out.println("DEVICE CHANGE" + wParam + "/" + lParam); } break; } } catch (Exception e) { e.printStackTrace(); } return 0;// OS.DefWindowProc (hwnd, (int)/*64*/msg, wParam, lParam); } }