Unable to use JNA to pass in the save format parameter for SaveAs function of Word COM interface

429 views
Skip to first unread message

Michael Whapples

unread,
May 10, 2013, 8:21:43 AM5/10/13
to jna-...@googlegroups.com
Hello,
I wrote before on this topic, basically I cannot get JNA to pass the
save format parameter of the SaveAs function to word.

All my attempts to create a VARIANT to pass in as this parameter fail.
Since writing I have looked at this further. According to the Microsoft
documentation, it says that the Document object has a SaveFomrmat
property which will report the format which will be used should no save
format be given to SaveAs. It also says that the value of SaveFormat
property can be passed in to the SaveAs function. When I use JNA to get
the SaveFormat property and then call SaveAs using the value from
SaveFormat property the call to SaveAs fails, saying that it cannot
coerse one of the parameters.

As I said in my other message the call to SaveAs works when I only pass
in the filename parameter.

Please can someone help with this. As I said I have this working with
jacob java COM bridge, so either I am missing something with JNA or
there is a bug in the JNA COM code.

Thanks in advance.

Michael Whapples

Timothy Wall

unread,
May 10, 2013, 2:21:44 PM5/10/13
to jna-...@googlegroups.com
I'm no COM expert, but might be able to spot something if you were to show the two versions (JNA and jacob) side by side (the data setup and invocation).

Keep in mind that the VARIANT is a union and as such, needs to have the "active" type set on the union before JNA can automatically copy the Java fields to native memory.
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Michael Whapples

unread,
May 13, 2013, 5:45:21 AM5/13/13
to Java Native Access
My JNA code for calling SaveAs looks like this (from a class extending
COMObject representing the Document object in Word):

public void saveAs(String fileName, int format) {
BSTR bstrFileName = OleAuto.INSTANCE.SysAllocString(fileName);
VARIANT varFileName = new VARIANT(bstrFileName);
WinDefLONG lFormat = new WinDef.LONG(format);
VARIANT varFormat = new VARIANT(lFormat);
this.oleMethod(OleAuto.DISPATCH_METHOD, null, this.getIDispatch(),
"SaveAs", new VARIANT[] {varFileName, varFormat});
}

I have tried getting the format parameter from the SaveFormat property
of Word and using that for varFormat:

VARIANT.ByReference varFormat = new VARIANT.ByReference();
this.oleMethod(OleAuto.DISPATCH_PROPERTYGET, varFormat,
this.getIDispatch(), "SaveFormat");

This does not work either. However should I change the actual call to
SaveAs so the line looks like:
this.oleMethod(OleAuto.DISPATCH_METHOD, null, this.getIDispatch(),
"SaveAs", new VARIANT[] {varFileName});
This works fine but does not allow me to save the document in my
desired format.

As far as I understand using the constructor VARIANT(WinDef.LONG)
should create the variant and set the type all for me.

The working jacob code looks like this:

public void saveAs(String fileName, int format) {
Dispatch.call(oDoc, "SaveAs", fileName, format);
}

Where oDoc is of type Dispatch and is the Document object. Jacob must
be doing some automatic type conversion for me from the standard Java
types.

Michael Whapples

Timothy Wall

