|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Tue Dec 29, 2009 9:07 am
[2.xx,3.xx] COM problem (A solution found) |
Zugg, I know you were not interested in fixing the COM problems, but I will continue to post them anyway since they affect me and will affect anyone else that attempt to use this feature. The number of users wanting to use COM objects will increase when non-mudders start using CMUD as a front-end anyway. So here it goes...
If an external application has the following signature
Code: |
public rettype methodname(vartype param1, object[] param2) {....} // C, C++, C#
|
or
Code: |
public rettype methodname(vartype param1, params object[] param2) {....} // C# only
|
or
Code: |
public rettype methodname(params object[] param1) {....} // C# only
|
you will pass the parameters to the application incorrectly and either INVALID NUMBER OF PARAMETERS or THE PARAMETER IS INVALID is returned as a parsing error.
If I call a method using one of these types of signatures from a C, C++, or C# application there is no problem, so the problem must lie with CMUD.
IMO what is happening is that CMUD is looking at the method signature and trying to marshal the parameters it sees in the COM function call to the application to match the signature (which is fine), but since an array is being used (or not, as it is sometimes the case with C#) and a mixed parameter list is involved, it passes the paremeters incorrectly.
For instance, in the 3rd case above, one can pass a regular CSV list to the application and the CLR will marshal it into an array for consumption by the method (params is a keyword that indicates a variable number of parameters), but CMUD seeing an array signature, will complain.
Perhaps this comes about because at the time COM for ZMUD was developed, the 2nd and 3rd type of signatures didn't exist and, therefore, are not being taken into account (this doesn't explain with the first type of signature fails, though).
Without this fix, one is forced to write a method overload for each parameter count, rather than passing a variable parameter list to the method.
One way to get around these problems, I think, is to ignore the target signature and pass the parameters as a CSV and let the target application front-end worry about whether the parameter list is correct or not.
Oddly enough, when a Python script is invoked from CMUD (via COM) using a CSV list, it works just fine even though the method signature looks like this:
Code: |
def MethodName (var1, *var2)
|
which , as you can see, is equivalent to the 2nd signature above. |
|
_________________ Sic itur ad astra.
Last edited by Anaristos on Tue Jan 05, 2010 12:06 am; edited 1 time in total |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Jan 04, 2010 6:32 pm |
When ever you have any sort of COM array argument, you will need to use the %array function in CMUD to create the proper parameter list.
Also, keep in mind that C# is creating a .NET interface and not a traditional COM interface. The COM support in CMUD (and zMUD) is the traditional COM API and doesn't have any extensions for anything Microsoft added to COM with .NET.
At the low level you are describing, there is very little I can do. I'm calling the COM routines supplied by Delphi to execute a COM object method or retrieve a COM property. I don't do any of the low-level marshaling myself.
This kind of stuff has always been an issue for COM. It really isn't as "language independant" as it should be. Obviously if your COM object is created in C/C++/C# and then called from a C/C++/C# application it is going to work fine because both are using the same exact types of data structures. But calling your C/C++/C# COM object from another language (like Delphi) has a completely different implementation of arrays.
The fact that CMUD is working with your last Python example tends to make me think that Python is handling it correctly but that your C/C++/C# system is using some sort of Microsoft extension that isn't part of the basic COM API or something. |
|
|
|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Tue Jan 05, 2010 12:05 am |
I have found a solution to the problem. Taking into account that you are using Delphi as the COM driver I am now passing the paramters to the mthod this way:
Code: |
$rec = @comobj.MethodName("param1",%array("param2",....,"paramN"))
|
which seems to be working.
Delphi IS misreading the target method signature, however.
If the target method signature is
Code: |
public rettype methodname(string str, params object[] param2)
|
it should just pass the parameters as is rather than expect an array as the second parameter. The params keyword indicates to the runtime that if parameters from that position on are simple ones, they will be handed to the method in an array, it doesn't mean that an array is expected (though not excluded, in which case the runtime expects a single array parameter).
So by including the params keyword in the array the method can be called also this way
Code: |
$rec = MethodName("param1", "param2",....,"paramN")
|
In this case the runtime stuffs "param2" through "paramN" into an array and hands it to the method. So both call styles are equivalent.
At any rate I am glad that there is a solution. Thanks for your patience.
EDIT note to those writing applications, the array must be of object[] type, if any other type is used, CMUD will get a type mismatch error. |
|
_________________ Sic itur ad astra. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jan 05, 2010 5:26 pm |
Actually, CMUD or Delphi is "misreading" anything. Nothing in the COM system that CMUD is using actually reads the signatures. CMUD is not looking at the Type Library for your object (because some COM objects don't have type libraries). CMUD and Delphi are just passing the arguments without looking at them. That's why I said you needed to use %array to create a proper COM array to send to your object.
I haven't looked at this stuff in a long time and don't really know anything about the "params" keyword. Is it possible that this is something that was added later to the COM spec by Microsoft in .NET and isn't supported by the older COM API? In other words, is this just something used in C/C++/C#, or is it really part of the COM spec somewhere? Because it seems like that kind of stuff should be happening in the lower level part of Windows. If CMUD just passes regular arguments, shouldn't the low-level COM system be detecting the "params" keyword and then handling the arguments properly? CMUD isn't working at that kind of low level. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Jan 05, 2010 5:27 pm |
Oh, also, if you have a DLL that uses the "params" keyword, go ahead and send it to me along with instructions on how to call it. I can play around with some Delphi test programs to see if it's really something I can handle on my end or not. It's also possible that the newer version of Delphi has improved some of this.
|
|
|
|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Tue Jan 05, 2010 11:55 pm |
OK, I will build a small test case and mail it to you.
The one drawback with the solution I am using, which really is indicative of the overall problem, is that I have to send an array with a null element (because CMUD won't create empty arrays), when one doesn't want to pass any parameters.
So if the signature is
Code: |
public rettype methodname(params object[] args)
|
and I don't want to pass any paramenters (params is used when the arguments beyond the keyword are optional) then I have to do this from CMUD
Code: |
#CALL @comobj.methodname(%array(%null))
|
if done this way, it will get an "invalid number of parameters" error.
Code: |
#CALL @comobj.methodname()
|
NOTE: The reason Python has no problems with using either signature (from the original post) is because it is not a strongly typed language. It is up to the method to check how the parameters were passed. So if you pass 4 string arguments or 1 string argument and and array with 3 strings in it, it won't complain. Unfortunately, Windows 7 is having problems with Python Windows scripts at the moment so I can't test this aspect any further. |
|
_________________ Sic itur ad astra. |
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|