diff --git a/CHANGES.md b/CHANGES.md index e71c9445dd..7ed28ac20b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Release 4.5.0 (Next release) Features -------- * [#774](https://github.com/java-native-access/jna/pull/774): Addition win32 api : SendMessage, GetActiveWindow, COPYDATASTRUCT and a few constants + a demo application - [@cnico](https://github.com/cnico). +* [#783](https://github.com/java-native-access/jna/pull/783): Add Ole32 functions: `OleBuildVersion`, `OleInitialize`, `OleUninitialize`, `OleFlushClipboard`, `OleRun`, add VARIANT conversion functions to OleAuto, add default locale, LCID and LANG to WinNT - [@matthiasblaesing](https://github.com/matthiasblaesing). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Ole32.java b/contrib/platform/src/com/sun/jna/platform/win32/Ole32.java index 7ce2eb1b2f..bb3480a0b0 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Ole32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Ole32.java @@ -352,4 +352,117 @@ HRESULT CoCreateInstance(GUID rclsid, Pointer pUnkOuter, int dwClsContext, */ boolean CoIsHandlerConnected(Pointer pUnk); + + /** + * Initializes the COM library on the current apartment, identifies the + * concurrency model as single-thread apartment (STA), and enables + * additional functionality described in the Remarks section below. + * Applications must initialize the COM library before they can call COM + * library functions other than CoGetMalloc and memory allocation functions. + * @param pvReserved Reserved; must be null. + * @return {@link WinError#S_OK S_OK} if the COM library and additional functionality were + * initialized successfully on this apartment.
+ * {@link WinError#S_FALSE S_FALSE} if the COM library is already initialized on this apartment.
+ * {@link WinError#OLE_E_WRONGCOMPOBJ OLE_E_WRONGCOMPOBJ} if the versions of COMPOBJ.DLL and OLE2.DLL on + * your machine are incompatible with each other.
+ * {@link WinError#RPC_E_CHANGED_MODE RPC_E_CHANGED_MODE} if a previous call to CoInitializeEx specified + * the concurrency model for this apartment as + * multithread apartment (MTA). If running + * Windows 2000, this could also mean that a + * change from neutral threaded apartment to + * single threaded apartment occurred. + */ + HRESULT OleInitialize(Pointer pvReserved); + + /** + * Closes the COM library on the apartment, releases any class factories, + * other COM objects, or servers held by the apartment, disables RPC on the + * apartment, and frees any resources the apartment maintains. + * + * Remarks: + * Call OleUninitialize on application shutdown, as the last COM library + * call, if the apartment was initialized with a call to + * {@link #OleInitialize}. OleUninitialize calls the CoUninitialize function + * internally to shut down the OLE Component Object(COM) Library. + * + * If the COM library was initialized on the apartment with a call to + * CoInitialize or CoInitializeEx, it must be closed with a call to + * CoUninitialize. + * + * The {@link #OleInitialize} and OleUninitialize calls must be balanced — + * if there are multiple calls to the {@link #OleInitialize} function, there + * must be the same number of calls to OleUninitialize: Only the + * OleUninitialize call corresponding to the {@link #OleInitialize} call + * that actually initialized the library can close it. + */ + void OleUninitialize(); + + /** + * Carries out the clipboard shutdown sequence. It also releases the + * IDataObject pointer that was placed on the clipboard by the + * OleSetClipboard function. + * @return {@link WinError#S_OK S_OK} on success.
+ * {@link WinError#CLIPBRD_E_CANT_OPEN CLIPBRD_E_CANT_OPEN} The Windows OpenClipboard function used + * within OleFlushClipboard failed.
+ * {@link WinError#CLIPBRD_E_CANT_CLOSE CLIPBRD_E_CANT_CLOSE} The Windows CloseClipboard function used + * within OleFlushClipboard failed.
+ * Remarks
+ * OleFlushClipboard renders the data from a data object onto the clipboard + * and releases the IDataObject pointer to the data object. While the + * application that put the data object on the clipboard is running, the + * clipboard holds only a pointer to the data object, thus saving memory. + * If you are writing an application that acts as the source of a clipboard + * operation, you can call the OleFlushClipboard function when your + * application is closed, such as when the user exits from your application. + * Calling OleFlushClipboard enables pasting and paste-linking of OLE + * objects after application shutdown. + * Before calling OleFlushClipboard, you can easily determine if your data + * is still on the clipboard with a call to the OleIsCurrentClipboard + * function. + * + * OleFlushClipboard leaves all formats offered by the data transfer object, + * including the OLE 1 compatibility formats, on the clipboard so they are + * available after application shutdown. In addition to OLE 1 compatibility + * formats, these include all formats offered on a global handle medium (all + * except for TYMED_FILE) and formatted with a null target device. For + * example, if a data-source application offers a particular clipboard + * format (say cfFOO) on an IStorage object, and calls the OleFlushClipboard + * function, the storage object is copied into memory and the hglobal memory + * handle is put on the clipboard. + * + * To retrieve the information on the clipboard, you can call the + * OleGetClipboard function from another application, which creates a + * default data object, and the hglobal from the clipboard again becomes a + * storage object. Furthermore, the FORMATETC enumerator and the + * IDataObject::QueryGetData method would all correctly indicate that the + * original clipboard format (cfFOO) is again available on a TYMED_ISTORAGE. + * + * To empty the clipboard, call the OleSetClipboard function specifying a + * null value for its parameter. The application should call this when it + * closes if there is no need to leave data on the clipboard after shutdown, + * or if data will be placed on the clipboard using the standard Windows + * clipboard functions. + */ + HRESULT OleFlushClipboard(); + + /** + * Puts an OLE compound document object into the running state. + * @param pUnknown [in] Pointer to the {@link IUnknown IUnknown} interface + * on the object, with which it will query for a pointer to + * the IRunnableObject interface, and then call its Run method. + * @return This function returns on success. + * Other possible values include the following.
+ * {@link WinError#OLE_E_CLASSDIFF OLE_E_CLASSDIFF} The source of an + * OLE link has been converted to a different class.
+ * Remarks
+ * The OleRun function puts an object in the running state. The + * implementation of OleRun was changed in OLE 2.01 to coincide with the + * publication of the IRunnableObject interface. You can use OleRun and + * IRunnableObject::Run interchangeably. OleRun queries the object for a + * pointer to IRunnableObject. If successful, the function returns the + * results of calling the IRunnableObject::Run method.
+ * For more information on using this function, see IRunnableObject::Run. + */ + HRESULT OleRun(Pointer pUnknown); + } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java b/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java index 535955de6f..80a31b89d3 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java @@ -239,6 +239,164 @@ public interface OleAuto extends StdCallLibrary { * @return the hresult */ HRESULT VariantClear(VARIANT pvarg); + + public static final short VARIANT_NOVALUEPROP = 0x01; + /** For VT_BOOL to VT_BSTR conversions, convert to "True"/"False" instead of "-1"/"0" */ + public static final short VARIANT_ALPHABOOL = 0x02; + /** For conversions to/from VT_BSTR, passes LOCALE_NOUSEROVERRIDE to core coercion routines */ + public static final short VARIANT_NOUSEROVERRIDE = 0x04; + public static final short VARIANT_CALENDAR_HIJRI = 0x08; + /** For VT_BOOL to VT_BSTR and back, convert to local language rather than English */ + public static final short VARIANT_LOCALBOOL = 0x10; + /** SOUTHASIA calendar support */ + public static final short VARIANT_CALENDAR_THAI = 0x20; + /** SOUTHASIA calendar support */ + public static final short VARIANT_CALENDAR_GREGORIAN = 0x40; + /** NLS function call support */ + public static final short VARIANT_USE_NLS = 0x80; + + /** + * Converts a variant from one type to another. + * @param pvargDest [out] The destination variant. If this is the same as + * pvarSrc, the variant will be converted in place. + * @param pvarSrc [in] The variant to convert. + * @param wFlags Combination of the following flags + *
Value | Meaning | |
---|---|---|
{@link #VARIANT_NOVALUEPROP} | Prevents the function from attempting to coerce an object to a fundamental type by getting the Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications. | |
{@link #VARIANT_ALPHABOOL} | Converts a {@link Variant#VT_BOOL VT_BOOL} value to a string containing either "True" or "False". | |
{@link #VARIANT_NOUSEROVERRIDE} | For conversions to or from {@link Variant#VT_BSTR VT_BSTR}, passes LOCALE_NOUSEROVERRIDE to the core coercion routines. | |
{@link #VARIANT_LOCALBOOL} | For conversions from {@link Variant#VT_BOOL VT_BOOL} to {@link Variant#VT_BSTR VT_BSTR} and back, uses the language specified by the locale in use on the local computer. |
Return code | Description |
---|---|
{@link WinError#S_OK S_OK} | Success. |
{@link WinError#DISP_E_BADVARTYPE DISP_E_BADVARTYPE} | The variant type is not a valid type of variant. |
{@link WinError#DISP_E_OVERFLOW DISP_E_OVERFLOW} | The data pointed to by pvarSrc does not fit in the destination type. |
{@link WinError#DISP_E_TYPEMISMATCH DISP_E_TYPEMISMATCH} | The argument could not be coerced to the specified type. |
{@link WinError#E_INVALIDARG E_INVALIDARG} | One of the arguments is not valid. |
{@link WinError#E_OUTOFMEMORY E_OUTOFMEMORY} | Insufficient memory to complete the operation. |
puArgErr
parameter referenced value to 0 (indicating the
+ * argument in error) and return DISP_E_TYPEMISMATCH from Invoke.
+ *
+ * Arrays of one type cannot be converted to arrays of another type with
+ * this function.
+ *
+ * Note The type of a {@link Variant.VARIANT VARIANT} should not be
+ * changed in the {@link DISPPARAMS#rgvarg rgvarg} array in place.
+ */
+ HRESULT VariantChangeType(VARIANT pvargDest, VARIANT pvarSrc, short wFlags, VARTYPE vt);
+
+ /**
+ * Converts a variant from one type to another.
+ * @param pvargDest [out] The destination variant. If this is the same as
+ * pvarSrc, the variant will be converted in place.
+ * @param pvarSrc [in] The variant to convert.
+ * @param wFlags Combination of the following flags
+ * Value | Meaning | |
---|---|---|
{@link #VARIANT_NOVALUEPROP} | Prevents the function from attempting to coerce an object to a fundamental type by getting the Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications. | |
{@link #VARIANT_ALPHABOOL} | Converts a {@link Variant#VT_BOOL VT_BOOL} value to a string containing either "True" or "False". | |
{@link #VARIANT_NOUSEROVERRIDE} | For conversions to or from {@link Variant#VT_BSTR VT_BSTR}, passes LOCALE_NOUSEROVERRIDE to the core coercion routines. | |
{@link #VARIANT_LOCALBOOL} | For conversions from {@link Variant#VT_BOOL VT_BOOL} to {@link Variant#VT_BSTR VT_BSTR} and back, uses the language specified by the locale in use on the local computer. |
Return code | Description |
---|---|
{@link WinError#S_OK S_OK} | Success. |
{@link WinError#DISP_E_BADVARTYPE DISP_E_BADVARTYPE} | The variant type is not a valid type of variant. |
{@link WinError#DISP_E_OVERFLOW DISP_E_OVERFLOW} | The data pointed to by pvarSrc does not fit in the destination type. |
{@link WinError#DISP_E_TYPEMISMATCH DISP_E_TYPEMISMATCH} | The argument could not be coerced to the specified type. |
{@link WinError#E_INVALIDARG E_INVALIDARG} | One of the arguments is not valid. |
{@link WinError#E_OUTOFMEMORY E_OUTOFMEMORY} | Insufficient memory to complete the operation. |
puArgErr
parameter referenced value to 0 (indicating the
+ * argument in error) and return DISP_E_TYPEMISMATCH from Invoke.
+ *
+ * Arrays of one type cannot be converted to arrays of another type with
+ * this function.
+ *
+ * Note The type of a {@link Variant.VARIANT VARIANT} should not be
+ * changed in the {@link DISPPARAMS#rgvarg rgvarg} array in place.
+ */
+ HRESULT VariantChangeType(VARIANT.ByReference pvargDest, VARIANT.ByReference pvarSrc, short wFlags, VARTYPE vt);
+
/**
* Creates a new array descriptor, allocates and initializes the data for
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
index 26f432a30d..adc8111e27 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
@@ -3272,4 +3272,351 @@ protected ListA language ID is a 16 bit value which is the combination of a + * primary language ID and a secondary language ID. The bits are + * allocated as follows:
+ * + *+ * +-----------------------+-------------------------+ + * | Sublanguage ID | Primary Language ID | + * +-----------------------+-------------------------+ + * 15 10 9 0 bit + *+ * + *
WARNING: This pattern isn't always follows, Serbina, Bosnian & Croation for example.
+ * + *It is recommended that applications test for locale names or actual LCIDs.
+ * + *Note that the LANG, SUBLANG construction is not always consistent. + * The named locale APIs (eg GetLocaleInfoEx) are recommended.
+ * + *Language IDs do not exist for all locales
+ * + *A locale ID is a 32 bit value which is the combination of a + * language ID, a sort ID, and a reserved area. The bits are + * allocated as follows:
+ * + *+ * +-------------+---------+-------------------------+ + * | Reserved | Sort ID | Language ID | + * +-------------+---------+-------------------------+ + * 31 20 19 16 15 0 bit + *+ * + *
WARNING: This pattern isn't always followed (es-ES_tradnl vs es-ES for example)
+ * + *It is recommended that applications test for locale names or actual LCIDs.
+ */ + public static final class LocaleMacros { + private static final int _MAKELCID(int lgid, int srtid) { + return (srtid << 16) | lgid; + } + + /** + * construct the locale id from a language id and a sort id. + * + * @param lgid + * @param srtid + * @return + */ + public static final LCID MAKELCID(int lgid, int srtid) { + return new LCID(_MAKELCID(lgid, srtid)); + } + + /** + * construct the locale id from a language id, sort id, and sort version. + * + * @param lgid + * @param srtid + * @param ver + * @return + */ + public static final LCID MAKESORTLCID(int lgid, int srtid, int ver) { + return new LCID(_MAKELCID(lgid, srtid) | (ver << 20)); + } + + /** + * extract the language id from a locale id. + * + * @param lcid + * @return + */ + public static final int LANGIDFROMLCID(LCID lcid) { + return lcid.intValue() & 0xFFFF; + } + + /** + * extract the sort id from a locale id. + * + * @param lcid + * @return + */ + public static final int SORTIDFROMLCID(LCID lcid) { + return (lcid.intValue() >>> 16) & 0xf; + } + + /** + * extract the sort version from a locale id. + * + * @param lcid + * @return + */ + public static final int SORTVERSIONFROMLCID(LCID lcid) { + return (lcid.intValue() >>> 20) & 0xf; + } + + /** + * Construct language id from a primary language id and a sublanguage id. + * + * @param p Language ID + * @param s Sublanguage ID + * @return + */ + public static final int MAKELANGID(int p, int s) { + return (s << 10) | (p & 0xFFFF); + } + + /** + * Extract primary language id from a language id. + * + * @param lgid Language ID + * @return + */ + public static final int PRIMARYLANGID(int lgid) { + return lgid & 0x3ff; + } + + /** + * Extract sublanguage id from a language id. + * + * @param lgid Language ID + * @return + */ + public static final int SUBLANGID(int lgid) { + return (lgid & 0xFFFF) >>> 10; + } + } + + public static final int LANG_SYSTEM_DEFAULT = LocaleMacros.MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT); + public static final int LANG_USER_DEFAULT = LocaleMacros.MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); + + public static final LCID LOCALE_SYSTEM_DEFAULT = LocaleMacros.MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT); + public static final LCID LOCALE_USER_DEFAULT = LocaleMacros.MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT); + + public static final LCID LOCALE_NEUTRAL = LocaleMacros.MAKELCID(LocaleMacros.MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT); + + public static final LCID LOCALE_INVARIANT = LocaleMacros.MAKELCID(LocaleMacros.MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT); } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Ole32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Ole32Test.java index 73ce524542..3cae8086c2 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Ole32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Ole32Test.java @@ -126,4 +126,16 @@ public void testCoTaskMemRealloc() { Ole32.INSTANCE.CoTaskMemFree(ptr); } + + public void testOleFunctions() { + HRESULT initResult = Ole32.INSTANCE.OleInitialize(Pointer.NULL); + + assertTrue(W32Errors.SUCCEEDED(initResult)); + + // For a real test, a test component will be needed + Ole32.INSTANCE.OleFlushClipboard(); + Ole32.INSTANCE.OleRun(Pointer.NULL); + + Ole32.INSTANCE.CoUninitialize(); + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/OleAutoTest.java b/contrib/platform/test/com/sun/jna/platform/win32/OleAutoTest.java index 1f8f758c38..ec22397fa8 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/OleAutoTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/OleAutoTest.java @@ -20,6 +20,8 @@ import com.sun.jna.platform.win32.WinDef.LCID; import com.sun.jna.platform.win32.WinNT.HRESULT; import com.sun.jna.platform.win32.COM.COMUtils; +import com.sun.jna.platform.win32.Variant.VARIANT; +import com.sun.jna.platform.win32.WTypes.VARTYPE; import com.sun.jna.ptr.PointerByReference; /** @@ -62,4 +64,33 @@ public void testLoadRegTypeLib() { assertEquals(0, hr.intValue()); } + public void testVariantConvertBoolean() { + VARIANT variant = new Variant.VARIANT(true); + OleAuto.INSTANCE.VariantChangeType(variant, variant, OleAuto.VARIANT_ALPHABOOL, new VARTYPE(Variant.VT_BSTR)); + assertEquals("Variant-Type", Variant.VT_BSTR, variant.getVarType().intValue()); + assertEquals("Variant-Value", "True", variant.stringValue()); + OleAuto.INSTANCE.VariantClear(variant); + + VARIANT.ByReference variant2 = new Variant.VARIANT.ByReference(); + variant2.setValue(Variant.VT_BOOL, new OaIdl.VARIANT_BOOL(true)); + OleAuto.INSTANCE.VariantChangeType(variant2, variant2, OleAuto.VARIANT_ALPHABOOL, new VARTYPE(Variant.VT_BSTR)); + assertEquals("Variant-Type", Variant.VT_BSTR, variant2.getVarType().intValue()); + assertEquals("Variant-Value", "True", variant2.stringValue()); + OleAuto.INSTANCE.VariantClear(variant2); + } + + public void testVariantConvertBSTR() { + VARIANT variant = new Variant.VARIANT("42"); + OleAuto.INSTANCE.VariantChangeType(variant, variant, (short) 0, new VARTYPE(Variant.VT_INT)); + assertEquals("Variant-Type", Variant.VT_INT, variant.getVarType().intValue()); + assertEquals("Variant-Value", 42, variant.intValue()); + OleAuto.INSTANCE.VariantClear(variant); + + VARIANT.ByReference variant2 = new Variant.VARIANT.ByReference(); + variant2.setValue(Variant.VT_BSTR, OleAuto.INSTANCE.SysAllocString("42")); + OleAuto.INSTANCE.VariantChangeType(variant2, variant2, (short) 0, new VARTYPE(Variant.VT_INT)); + assertEquals("Variant-Type", Variant.VT_INT, variant2.getVarType().intValue()); + assertEquals("Variant-Value", 42, variant2.intValue()); + OleAuto.INSTANCE.VariantClear(variant2); + } }