unread,
May 13, 2013, 8:52:34 AM5/13/13
to jna-...@googlegroups.com
It *looks* OK to me, but Tobias should comment on the specifics (he's authoring the new COM support).

All I can suggest is verify that the format has a valid value and that the implementation for VARIANT for WinDef.LONG is set up properly in the COM support.

Note that VARIANT.ByReference() is superfluous when passing a parameter; VARIANT is interpreted as a pointer (i.e. by reference) by default when used as a parameter.

You'll also need to explicitly call `Union.setType(); Structure.read()` after retrieving `varFormat`; JNA doesn't know the type of the `VARIANT` so it can't fully read it after the native call.

Michael Whapples

unread,
May 14, 2013, 7:55:37 AM5/14/13
to Java Native Access
Thanks for the response.

It appears like the problem may relate to calling COM functions with
multiple parameters, only the first value seems to be apssed in, but
it becomes the last on the actual COM call with the others being null.
The fact the first parameter becomes the last is not a surprise as
when I looked about using COM from C I noticed comments about needing
to pass parameters in reverse order.

Here is my test code. I created a COM server using python, the
function basically takes three strings and joins them together and
returns the joined up string.

class TestCom:
_public_methods_ = ["concat"]
_reg_progid_ = "TestCom.Application"
_reg_desc_ = "Test COM stuff"
_reg_clsid_ = "{41A6BEE3-46ED-4610-B28A-EF2B1E1A4616}"
def concat(self, msg1, msg2, msg3):
return " ".join([str(msg1), str(msg2), str(msg3)])

if __name__ == "__main__":
import win32com.server.register
win32com.server.register.UseCommandLine(TestCom)

Here is my Java method implementing the function call through JNA.

public String concat(String msg1, String msg2, String msg3) throws
COMException {
BSTR bstr1 = OleAuto.INSTANCE.SysAllocString(msg1);
BSTR bstr2 = OleAuto.INSTANCE.SysAllocString(msg2);
BSTR bstr3 = OleAuto.INSTANCE.SysAllocString(msg3);
Variant.VARIANT varMsg1 = new Variant.VARIANT(bstr1);
Variant.VARIANT varMsg2 = new Variant.VARIANT(bstr2);
Variant.VARIANT varMsg3 = new Variant.VARIANT(bstr3);
Variant.VARIANT.ByReference pvResult = new
Variant.VARIANT.ByReference();
this.oleMethod(OleAuto.DISPATCH_METHOD, pvResult,
this.getIDispatch(), "concat", new Variant.VARIANT[] {varMsg1,
varMsg2, varMsg3});
return pvResult.getValue().toString();
}

Now if from Java I call concat("Hello", "my", "world"); I get "None
None Hello" returned (None being python's null object).

As this seems to be a bug I will file a bug report.

I am using 3.5.2, so if a fix has been made in master since then, let
me know and it will save needing to file a bug report.

Thanks

Timothy Wall

unread,
May 14, 2013, 12:54:58 PM5/14/13
to jna-...@googlegroups.com, wolf....@gmx.net
that's a good thing to know. perhaps tobias will get a chance to look at this more closely; have you looked at his office examples? surely he had some functions that were passing more than one argument...

Michael Whapples

unread,
May 15, 2013, 5:19:40 AM5/15/13
to Java Native Access
I have filed an issue on the github page relating to this bug.

Yes I have looked at the office demo, that was where I learnt most of
my understanding of JNA's COM support. Slightly surprising but I don't
remember there being any call passing in more than one parameter.

May be I am making an incorrect assumption over how to pass in
multiple parameters, I just took it that the version of oleMethod
which accepts a VARIANT array is for multiple parameters. The source
code seems to suggest it is as it uses the length of the array to set
the number of parameters.

I will have a go with the latest JNA from master in case something has
been fixed since 3.5.2.

Tobias Wolf

unread,
May 20, 2013, 5:03:54 AM5/20/13
to jna-...@googlegroups.com
Hi guys,
 
I`ve provided a changed sample for saving MSWord files in a different Format, Please check the link above with the changed files. I`ve recreated a test case to prove your request for a bug (your comment about the variant Parameter ordering), but for now it`s working correctly!
 
 
I dont see your complete code, therefore I think your`re using the wrong pointer here:
 
 this.oleMethod(OleAuto.DISPATCH_METHOD, null, this.getIDispatch(),  --> THIS should be a valid Document pointer!!!!

"SaveAs", new VARIANT[] {varFileName});
 
I ran sucessful tests with RTF and HTML format.
 

msWord.SaveAs(

"C:\\TEMP\\jnatestSaveAs.rtf", wdFormatRTF);

msWord.SaveAs(

"C:\\TEMP\\jnatestSaveAs.html", wdFormatHTML);

public void SaveAs(String FileName, LONG FileFormat) throws COMException {
  VARIANT[] args = new VARIANT[2];
  args[0] = new VARIANT(FileFormat);
  args[1] = new VARIANT(FileName);
  
  this.invokeNoReply("SaveAs", this.getActiveDocument().getIDispatch(),
    args);
 }

 

I`m with you and I understand your pyton sample, but I dont have it and cannot reproduce it!

Tobias Wolf

unread,
May 20, 2013, 5:25:09 AM5/20/13
to jna-...@googlegroups.com
Hi Michael,
 
some comments for the Array recerse ordering.
 
First you are right, but it`s not a bug, it`s a feature ;-). The COM invoke method expect the variant Parameter array in reverse ordering. These MS guys are crazy, because in Java even in C++ it`s not common to to that way.
 
Second the documentation says it that in needs the reverse array ordering and the JNA COM support is already being used by some people. I can change it, but then maybe will some others code no longer run.
 
Question to the community: Shall I changed it or leave it????
 

On Friday, May 10, 2013 2:21:43 PM UTC+2, Michael Whapples wrote:

Tobias Wolf

unread,
May 20, 2013, 6:15:39 AM5/20/13
to jna-...@googlegroups.com
I decided to change the parameter reverse ordering as expected by COM runtime by default.

Use the newest code as below:

 

https://github.com/twall/jna/commit/7ae490a39305400b87da4d7c161d248df2b5031c

 

 

Timothy Wall

unread,
May 20, 2013, 7:42:42 AM5/20/13
to jna-...@googlegroups.com
why? I would think normal ordering would be expected.

Ideally we'd be generating some interfaces based on typelibs, like com4j does.

I'm trying to the the COM tests to run on XP, but have quite a few failing. one in particular can't seem to do CoCreateInstance on Shell.Application/IShellDispatch. Do I need to register something before this will work?

Michael Whapples

unread,
May 21, 2013, 5:27:26 AM5/21/13
to Java Native Access
Thanks for this. May be the problem for me was that I am using JNA
3.5.2, its my general policy to use release versions unless there is
something I need in development code. Also useful to know about it
being in the other branch, again I possibly would have missed this
work as I probably would go for master first.

I will take a look at this to see if it resolves it for me, by the
sound it probably will.

Michael Whapples

Tobias Wolf wrote:
> Hi guys,
>
> I`ve provided a changed sample for saving MSWord files in a different
> Format, Please check the link above with the changed files. I`ve recreated
> a test case to prove your request for a bug (your comment about the variant
> Parameter ordering), but for now it`s working correctly!
>
> *
> https://github.com/twall/jna/commit/4c114f779617950e8212fcc38892c59bb3b3dd92
> *<https://github.com/twall/jna/commit/4c114f779617950e8212fcc38892c59bb3b3dd92>

Michael Whapples

unread,
May 21, 2013, 5:31:46 AM5/21/13
to Java Native Access
On the question of whether needing to pass parameters in reverse order
like in the underlying C COM interface, I guess the question is
whether the JNA COM support is simply a Java interface for the C COM
interface or whether its meant to be a bit higher level.

In my mind it doesn't really matter too much, but it might be worth
having a comment in the JavaDoc explaining whether it does take
parameters in reverse order or not. The main thing is one needs to
know what they need to do.

Michael Whapples

Tobias Wolf wrote:
> Hi Michael,
>
> some comments for the Array recerse ordering.
>
> First you are right, but it`s not a bug, it`s a feature ;-). The COM invoke
> method expect the variant Parameter array in reverse ordering. These MS
> guys are crazy, because in Java even in C++ it`s not common to to that way.
>
> Second the documentation says it that in needs the reverse array ordering
> and the JNA COM support is already being used by some people. I can change
> it, but then maybe will some others code no longer run.
>
> *Question to the community*: Shall I changed it or leave it????

Michael Whapples

unread,
May 21, 2013, 12:31:55 PM5/21/13
to Java Native Access
I have now tested this in my code, yes it works. Is there any possible
estimation when this may enter the main branch of JNA and when it will
be in a released version?

Thanks

Michael Whapples

Daniel Doubrovkine

unread,
May 22, 2013, 5:51:35 PM5/22/13
to jna-...@googlegroups.com
Please make a pull request. See https://github.com/twall/jna/blob/master/www/Contributing.md. Do let us know if you need any help.

--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.





--

dB. | Moscow - Geneva - Seattle - New York
dblock.org - @dblockdotorg - artsy.net

Tobias Wolf

unread,
May 26, 2013, 5:06:30 AM5/26/13
to jna-...@googlegroups.com
I changed the ordering, because a normal java guys would except that a array takes parameters in usal order not in reverse ordering, that`s a microsoft specific thing. Otherwise we`ll get a call after call because nobody knows that behaviour.

Shell mean more or less the windows explorer. I don`t think a special registration is needed. What is the error you get back?

Timothy Wall

unread,
May 26, 2013, 8:56:28 AM5/26/13
to jna-...@googlegroups.com

On May 26, 2013, at 5:06 AM, Tobias Wolf wrote:

> I changed the ordering, because a normal java guys would except that a array takes parameters in usal order not in reverse ordering, that`s a microsoft specific thing. Otherwise we`ll get a call after call because nobody knows that behaviour.

I understand that, and I would expect the interface to have normal ordering, but didn't you just say you changed it again to do reverse (COM) ordering?


>
> Shell mean more or less the windows explorer. I don`t think a special registration is needed. What is the error you get back?

I'm getting errors on a *lot* of COM stuff (this is on XP, Vista, win7, all mostly vanilla systems). There are multiples of all of these. For example:

Ole32Test testCoCreateInstance Failure Class not registered

junit.framework.AssertionFailedError: Class not registered
at com.sun.jna.platform.win32.Ole32Test.testCoCreateInstance(Ole32Test.java:97)

IUnknownTest testQueryInterface Error Invalid memory access

java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:344)
at com.sun.jna.Function.invoke(Function.java:276)
at com.sun.jna.Function.invoke(Function.java:235)
at com.sun.jna.Function.invokeInt(Function.java:642)
at com.sun.jna.platform.win32.COM.IUnknown.QueryInterface(IUnknown.java:76)
at com.sun.jna.platform.win32.COM.IUnknownTest.testQueryInterface(IUnknownTest.java:70)

