1 /* Copyright (c) 2013 Tobias Wolf, All Rights Reserved 2 * 3 * The contents of this file is dual-licensed under 2 4 * alternative Open Source/Free licenses: LGPL 2.1 or later and 5 * Apache License 2.0. (starting with JNA version 4.0.0). 6 * 7 * You can freely decide which license you want to apply to 8 * the project. 9 * 10 * You may obtain a copy of the LGPL License at: 11 * 12 * http://www.gnu.org/licenses/licenses.html 13 * 14 * A copy is also included in the downloadable source code package 15 * containing JNA, in file "LGPL2.1". 16 * 17 * You may obtain a copy of the Apache License at: 18 * 19 * http://www.apache.org/licenses/ 20 * 21 * A copy is also included in the downloadable source code package 22 * containing JNA, in file "AL2.0". 23 */ 24 package com.sun.jna.platform.win32.COM; 25 26 import com.sun.jna.LastErrorException; 27 import java.util.ArrayList; 28 29 import com.sun.jna.Native; 30 import com.sun.jna.Pointer; 31 import com.sun.jna.platform.win32.Advapi32; 32 import com.sun.jna.platform.win32.Advapi32Util; 33 import com.sun.jna.platform.win32.Advapi32Util.EnumKey; 34 import com.sun.jna.platform.win32.Advapi32Util.InfoKey; 35 import com.sun.jna.platform.win32.Kernel32Util; 36 import com.sun.jna.platform.win32.OaIdl.EXCEPINFO; 37 import com.sun.jna.platform.win32.Ole32; 38 import com.sun.jna.platform.win32.OleAuto; 39 import com.sun.jna.platform.win32.W32Errors; 40 import com.sun.jna.platform.win32.WinNT; 41 import com.sun.jna.platform.win32.WinNT.HRESULT; 42 import com.sun.jna.platform.win32.WinReg; 43 import com.sun.jna.platform.win32.WinReg.HKEYByReference; 44 import com.sun.jna.ptr.IntByReference; 45 46 /** 47 * The Class COMUtils. 48 * 49 * @author wolf.tobias@gmx.net The Class COMUtils. 50 */ 51 public abstract class COMUtils { 52 53 /** The Constant CO_E_NOTINITIALIZED. */ 54 public static final int S_OK = 0; 55 public static final int S_FALSE = 1; 56 public static final int E_UNEXPECTED=0x8000FFFF; 57 58 /** 59 * Succeeded. 60 * 61 * @param hr 62 * the hr 63 * @return true, if successful 64 */ SUCCEEDED(HRESULT hr)65 public static boolean SUCCEEDED(HRESULT hr) { 66 return SUCCEEDED(hr.intValue()); 67 } 68 69 /** 70 * Succeeded. 71 * 72 * @param hr 73 * the hr 74 * @return true, if successful 75 */ SUCCEEDED(int hr)76 public static boolean SUCCEEDED(int hr) { 77 return hr >= 0; 78 } 79 80 /** 81 * Failed. 82 * 83 * @param hr 84 * the hr 85 * @return true, if successful 86 */ FAILED(HRESULT hr)87 public static boolean FAILED(HRESULT hr) { 88 return FAILED(hr.intValue()); 89 } 90 91 /** 92 * Failed. 93 * 94 * @param hr 95 * the hr 96 * @return true, if successful 97 */ FAILED(int hr)98 public static boolean FAILED(int hr) { 99 return hr < 0; 100 } 101 102 /** 103 * Throw new exception. 104 * 105 * @param hr 106 * the hr 107 */ checkRC(HRESULT hr)108 public static void checkRC(HRESULT hr) { 109 if (FAILED(hr)) { 110 String formatMessage; 111 try { 112 formatMessage = Kernel32Util.formatMessage(hr) + "(HRESULT: " + Integer.toHexString(hr.intValue()) + ")"; 113 } catch (LastErrorException ex) { 114 // throws if HRESULT can't be resolved 115 formatMessage = "(HRESULT: " + Integer.toHexString(hr.intValue()) + ")"; 116 } 117 throw new COMException(formatMessage, hr); 118 } 119 } 120 121 /** 122 * Check status of HRESULT if it indicates a failed call a COMInvokeException 123 * is reaised. 124 * 125 * <p>The string members of the pExcepInfo are freed in this call and can't 126 * be used afterwards. The structure is not freeed, as it is expected, that 127 * is allocated via the Memory object of JNA.</p> 128 * 129 * @param hr 130 * the hr 131 * @param pExcepInfo 132 * the excep info, it is expected 133 * @param puArgErr 134 * the pu arg err 135 */ checkRC(HRESULT hr, EXCEPINFO pExcepInfo, IntByReference puArgErr)136 public static void checkRC(HRESULT hr, EXCEPINFO pExcepInfo, 137 IntByReference puArgErr) { 138 139 COMException resultException = null; 140 141 if (FAILED(hr)) { 142 StringBuilder formatMessage = new StringBuilder(); 143 144 Integer errorArg = null; 145 Integer wCode = null; 146 Integer scode = null; 147 String description = null; 148 String helpFile = null; 149 Integer helpCtx = null; 150 String source = null; 151 152 if(puArgErr != null) { 153 errorArg = puArgErr.getValue(); 154 } 155 156 try { 157 formatMessage.append(Kernel32Util.formatMessage(hr)); 158 } catch (LastErrorException ex) { 159 // throws if HRESULT can't be resolved 160 } 161 162 formatMessage.append("(HRESULT: "); 163 formatMessage.append(Integer.toHexString(hr.intValue())); 164 formatMessage.append(")"); 165 166 if(pExcepInfo != null) { 167 wCode = pExcepInfo.wCode.intValue(); 168 scode = pExcepInfo.scode.intValue(); 169 helpCtx = pExcepInfo.dwHelpContext.intValue(); 170 171 if(pExcepInfo.bstrSource != null) { 172 source = pExcepInfo.bstrSource.getValue(); 173 formatMessage.append("\nSource: "); 174 formatMessage.append(source); 175 } 176 if(pExcepInfo.bstrDescription != null) { 177 description = pExcepInfo.bstrDescription.getValue(); 178 formatMessage.append("\nDescription: "); 179 formatMessage.append(description); 180 } 181 if(pExcepInfo.bstrHelpFile != null) { 182 helpFile = pExcepInfo.bstrHelpFile.getValue(); 183 } 184 } 185 186 throw new COMInvokeException( 187 formatMessage.toString(), 188 hr, 189 errorArg, 190 description, 191 helpCtx, 192 helpFile, 193 scode, 194 source, 195 wCode 196 ); 197 } 198 199 if(pExcepInfo != null) { 200 if(pExcepInfo.bstrSource != null) { 201 OleAuto.INSTANCE.SysFreeString(pExcepInfo.bstrSource); 202 } 203 if(pExcepInfo.bstrDescription != null) { 204 OleAuto.INSTANCE.SysFreeString(pExcepInfo.bstrDescription); 205 } 206 if(pExcepInfo.bstrHelpFile != null) { 207 OleAuto.INSTANCE.SysFreeString(pExcepInfo.bstrHelpFile); 208 } 209 } 210 211 if(resultException != null) { 212 throw resultException; 213 } 214 } 215 216 /** 217 * Gets the all com info on system. 218 * 219 * @return the all com info on system 220 */ getAllCOMInfoOnSystem()221 public static ArrayList<COMInfo> getAllCOMInfoOnSystem() { 222 HKEYByReference phkResult = new HKEYByReference(); 223 HKEYByReference phkResult2 = new HKEYByReference(); 224 String subKey; 225 ArrayList<COMInfo> comInfos = new ArrayList<COMUtils.COMInfo>(); 226 227 try { 228 // open root key 229 phkResult = Advapi32Util.registryGetKey(WinReg.HKEY_CLASSES_ROOT, 230 "CLSID", WinNT.KEY_READ); 231 // open subkey 232 InfoKey infoKey = Advapi32Util.registryQueryInfoKey( 233 phkResult.getValue(), WinNT.KEY_READ); 234 235 for (int i = 0; i < infoKey.lpcSubKeys.getValue(); i++) { 236 EnumKey enumKey = Advapi32Util.registryRegEnumKey( 237 phkResult.getValue(), i); 238 subKey = Native.toString(enumKey.lpName); 239 240 COMInfo comInfo = new COMInfo(subKey); 241 242 phkResult2 = Advapi32Util.registryGetKey(phkResult.getValue(), 243 subKey, WinNT.KEY_READ); 244 InfoKey infoKey2 = Advapi32Util.registryQueryInfoKey( 245 phkResult2.getValue(), WinNT.KEY_READ); 246 247 for (int y = 0; y < infoKey2.lpcSubKeys.getValue(); y++) { 248 EnumKey enumKey2 = Advapi32Util.registryRegEnumKey( 249 phkResult2.getValue(), y); 250 String subKey2 = Native.toString(enumKey2.lpName); 251 252 if (subKey2.equals("InprocHandler32")) { 253 comInfo.inprocHandler32 = (String) Advapi32Util 254 .registryGetValue(phkResult2.getValue(), 255 subKey2, null); 256 } else if (subKey2.equals("InprocServer32")) { 257 comInfo.inprocServer32 = (String) Advapi32Util 258 .registryGetValue(phkResult2.getValue(), 259 subKey2, null); 260 } else if (subKey2.equals("LocalServer32")) { 261 comInfo.localServer32 = (String) Advapi32Util 262 .registryGetValue(phkResult2.getValue(), 263 subKey2, null); 264 } else if (subKey2.equals("ProgID")) { 265 comInfo.progID = (String) Advapi32Util 266 .registryGetValue(phkResult2.getValue(), 267 subKey2, null); 268 } else if (subKey2.equals("TypeLib")) { 269 comInfo.typeLib = (String) Advapi32Util 270 .registryGetValue(phkResult2.getValue(), 271 subKey2, null); 272 } 273 } 274 275 Advapi32.INSTANCE.RegCloseKey(phkResult2.getValue()); 276 comInfos.add(comInfo); 277 } 278 } finally { 279 Advapi32.INSTANCE.RegCloseKey(phkResult.getValue()); 280 Advapi32.INSTANCE.RegCloseKey(phkResult2.getValue()); 281 } 282 283 return comInfos; 284 } 285 286 /** 287 * Check if COM was initialized correctly. The initialization status is not changed! 288 * 289 * <p>This is a debug function, not for normal usage!</p> 290 * 291 * @return whether COM has been initialized 292 */ comIsInitialized()293 public static boolean comIsInitialized() { 294 WinNT.HRESULT hr = Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED); 295 if (hr.equals(W32Errors.S_OK)) { 296 // User failed - uninitialize again and return false 297 Ole32.INSTANCE.CoUninitialize(); 298 return false; 299 } else if (hr.equals(W32Errors.S_FALSE)) { 300 // OK Variant 1 - User initialized COM with same threading module as 301 // in this check. According to MSDN CoUninitialize needs to be called 302 // in this case. 303 Ole32.INSTANCE.CoUninitialize(); 304 return true; 305 } else if (hr.intValue() == W32Errors.RPC_E_CHANGED_MODE) { 306 return true; 307 } 308 // If another result than the checked ones above happens handling is 309 // delegated to the "normal" COM exception handling and a COMException 310 // will be raised. 311 COMUtils.checkRC(hr); 312 // The return will not be met, as COMUtils#checkRC will raise an exception 313 return false; 314 } 315 316 /** 317 * The Class COMInfo. 318 * 319 * @author wolf.tobias@gmx.net The Class COMInfo. 320 */ 321 public static class COMInfo { 322 323 /** The clsid. */ 324 public String clsid; 325 326 /** The inproc handler32. */ 327 public String inprocHandler32; 328 329 /** The inproc server32. */ 330 public String inprocServer32; 331 332 /** The local server32. */ 333 public String localServer32; 334 335 /** The prog id. */ 336 public String progID; 337 338 /** The type lib. */ 339 public String typeLib; 340 341 /** 342 * Instantiates a new cOM info. 343 */ COMInfo()344 public COMInfo() { 345 } 346 347 /** 348 * Instantiates a new cOM info. 349 * 350 * @param clsid 351 * the clsid 352 */ COMInfo(String clsid)353 public COMInfo(String clsid) { 354 this.clsid = clsid; 355 } 356 } 357 } 358