我在java项目中使用jna-4.5.1。这是我要复制的cryptdlg structure cert\u select\u struct。
typedef struct tagCSSA {
DWORD dwSize;
HWND hwndParent;
HINSTANCE hInstance;
LPCSTR pTemplateName;
DWORD dwFlags;
LPCSTR szTitle;
DWORD cCertStore;
HCERTSTORE *arrayCertStore;
LPCSTR szPurposeOid;
DWORD cCertContext;
PCCERT_CONTEXT *arrayCertContext;
LPARAM lCustData;
PFNCMHOOKPROC pfnHook;
PFNCMFILTERPROC pfnFilter;
LPCSTR szHelpFileName;
DWORD dwHelpId;
HCRYPTPROV hprov;
} CERT_SELECT_STRUCT_A, *PCERT_SELECT_STRUCT_A;
我的项目的示例java代码。
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize = size();
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
@Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
...// parentHwnd and hCertStore are initalized and passed to this method
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
WinCrypt.CERT_CONTEXT[] pContexts = new WinCrypt.CERT_CONTEXT[1];
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pContexts[0] = new WinCrypt.CERT_CONTEXT.ByReference();
certSel.setArrayCertContext(pContexts);
cryptdlg.CertSelectCertificate(certSel); //line 60
...
}
}
当我调用这个方法时,在dll调用中得到“java.lang.error:invalid memory access” cryptdlg.CertSelectCertificate(certSel)
在上面第60行。
java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:419)
at com.sun.jna.Function.invoke(Function.java:354)
at com.sun.jna.Library$Handler.invoke(Library.java:244)
at com.sun.proxy.$Proxy13.CertSelect(Unknown Source)
at com.project.Crypto.CertSelect(Crypto.java:60)
我不知道为什么我们会有例外。我遵循了这里提到的例子。
[更新]
值得一提的是,当我从指向hcertstore[]的指针修改“setarraycertstore”的类型时,我没有得到任何异常,但是没有得到任何证书。
它让我思考arraycertstore初始化是否正确。
WinCrypt.HCERTSTORE[] cStoreArray = new WinCrypt.HCERTSTORE[1];
pCertSelectInfo.cCertStore = 1;
cStoreArray[0] = hCertStore;
pCertSelectInfo.arrayCertStore = cStoreArray;
结构定义更改如下
public WinCrypt.HCERTSTORE[] arrayCertStore;
以及 HCRYPTPROV
定义为
public static class HCRYPTPROV extends BaseTSD.ULONG_PTR {
public HCRYPTPROV() {}
public HCRYPTPROV(long value) {
super(value);
}
}
==================================
[编辑]与丹尼尔和其他人讨论后。下面是最新的代码
public class Crypto {
public interface Cryptdlg extends Library {
Cryptdlg INSTANCE = (Cryptdlg) Native.loadLibrary("Cryptdlg", Cryptdlg.class, W32APIOptions.DEFAULT_OPTIONS);
public boolean CertSelectCertificate(CERT_SELECT_STRUCT pCertSelectInfo);
public static class CERT_SELECT_STRUCT extends Structure {
private static final List<String> fieldOrder = createFieldsOrder("dwSize", "hwndParent", "hInstance",
"pTemplateName", "dwFlags", "szTitle", "cCertStore", "arrayCertStore", "szPurposeOid",
"cCertContext", "arrayCertContext", "lCustData", "pfnHook", "pfnFilter", "szHelpFileName",
"dwHelpId", "hprov");
public static class ByReference extends CERT_SELECT_STRUCT implements Structure.ByReference {
}
public int dwSize;
public HWND hwndParent;
public HINSTANCE hInstance;
public String pTemplateName;
public int dwFlags;
public String szTitle;
public int cCertStore;
public Pointer arrayCertStore;
public String szPurposeOid;
public int cCertContext;
public Pointer arrayCertContext;
public WinDef.LPARAM lCustData;
public Pointer pfnHook = null;
public Pointer pfnFilter = null;
public String szHelpFileName;
public int dwHelpId;
public HCRYPTPROV hprov;
public CERT_SELECT_STRUCT() {
super();
}
public WinCrypt.CERT_CONTEXT[] getArrayCertContext() {
WinCrypt.CERT_CONTEXT[] elements = new WinCrypt.CERT_CONTEXT[cCertContext];
for (int i = 0; i < elements.length; i++) {
elements[i] = (WinCrypt.CERT_CONTEXT) Structure.newInstance(WinCrypt.CERT_CONTEXT.class,
arrayCertContext.getPointer(i * Native.POINTER_SIZE));
elements[i].read();
}
return elements;
}
public void setArrayCertContext(WinCrypt.CERT_CONTEXT[] arrayCertContexts) {
if (arrayCertContexts == null || arrayCertContexts.length == 0) {
arrayCertContext = null;
cCertContext = 0;
} else {
cCertContext = arrayCertContexts.length;
Memory mem = new Memory(Native.POINTER_SIZE * arrayCertContexts.length);
for (int i = 0; i < arrayCertContexts.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, arrayCertContexts[i].getPointer());
}
arrayCertContext = mem;
}
}
public void setArrayCertStore(WinCrypt.HCERTSTORE[] stores) {
if (stores == null || stores.length == 0) {
arrayCertStore = null;
cCertStore = 0;
} else {
Memory mem = new Memory(Native.POINTER_SIZE * stores.length);
for (int i = 0; i < stores.length; i++) {
mem.setPointer(i * Native.POINTER_SIZE, stores[i].getPointer());
}
cCertStore = stores.length;
arrayCertStore = mem;
}
}
public WinCrypt.HCERTSTORE[] getArrayCertStore() {
if (arrayCertStore == null || cCertStore == 0) {
return new WinCrypt.HCERTSTORE[0];
} else {
WinCrypt.HCERTSTORE[] result = new WinCrypt.HCERTSTORE[cCertStore];
for (int i = 0; i < result.length; i++) {
result[i] = new WinCrypt.HCERTSTORE(arrayCertStore.getPointer(i * Native.POINTER_SIZE));
}
return result;
}
}
@Override
public void write() {
this.dwSize = size();
super.write();
}
@Override
protected List<String> getFieldOrder() {
return fieldOrder;
}
}
}
public void CertSelect() {
Cryptdlg cryptdlg = Cryptdlg.INSTANCE;
Cryptdlg.CERT_SELECT_STRUCT certSel = new Cryptdlg.CERT_SELECT_STRUCT();
certSel.hwndParent = parentHwnd;
certSel.szTitle = "title";
certSel.cCertStore = 1;
certSel.setArrayCertStore(new WinCrypt.HCERTSTORE[] {hCertStore});
pCertSelectInfo.cCertContext = 1;
pCertSelectInfo.arrayCertContext = new Memory(Native.POINTER_SIZE);
pCertSelectInfo.arrayCertContext.setPointer(0, Pointer.NULL);
cryptdlg.CertSelectCertificate(certSel);
...
}
}
1条答案
按热度按时间dojqjjoe1#
有几个潜在的问题领域。
首先,您混合了ansi和unicode版本。
这个
CertSelectCertificate()
函数有两个变量,一个以A
一个在里面W
. 这个-A
函数是ansi(8位字符),而-W
变体用于unicode/宽字符串(16位字符)。这些方法的主要区别在于CERT_SELECT_STRUCT
结构,同样有两个变体,CERT_SELECT_STRUCT_A
以及CERT_SELECT_STRUCT_W
.jna会自动将您Map到正确的版本(即
-W
在现代操作系统中,几乎所有情况下都使用默认类型Map器。您可能应该使用win32库的默认选项在库加载中显式添加该类型Map器:但是,您有一个显式调用来使用
-A
在您的CERT_SELECT_STRUCT()
施工单位:这迫使它使用-a版本的结构,它的字符串中每个字符只有8位。你应该给我打个电话
super()
.第二种可能性,虽然从文件上看不明显,但第一个因素,
dwSize
,应该是结构的大小。你应该把它放在你的构造器里:当您设置
arrayCertContext
现场。记录如下:指向数组的指针
CERT_CONTEXT
结构。将java端的数组定义为一个结构(它有自己的指针),并手动将其设置到内存中,而不是填充
CERT_CONTEXT
你把一个Pointer
在那里:最后用刚创建的指针地址填充“结构”的前8个字节,其中的前4个字节分配给
dwCertEncodingType
接下来的4个字节(加上4个空字节)指向ByteByReference()
现场。此外,与内存分配相比,结构数组的分配可以这样做:
另外,您可能会发现JNA5.x(目前为5.6.0)中的结构定义更加精简,其中包括
@FieldOrder
注解作为创建字段顺序列表的首选方法。