ITypeInfoTest testGetRefTypeOfImplType Error N/A

java.lang.NullPointerException
at com.sun.jna.platform.win32.COM.ITypeInfo.GetRefTypeOfImplType(ITypeInfo.java:126)
at com.sun.jna.platform.win32.ITypeInfoTest.testGetRefTypeOfImplType(ITypeInfoTest.java:137)

ITypeLibTest testGetTypeInfoOfGuid Error Unexpected Typelib error code : 0x24

com.sun.jna.platform.win32.COM.COMException: Unexpected Typelib error code : 0x24
at com.sun.jna.platform.win32.COM.COMUtils.checkTypeLibRC(COMUtils.java:281)
at com.sun.jna.platform.win32.ITypeLibTest.testGetTypeInfoOfGuid(ITypeLibTest.java:97)

ITypeLibTest testGetTypeComp Error No type description was found in the library with the specified GUID.

com.sun.jna.platform.win32.COM.COMException: No type description was found in the library with the specified GUID.
at com.sun.jna.platform.win32.COM.COMUtils.checkTypeLibRC(COMUtils.java:278)
at com.sun.jna.platform.win32.ITypeLibTest.testGetTypeComp(ITypeLibTest.java:119)

ITypeLibTest testGetTypeInfo Error Unexpected Typelib error code : 0x5

com.sun.jna.platform.win32.COM.COMException: Unexpected Typelib error code : 0x5
at com.sun.jna.platform.win32.COM.COMUtils.checkTypeLibRC(COMUtils.java:281)
at com.sun.jna.platform.win32.ITypeLibTest.testGetTypeInfo(ITypeLibTest.java:74)

OleAutoTest testLoadRegTypeLib Error Unexpected Typelib error code : 0x8002801D

com.sun.jna.platform.win32.COM.COMException: Unexpected Typelib error code : 0x8002801D
at com.sun.jna.platform.win32.COM.COMUtils.checkTypeLibRC(COMUtils.java:281)
at com.sun.jna.platform.win32.OleAutoTest.testLoadRegTypeLib(OleAutoTest.java:70)

Daniel Doubrovkine

unread,
May 26, 2013, 9:16:12 AM5/26/13
to jna-...@googlegroups.com
Same here, fyi. Win7/64. 
Reply all
Reply to author
Forward
0 new messages