I tried to translate the SHGetFileInfo function from Shell32 into Java with JNA and used C# code and this as reference
While in the C# code psfi.iIcon is 432 in my translated Java code psfi.iIcon is 0. If I am right, for the same file they should be same no matter which language I use, shouldn't they?
My Java code:
public static void main(String[] args) {
String path = "[PATH_TO_EXE]\\test.exe"; //Of course in my code I used the real path
SHFILEINFO sfi = new SHFILEINFO();
DWORD_PTR i = Shell32.INSTANCE.SHGetFileInfo(path, 0, sfi, sfi.size(), SHGFI.SysIconIndex);
System.out.println(sfi.iIcon); //<-- Prints 0, should print 432
}
public static class SHGFI {
static final int SysIconIndex = 0x000004000;
static final int LargeIcon = 0x000000000;
static final int UseFileAttributes = 0x000000010;
}
public interface Shell32 extends StdCallLibrary {
Shell32 INSTANCE = Native.loadLibrary("shell32", Shell32.class, W32APIOptions.UNICODE_OPTIONS);
DWORD_PTR SHGetFileInfo(String pszPath, int dwFileAttributes, SHFILEINFO psfi, int cbFileInfo, int uFlags);
}
public static class SHFILEINFO extends Structure {
public HICON hIcon;
public int iIcon;
public DWORD dwAttributes;
public char[] szDisplayName = new char[260];
public char[] szTypeName = new char[80];
#Override
protected List<String> getFieldOrder() {
return Arrays.asList("hIcon", "iIcon", "dwAttributes", "szDisplayName", "szTypeName");
}
}
Is there anything fundemental that I did wrong? I'm new to JNA and Windows functions
Under the Remarks section, there is this piece of information, which imho might be the source of your problem
You must initialize Component Object Model (COM) with CoInitialize or
OleInitialize prior to calling SHGetFileInfo.
It's a pretty straightforward call
CoInitialize(null);
As DanielWiddis pointed out in the comments, per documentation
New applications should call CoInitializeEx instead of CoInitialize
And
To close the COM library gracefully, each successful call to
CoInitialize or CoInitializeEx, including those that return S_FALSE,
must be balanced by a corresponding call to CoUninitialize
Example
CoInitializeEx(null, 0);
CoUninitialize();
Related
I would like to use the MMDevice API from my Java app. What are my options?
I tried to use JNA. Looks like I can't use JNA Typelib parsing because there no types for this API (Is there a COM type library for Windows Core Audio). As suggested, I need to provide my own declarations of the API.
So I also tried both JNA examples with manual declarations but they give "Interface not supported HRESULT=80004002" error:
public class MMDeviceAPITest {
public static void test1() {
try {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
var obj = new Test1.MMDeviceEnumerator(); // exception E_NOINTERFACE (HRESULT: 80004002)
// ...
} finally {
Ole32.INSTANCE.CoUninitialize();
}
}
public static void test2() {
try {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
var factory = new Factory();
var obj = factory.createObject(Test2.MMDeviceEnumerator.class); // exception E_NOINTERFACE (HRESULT: 80004002)
var in = obj.queryInterface(Test2.IMMDeviceEnumerator.class);
// ...
} finally {
Ole32.INSTANCE.CoUninitialize();
}
}
}
interface Test1 {
class MMDeviceEnumerator extends COMLateBindingObject {
public MMDeviceEnumerator() {
super(new Guid.CLSID("bcde0395-e52f-467c-8e3d-c4579291692e"), true);
}
}
}
interface Test2 {
#ComObject(clsId = "bcde0395-e52f-467c-8e3d-c4579291692e")
interface MMDeviceEnumerator extends IUnknown {} // doesn't extend IUnknown in C sources, probably it's the problem...
#ComInterface(iid = "a95664d2-9614-4f35-a746-de8db63617e6")
interface IMMDeviceEnumerator extends IUnknown {}
}
Any ideas how I could access this API from Java? Can I somehow create working declarations for JNA? Or use another framework maybe?
My last idea is to create/find a micro native app/library that wraps the needed COM calls, so I could call this app/library easily (via subprocesses or simple JNA declarations). I'm new to COM world, but it sounds working for me...
The docs you linked show how to create using CoCreateInstance:
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
This should get you somewhere close with JNA.
class MMDeviceEnumerator extends Unknown {
public static final CLSID CLSID_MMDeviceEnumerator = new CLSID("bcde0395-e52f-467c-8e3d-c4579291692e");
public static final GUID IID_IMMDeviceEnumerator = new GUID("a95664d2-9614-4f35-a746-de8db63617e6");
public MMDeviceEnumerator(Pointer p) {
super(p);
}
public static MMDeviceEnumerator create() {
PointerByReference pEnumerator = new PointerByReference();
HRESULT hres = Ole32.INSTANCE.CoCreateInstance(
CLSID_MMDeviceEnumerator, null,
WTypes.CLSCTX_ALL, IID_IMMDeviceEnumerator,
pEnumerator);
if (COMUtils.FAILED(hres)) {
return null;
}
return new MMDeviceEnumerator(pEnumerator.getValue());
}
// map functions as needed
}
I used the implementation of IWbemContext in JNA as a template above. You can consult that class for example COM function mappings.
For some reason I can't suggest edits to the answer of Daniel Widdis. The answer worked for me, many thanks! Just wanted to show how to map one method as an example:
class MMDeviceEnumerator extends Unknown {
public static final CLSID CLSID_MMDeviceEnumerator = new CLSID("bcde0395-e52f-467c-8e3d-c4579291692e");
public static final GUID IID_IMMDeviceEnumerator = new GUID("a95664d2-9614-4f35-a746-de8db63617e6");
public MMDeviceEnumerator(Pointer p) {
super(p);
}
public static MMDeviceEnumerator create() {
PointerByReference pEnumerator = new PointerByReference();
HRESULT hres = Ole32.INSTANCE.CoCreateInstance(
CLSID_MMDeviceEnumerator, null,
WTypes.CLSCTX_ALL, IID_IMMDeviceEnumerator, pEnumerator);
if (COMUtils.FAILED(hres)) {
return null;
}
return new MMDeviceEnumerator(pEnumerator.getValue());
}
public static final int EDataFlow_eRender = 0;
public static final int EDataFlow_eCapture = 1;
public static final int EDataFlow_eAll = 2;
public static final int EDataFlow_enum_count = 3;
public static final int DEVICE_STATE_ACTIVE = 0x1;
public static final int DEVICE_STATE_DISABLED = 0x2;
public static final int DEVICE_STATE_NOTPRESENT = 0x4;
public static final int DEVICE_STATE_UNPLUGGED = 0x8;
public static final int DEVICE_STATEMASK_ALL = 0xF;
public void EnumAudioEndpoints(int dataFlow, int dwStateMask, PointerByReference ppDevices) {
WinNT.HRESULT res = (WinNT.HRESULT) _invokeNativeObject(
3, // `EnumAudioEndpoints` is the 3rd method of `IMMDeviceEnumeratorVtbl` in `mmdeviceapi.h`
new Object[] { getPointer(), dataFlow, new WinDef.DWORD(dwStateMask), ppDevices},
WinNT.HRESULT.class
);
COMUtils.checkRC(res);
}
// map other functions as needed
}
I have an external library:
public class ExternalLib { ... }
I want to use it in my project so I initiated it like this in the class I will use in my project:
public class Codec {
private static final ExternalLib externalLib = new ExternalLib();
public static String encode(String x, int l, Long s, int f) {
return externalLib.encode(x, l, s, f);
}
public static ExternalLib decode(String y) {
return externalLib.decode(y);
}
I would like to protect my class Codec in case anyone change sth in class ExternalLib, so was wondering how could I introduce here a new class/interface? and map the externalLib (in the body of decode method)? Was thinking about wrapping externalLib and than mapping it into new object that I will return when performing decode method. Anyone can help me with that?
I am writing a java application that will access to C++ dll usnig JNA. So I prepared a C dll to communicate between the JNA and C++ thrid party dll. I have these two structs:
C code:
struct Struct1
{
uint32_t Size;
unsigned char* Data;
};
struct Struct2
{
uint32_t Struct1_Nbr;
Struct1* struct1_elements;
};
bool Open(char* fileName, Struct2** struct2);
Now I am writing the corresponding JNA code in java application and I want to access the "unsigned char* Data" without copying this data as it is a large amount of Data.
How can I use the "Memory" or the "Pointer" JNA types to do this task?
Here is my attempt:
public class Test
{
public static class Struct1 extends com.sun.jna.Structure {
public Struct1(){}
public Struct1(Pointer pointer){
super(pointer);
read();
}
public static class Struct1ByValue extends Struct1 implements com.sun.jna.Structure.ByValue{};
public int Size;
public Memory Data;
public static class Struct1ByReference extends Struct1 implements com.sun.jna.Structure.ByReference{}
#Override
protected List getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList("Size", "Data");
};
public static class Struct2 extends com.sun.jna.Structure {
public Struct2 (){}
public Struct2 (Pointer pointer){
super(pointer);
read();
}
public int Struct2_Nbr;
public Struct1.Struct1ByReference struct1_elements = new Struct1.Struct1ByReference();
public static class Struct2ByValue extends Struct2 implements com.sun.jna.Structure.ByValue{};
public static class Struct2ByReference extends Struct2 implements com.sun.jna.Structure.ByReference{}
#Override
protected List getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList("Struct1_Nbr", "struct1_elements"));
};
}
public interface StructureProtocol extends com.sun.jna.Library{
Boolean Open(String fileName, PointerByReference struct2);
}
public StructureProtocol lib;
public Test(){
this.lib = (StructureProtocol) Native.loadLibrary("TestAPI", StructureProtocol.class);
}
public static void main(String[] args) {
Test test = new Test();
PointerByReference pref = new PointerByReference();
test.lib.Open("filePath", pref);
Pointer ptr = pref.getValue();
Struct2 struct2= new Struct2(ptr);
Struct1[] struct1_array= (Struct1[])(struct2.struct1_elements).toArray(struct2.struct1_Nbr);
System.out.println("struct1_array[0]: Size = " + struct1_array[0].Size);
System.out.println("struct1_array[0]: Data= " + struct1_array[0].Data);
}
}
Any advice would be very appreciated.
Here is my Solutiuon, first Draft:
Declare a Class in java that extends Structure
(com.sun.jna.Structure)
(all fields in the class must be public or you get an error, that the size of the structure extended class can't be measured)
public class Struct1 extends Structure{
public int Size;
public String Data;
}
Declare and define a method in the C Dll, that takes a pointer to the structure as an argument (I created a structure and filled it with values for testing)
void __declspec(dllexport) GetStruct(Struct1* a){
Struct1 s;
s.Size = 9;
s.Data = "Output";
*a = s;
}
I assume that you already successfully connected the java app to the c dll, so i skip that part(if my assumption is wrong, tell me in the comments and i edit my answer)
If you add these lines to your java code (note cdll is the handle to my C library)
Struct1 test = new Struct1();
cdll.GetStruct(test);
System.out.println("Struct1: " + test.Size + " " + test.Data);
You should get the data from the Structure s in the C Dll.
If the Data field points to arbitrary data, use a Pointer. If the native side allocates, then you do nothing. If the Java side allocates, use a Memory object assigned to that field.
As for the struct* and struct**, it'd be useful to see some native code using those constructs in order to tell what they represent, since there is some ambiguity (struct* could be a pointer to a single struct, or a pointer to a contiguous array of them). struct** could be storage allocated for the return of a struct*, or it may be something else.
I am attempting to use JNA to invoke the QueryContextAttributes function in the Secur32.dll on Windows. I am unable to get the invocation correct for the SECPKG_ATTR_SIZES call. I have an implementation working for SECPKG_ATTR_NAMES and SECPKG_ATTR_PACKAGE_INFO. Therefore, I presume (famous last words) the issue is in the definition of the structure, or something about the invocation.
The Microsoft function definition for QueryContextAttributes is:
SECURITY_STATUS SEC_Entry QueryContextAttributes(
_In_ PCtxtHandle phContext,
_In_ ULONG ulAttribute,
_Out_ PVOID pBuffer
);
The Microsoft structure definition for the SecPkgContext_Sizes is:
typedef struct _SecPkgContext_Sizes {
ULONG cbMaxToken;
ULONG cbMaxSignature;
ULONG cbBlockSize;
ULONG cbSecurityTrailer;
} SecPkgContext_Sizes, *PSecPkgContext_Sizes;
The JNA library (I'm using jna-4.2.2 and jna-platform-4.2.2) provides an implementation in the Secur32 for some of the functions in that .dll. The definitions for the structures are at:
SecPkgContext_Names structure,
SecPkgInfo structure, and
SecPkgContext_Sizes structure
I therefore have defined the following:
public interface ISecur32 extends Secur32 {
// get own copy of the INSTANCE variable
ISecur32 INSTANCE = (ISecur32) Native.loadLibrary("Secur32",
ISecur32.class,
W32APIOptions.UNICODE_OPTIONS);
// method definition to match
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
PointerByReference pp);
//
// for the SECPKG_ATTR_NAMES call
// NOTE: this definition and invocation is working
//
public static class SecPkgContext_Names extends Structure {
public Pointer pName;
public SecPkgContext_Names(Pointer p)
{ super(p); }
#Override
protected List<?> getFieldOrder()
{ return Arrays.asList(new String[] { "pName" }); }
}
//
// for the SECPKG_ATTR_SIZES call
// NOTE: This invocation is NOT working
//
public static class SecPkgContext_SizesBis extends Structure {
public NativeLong cbMaxToken;
public NativeLong cbMaxSignature;
public NativeLong cbBlockSize;
public NativeLong cbSecurityTrailer;
public SecPkgContext_SizesBis(Pointer p)
{ super(p); }
#Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "cbMaxToken", "cbMaxSignature",
"cbBlockSize", "cbSecurityTrailer"});
}
} //interface
The call for the Names (which is working) is:
public static void querySecPkgAttr_Names(CtxtHandle phContext) {
final int SECPKG_ATTR_NAMES = 1;
PointerByReference pp = new PointerByReference();
int rc = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_NAMES,
pp);
if (rc != 0) {
_log.error("Error in QueryContextAttributes: {}", rc);
return;
}
Pointer p = pp.getPointer();
ISecur32.SecPkgContext_Names names = new ISecur32.SecPkgContext_Names(p);
names.read();
String name = names.pName.getWideString(0);
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
}
When I attempt to obtain the Sizes (specifically, I'm after the cbMaxSignature value), I use the following call:
public static int querySecPkgAttr_Sizes(CtxtHandle phContext) {
final int SECPKG_ATTR_SIZES = 0; // SECPKG_ATTR_SIZES is 0
PointerByReference pp = new PointerByReference();
int res = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_SIZES,
pp);
// NOTE: the call is succeeding, so this line is not invoked
if (res != 0) {
return new NativeLong(0);
}
// NOTE: I have also used pp.getPointer()
Pointer p = pp.getValue();
ISecur32.SecPkgContext_Sizes sizes =
new ISecur32.SecPkgContext_Sizes(p);
// THIS LINE THROWS THE Invalid Memory Access Error
sizes.read();
NativeLong maxSig = sizes.cbMaxSignature;
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
return maxSig.intValue();
}
Using the above call, I receive the Exception stack trace of:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.getInt(Native Method)
at com.sun.jna.Pointer.getInt(Pointer.java:601)
at com.sun.jna.Pointer.getValue(Pointer.java:389)
at com.sun.jna.Structure.readField(Structure.java:705)
at com.sun.jna.Structure.read(Structure.java:565)
at gov.sandia.dart.sspi.Utils.querySecPkgAttr_Sizes(Utils.java:145)
If instead of the pp.getValue() call, I use pp.getPointer(), I receive (when trying to instantiate the Object, I believe):
java.lang.IllegalArgumentException: Structure exceeds provided memory bounds
I am at a loss as to how to solve this issue.
I apologize for not having a complete program, but to get to the point of having the CtxtHandle needed requires a romp through AcquireCredentialsHandle and InitializeSecurityContext. I believe these are working appropriately, as the Kerberos ticket is showing in the MSLSA cache (viewable via klist) after the InitializeSecurityContext completes.
I also looked at the solution Waffle, but it does not set the correct flags for in the initialization loop, and also does not implement QueryContextAttributes, or the ultimate goal in all of this the MakeSignature function.
I apologize for the length of the post. If I have omitted any piece of information, please let me know.
Thank you!
I was able to resolve the issue I was having, though not in a very elegant manner. Rather than attempting to use the a PointerByReference in the QueryContextAttributes as suggested in the question, I ended up creating multiple method definitions, one for each structure. So I have in the Interface, the approach of:
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
SecPkgContext_NegotiationInfo negoInfo);
public static class SecPkgContext_NegotiationInfo extends Structure
{
public Pointer pPackageInfo;
public int negotiationState;
public SecPkgContext_NegotiationInfo() {
super();
}
public SecPkgContext_NegotiationInfo(Pointer p) {
super(p);
}
#Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "pPackageInfo", "negotiationState"
});
}
}
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
SecPkgContext_Sizes sizes);
public static class SecPkgContext_Sizes extends Structure
{
public int cbMaxToken;
public int cbMaxSignature;
public int cbBlockSize;
public int cbSecurityTrailer;
public SecPkgContext_Sizes() {
super();
}
public SecPkgContext_Sizes(Pointer p) {
super(p);
}
#Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "cbMaxToken",
"cbMaxSignature",
"cbBlockSize",
"cbSecurityTrailer"
});
}
}
And so forth for the few definitions I need.
Ultimately the goal was to get the MakeSignature call to work (the QueryContextAttributes(...) being a precursor), and I had trouble leveraging the default JNA SecBufferDesc structure. I found a pointer to a solution from JSch SSPI by Joe Khoobyar, and leveraged the basic definition from that site, changing the NativeLong objects to int, and adding the new required method getFieldOrder().
The MakeSignature method, following definitions from Microsoft, was defined in the Interface as:
public int MakeSignature(CtxtHandle phContext,
int fQOP,
ISecur32.SecBufferDesc pMessage,
int messageSeqNo);
After using the above methods for QueryContextAttributes and the modified structure for SecBufferDesc, I was able to get a working solution. The Java clients may now leverage the Microsoft SSPI system for SSO to the remote Linux machines.
I am trying to solve the following problem for days. My JNA program gets hanged while execution of particular native function and debugging shows program control gets lost at particular location in JNA Source. Here are the details.
I have three native functions in DLL which I am trying to access with JNA.
They are as follows
DllExport long calculatePayment(...,Protection protectionArr[PROTECTION_SIZE],
Others othersArr[OTHERS_SIZE],RC rcArr[RC_SIZE], ...);
DllExport long bufferCalculatePayment(const char *inputBuffer, char **OutputBuffer);
DllExport long fileCalculatePayment(const char *InputFile, const char *OutputFile);
Corresponding Java interface mapping is as follows
public interface DLLInterface extends Library {
public DLLInterface INSTANCE = (DLLInterface) Native.loadLibrary("DLLInterface",
DLLInterface.class);
/* Others Structure is as follows.. protection and rc structure is similar with their
own initialize methods*/
public static final NativeLong othersSize = new NativeLong(20);
class Others extends Structure {
public static class ByValue extends Others implements Structure.ByValue {
}
public double amt = 0.00;
public NativeLong flag = new NativeLong();
public byte[] details = new byte[50]; //
public byte[] mDetails = new byte[50];
public NativeLong flag2 = new NativeLong();
public static Structure[] initialize() {
Others result = new Others();
Others[] resultArr = (Others[]) result.toArray(othersSize);
return resultArr;
}
public void setDetails(String dataIn) {
Arrays.fill(details, (byte) 0);
if (dataIn != null) {
String data = dataIn;
if (data.length() > 49) {
data = data.substring(0, 49);
}
byte[] bytes = data.getBytes();
System.arraycopy(bytes, 0, details, 0, bytes.length);
}
}
//other set functions here
#Override
protected List getFieldOrder() {
return Arrays.asList("amt", "flag", "details", "mDetails", "flag2");
}
}
//Protection and RC sturcutre are similar. Both structures contain fields
of the type byte[] and double.
//Prototypes for native functions
NativeLong calculatePayment(.....Structure[] protectionArr, Structure[]
othersStruct , Structure[] rcArr,.....) ;
Nativelong bufferCalculatePayment(Strubg inputBuffer, PointerByReference
OutputBuffer);
Natuvelong fileCalculatePayment(String InputFile, String OutputFile);
}
//In main function I am calling these functions as follows -
public static void main(String args[]){
DLLInterface.Others[] othersArr = (DLLInterface.Others[])
DLLInterface.Others.initialize();
DLLInterface.RC[] rcArr = (DLLInterface.RC[]) DLLInterface.RC.initialize();
DLLInterface.Protection[] protectionArr = (DLLInterface.Protection[])
DLLInterface.Protection.initialize(); //static method
...
//passing values to structures
...
//few native functions calls goes here (they get executed successfully
NativeLong y =
DLLInterface.INSTANCE.calculatePayment(....protectionArr,othersArr,rcArr, ...);
String inputBuffer = ""<?xml version= \"1.0\" ?><ROOT><REQ><TRANSACT>
<ID>12345</ID><METHOD>COMPOUND</METHOD><AMT>50000</AMT><TERM>360</TERM></TRANSACT>
</REQ></ROOT>";
NativeLong b = DLLInterface.INSTANCE.bufferCalculatePayment(inputBuffer,pRef);
DLLInterface.INSTANCE.fileCalculatePayment("InFile","OutFile");
}
For all three functions program gets hanged..never get terminated so I tried to debug the code. Then I found that after invocation of
Object result = invoke(args, nativeType, allowObjects) , program control gets lost in after following for loop. I listed few lines of source code from
Function.java file source- JNA source
public Object invoke(Class returnType, Object[] inArgs, Map options){
.......
result = resultConverter.fromNative(result, context);
....
// Sync all memory which might have been modified by the native call
if (Structure.ByReference[].class.isAssignableFrom(inArg.getClass()))
{ Class type = inArg.getClass().getComponentType();
Structure[] ss = (Structure[])inArg;
for (int si=0;si < ss.length;si++) {
Pointer p =array.getPointer(Pointer.SIZE * si);
ss[si] =Structure.updateStructureByReference(type, ss[si], p);
} //////*///////////////////////*/program control gets lost after this
}.........}
What could be the problem any guesses? Is there something wrong with native functions or my mapping of arguments is incorrect.
Any help is much appreciated..