Options

DotNet passing "Missing" parameters

mihail_kolevmihail_kolev Member Posts: 379
edited 2013-01-30 in NAV Three Tier
Hi experts,

I'm trying to use the DotNet variables in NAV2009R2, the Microsoft.Office.Interop.Word assembly to create some automated document creation. Looks like it works in the beginning but I have a little problem. Almost all of the methods require parameters as "ref" - wordApp.Documents.Add(ref object Template, ref object NewTemplate, ref object DocumentType, ref object Visible). Everything works fine if I pass the parameters in variables. The problem is that these parameters are optional. In C# I can just simply define missingObj as System.Reflection.Missing.Value, but I don't find any equivalent in C/AL. If I define some dummy variable and pass it, I get TypeMismatch exception. If I pass correct parameters (Text,Boolean,Integer,Boolean) it works fine.


So the question is: Is there any way to pass "Missing" parameters. I've tried already to define Missing in C/AL as System.Reflection.Missing (mscorlib.dll), also tried to pass Variant data type... no luck :(
-Mihail- [MCTS]

Answers

  • Options
    VjekoVjeko Member Posts: 55
    In current releases using mscorlib is not fully supported, and there are tons of issues with various system types there. Declaring variables from there is not guaranteed to work (check my presentation on NAV Tech Days about .NET interop, I've talked about that).

    To make it short, you'll need to pass actual variables.

    Alternatively - but I haven't tried that! - you may want to create a .NET class with a function which returns object, like this:
    public object MissingValue()
    {
        return System.Reflection.Missing.Value;
    }
    

    Then call that class, and assign a value to a Variant variable in C/AL:
    MyCALVariant := MyDotNetClass.MissingValue();
    

    Then pass this MyCALVariant wherever Missing is needed.

    As I said - I can't guarantee this will work, as I am only theorizing here, don't have time at the moment to test this concept. Please do let me know if it works, or fails. I'd like to know.
    (Co-)author of "Implementing Microsoft Dynamics NAV 2009"
    http://vjeko.com/
  • Options
    mihail_kolevmihail_kolev Member Posts: 379
    well, this is good idea, I'll give it a try when I have some free time. But for now, I want to create my functions without registering any custom components. Thank you :)

    EDIT: btw, I attended at your presentation, it was one of the best for me on NAVTechDays
    -Mihail- [MCTS]
  • Options
    VjekoVjeko Member Posts: 55
    EDIT: btw, I attended at your presentation, it was one of the best for me on NAVTechDays

    Thanks, Mihail! :thumbsup:
    (Co-)author of "Implementing Microsoft Dynamics NAV 2009"
    http://vjeko.com/
  • Options
    mihail_kolevmihail_kolev Member Posts: 379
    @Vjeko, I tried your suggestion with the MissingValue() function. As I expected - it's not working :) ... It just crash the client when you call the function (even when you don't assign the return value to a variable).

    anyway the most interesting lines from the eventvwr:
    Type: System.ServiceModel.FaultException
    Action: http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault
    Message: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://www.microsoft.com/Dynamics/NAV/51:automationMethodResponse. The InnerException message was 'The constructor with parameters (SerializationInfo, StreamingContext) is not found in ISerializable type 'System.Reflection.Missing'.'.  Please see InnerException for more details.
    
    -Mihail- [MCTS]
  • Options
    VjekoVjeko Member Posts: 55
    This definitely looks strange - I have never experienced any serialization issues with .NET interop. I wasn't even aware any serialization was happening there - I was sure it was simply wrapping .NET interop objects into a common wrapper.

    Could you share your .NET code as well as your NAV code where you are calling this?
    (Co-)author of "Implementing Microsoft Dynamics NAV 2009"
    http://vjeko.com/
  • Options
    mihail_kolevmihail_kolev Member Posts: 379
    well, .NET code (I tried this as automation and as AddIn, same result):
    using System;
    using System.Net;
    using System.Web;
    using System.Text;
    using System.Linq;
    using System.Threading;
    using System.Globalization;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    
    namespace MissingValue
    {
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        public interface _MissingValue
        {
            [DispId(1)]
            object GetMissingValue();
        }
    
        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ProgId("MissingValue.MissingValue_")]
        public partial class MissingValue : _MissingValue
        {
            MissingValue()
            {
            }
    
            public object GetMissingValue()
            {
                return System.Reflection.Missing.Value;
            }
    
            public static object GetMissingValueStatic()
            {
                return System.Reflection.Missing.Value;
            }
        }
    }
    

    I already unregistered the assembly but the NAV code looked like this:

    as Automation variable:
    CREATE(myMissing,FALSE,ISSERVICETIER);
    myMissing.GetMissingValue();
    

    as DotNet variable:
    myMissing.GetMissingValueStatic();
    

    EDIT: and one offtopic: I'm already cool with the fact I can't pass "Missing", but I got another problem with the Microsoft.Office.Interop.Word assembly. In the Document element we got property Tables, and Tables have property Item(int index) which return a table element. Looks fine but when I try to call the Tables.Item(1) navision says
    This message is for C/AL programmers: The call to member Item failed: 'Item' is not a property..
    

    do you have any suggestion why this is happening?
    -Mihail- [MCTS]
  • Options
    VjekoVjeko Member Posts: 55
    Don't know about this indexer, but about Missing, can you try if any of these work?
    public object MissingParameter
    {
    get { return System.Reflection.Missing.Value; }
    }

    public System.Reflection.Missing MissingValue
    {
    get { return System.Reflection.Missing.Value; }
    }
    (Co-)author of "Implementing Microsoft Dynamics NAV 2009"
    http://vjeko.com/
  • Options
    mihail_kolevmihail_kolev Member Posts: 379
    I may give it a try, but I think it will have the same effect. Looks like the DotNet datatype is still buggy :bug: .

    Just a note - I left the DotNet variable and instead I took the Automation equivalent - 'Microsoft Word 14.0 Object Library'. When using the automations you can pass or not pass the optional parameters, the rest of the code is the same, you should just CREATE the automation and CLEAR it at the end (and I don't need to register any custom components on client machines :) ).
    -Mihail- [MCTS]
  • Options
    IsakssonMiIsakssonMi Member Posts: 77
    I don't know if this will help you, but RTC don't support optional COM-method parameters. Classic Client are running fine by exclude optional parameters but RTC fails, my suggestion is to fill all arguments.
  • Options
    VjekoVjeko Member Posts: 55
    Well, I've just made an example in .NET and C/AL and Missing works like charm, if used from pure .NET interop environment:

    C/AL:
    //GetValue() : Text[30]
    Missing := Missing.Missing;
    Optional := Optional.TryOptional;
    EXIT(Optional.CallMethod(Missing.MissingValue, 4));
    

    C#:
        public class TryOptional
        {
            public string CallMethod(object a = null, object b = null)
            {
                int a1 = (int) (a ?? 1);
                int b1 = (int) (b ?? 2);
                return a1 + " + " + b1 + " = " + (a1 + b1);
            }
        }
    
        public class Missing
        {
            public object MissingParameter
            {
                get { return System.Reflection.Missing.Value; }
            }
    
            public System.Reflection.Missing MissingValue
            {
                get { return System.Reflection.Missing.Value; }
            }
        }
    

    Both of the above approaches work (returning object and Missing). C/AL simply does what it's intended to do, no crashes.

    What I can only assume is what IsakssonMi says - if you are trying to wrap that into COM, it will fail due to the limitations of COM, not .NET (or DotNet). That may explain the indexer failure, as well.
    (Co-)author of "Implementing Microsoft Dynamics NAV 2009"
    http://vjeko.com/
  • Options
    nhsejthnhsejth Member, Microsoft Employee Posts: 34
    The root cause of the problem with the"Missing" class is that the value is defined as a C# public field and not as a property. The Nav interop implementation does not support public fields, only properties, which explains why it works when wrapped into a function or property.
    _________________
    Niels-Henrik Sejthen
    Senior Software Developer
    Microsoft Dynamics NAV

    The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
  • Options
    mihail_kolevmihail_kolev Member Posts: 379
    good to know, topic solved :thumbsup:
    -Mihail- [MCTS]
  • Options
    Fred_CleverFred_Clever Member Posts: 11
    Hi.

    In your CAL Example; What Type ar the Variables: Missing, Optional?
  • Options
    Fred_CleverFred_Clever Member Posts: 11
    Hi 2.

    Forgot the question!!!!

    First time I think the CAL-Code is Stamd alone!
  • Options
    2mas2mas Member Posts: 7
    Hello Guys, I see that this is quite old topic, but I had exactly same problem with very little info regarding Missing.Type solution in NAV. So hopefully for anyone who is looking for same problem it will be useful. Actually found two different ways to have Missing.Type available in C/AL, without creating your own DLL.

    1. Geting to the Type.Missing value by yourself:
    Name	DataType	Subtype	Length
    Info	DotNet	System.Reflection.FieldInfo.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    Type	DotNet	System.Type.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    MissingTypeValue DotNet	System.Object.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'	
    
    
    Type := Type.GetType('System.Reflection.Missing');
    Info := Type.GetField('Value');
    MissingTypeValue := Info.GetValue(MissingTypeValue);
    
    2. Use library provided by Microsoft with latest NAV Versions:
    Name	DataType	Subtype	Length
    TypeMissing	DotNet	Microsoft.Dynamics.Nav.Integration.Helper.'Microsoft.Dynamics.Nav.Integration.Office, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'	
    
    
    TypeMissing.GetMissingValue()
    
    

    P.S.: Don't forget to check variables parameter RunOnClient.
  • Options
    TomigsTomigs Member Posts: 85
    Hi,

    I'm getting a similar issue (need to populate a missing value) and trying to resolve it using 2mas' solutions, avoiding DLLs. But I'm not being able to use the GetMissingValue() function from the integration helper library as suggested by 2Mas (suggestion number #2).

    If I do it I get "The parameter is incorrect". I wonder if I'm not using it correctly? If anybody could share an example it would be great.

    ktn3jq9pm1v9.png

    rpo9pdk6rfek.png

    If I look to his suggestion #1, I don't find the libraries mentioned (System.Reflection.FieldInfo or System. Type, nor System.Object). What am I doing wrong? Am I missing some component that I need to install on the server?

    sz3k0k61j8gi.png

    Thanks!
    Tomas
Sign In or Register to comment.