This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Help request for GitHub sample UsingManagedAssemblies

Hello everyone,

I would like to create an UI extension add-on for M-Files, but I am new to developing for M-Files,
so I decided to start with adjusting the sample code and see where it gets me.

1. I downloaded UsingManagedAssemblies sample from github:
https://github.com/M-Files/MFilesSamplesAndLibraries/tree/master/Samples/UIX%20Applications/UsingManagedAssemblies
2. I zipped the contents of uix folder and installed it to [color=blue]MyVault[/color] using the M-Files Admin tool.
3. Upon entering [color=blue]MyVault[/color] using the M-Files Online explorer, I got a popup window stating: "MyVault says Hello!".
4. I was happy to have successfully installed and ran the sample add-on!

Next, I wanted to add an extra method to the:

Class1.cs file:

public class Class1 {
public void ShowMessage(Int32 parentHWND, string message, dynamic vault) {
// Get a reference to the window from the provided handle.
IWin32Window parentWindow = Control.FromHandle((IntPtr)parentHWND);

// Show the message.
MessageBox.Show(parentWindow, $"{vault.Name} says {message}");
}

public string GetString() {
return "GetString()";
}
}


main.js file:

function getShellFrameStartedHandler(shellFrame) {
return function() {
var clrObject = MFiles.CreateObjectCLR( "MyClassLibrary.dll", "MyClassLibrary.Class1" );
        var myString = clrObject.GetString();
clrObject.ShowMessage( shellFrame.OuterWindow.Handle, "Hello!", shellFrame.ShellUI.Vault );
};
}


So that I can use myString value instead of the hardcoded: "Hello!" string in the line:
[size=12pt]clrObject.ShowMessage( shellFrame.OuterWindow.Handle, "Hello!", shellFrame.ShellUI.Vault );[/size]
(I did not change the "Hello!" string for myString variable yet. I only added the var myString = clrObject.GetString(); into the main.js file)

I zipped the new .dll and main.js together with appdef.xml into a .zip file and installed it onto [color=blue]MyVault[/color] again.

Upon opening [color=blue]MyVault[/color] using the M-Files Online explorer I get the following error message:
https://imgur.com/a/2iIT4zg
(The green text is my translation for you)
With the following details:
CoScriptDelegate_Events.cpp, 396, Objekt nepodporuje t?to vlastnosť alebo met?du (0x80040008)
IDispatchInvocation.cpp, 96, Objekt nepodporuje t?to vlastnosť alebo met?du (0x80040008)
Managed Assemblies: main.js, 49, Objekt nepodporuje t?to vlastnosť alebo met?du (0x80040008)
MErrorHelper.cpp, 2457, Objekt nepodporuje t?to vlastnosť alebo met?du (0x80040008)
(M-Files 20.1.8669.3)


Does anyone know what is the problem?
What am I doing wrong?


The uix.zip can be found in the attachments.
uix.zip
  • It looks like your class library was compiled in x86 format, but I think it should be "Any CPU". Can you re-compile and check again?

    Regards,

    Craig.
  • Hello Craig Hawker,

    I recompiled my class library with AnyCpu setting as a Debug version, but I receive the same error message.
    Do you perhaps have a sample where the following type exchange is demonstrated?
    From .js to C# and vice versa.

    byte
    int
    float
    long
    double
    char
    string
    bool


    Full solution and compiled class library can be found here:
    https://www.sendspace.com/file/5xaana
  • Hi Marian,

    I have just tested here (code below, for your reference) and got a message saying "Hello!Craig" (yes, I forgot a space). My current assumption is that the DLL was locked on your machine when you updated the application (Windows Explorer tends to do this with managed assemblies; it's one of the most awkward things about using them) and is giving you the previous version of the DLL (the one without the GetString method).

    Can you try completely killing the Windows Explorer and the M-Files Desktop Client processes (or rebooting) and trying to access it again?

    Altered Class1.cs:

    using System;
    using System.Windows.Forms;

    namespace MyClassLibrary
    {
    ///
    /// The class which will be instantiated from the UIX application.
    ///
    public class Class1
    {
    public string GetString()
    {
    return "Craig";
    }

    ///
    /// Shows a message from within the managed assembly.
    ///
    /// A handle for the parent window (see www.m-files.com/.../index.html
    /// The message to show, which will be prefixed by the vault name.
    /// The M-Files API Vault object (see www.m-files.com/.../index.html
    public void ShowMessage(Int32 parentHWND, string message, dynamic vault)
    {
    // Get a reference to the window from the provided handle.
    IWin32Window parentWindow = Control.FromHandle((IntPtr)parentHWND);

    // Show the message.
    MessageBox.Show(parentWindow, $"{vault.Name} says {message}");
    }
    }
    }


    Altered main.js:

    // NOTE! This code is for demonstration purposes only and does not contain any kind of
    // error handling. MUST be revised before using in production.

    "use strict";

    function OnNewShellUI( shellUI )
    {
    // This is the start point of a ShellUI module.

    // Register to be notified when a new normal shell frame (Event_NewNormalShellFrame) is created.
    // We use Event_NewNormalShellFrame rather than Event_NewShellFrame as this won't fire for history (etc.) dialogs.
    // ref: www.m-files.com/.../index.html
    shellUI.Events.Register(
    Event_NewNormalShellFrame,
    handleNewNormalShellFrame );
    }

    function handleNewNormalShellFrame(shellFrame)
    {
    /// Handles the OnNewNormalShellFrame event for an IShellUI.
    /// The shell frame object which was created.

    // The shell frame was created but it cannot be used yet.
    // The following line would throw an exception ("The object cannot be accessed, because it is not ready."):
    // shellFrame.ShowMessage("A shell frame was created");

    // Register to be notified when the shell frame is started.
    // This time pass a reference to the function to call when the event is fired.
    shellFrame.Events.Register(
    Event_Started,
    getShellFrameStartedHandler(shellFrame) );
    }

    function getShellFrameStartedHandler(shellFrame)
    {
    /// Returns a function that handles the OnStarted event for an IShellFrame.

    return function()
    {
    // The shell frame is now started and can be used.

    // Instantiate the managed object.
    // ref: www.m-files.com/.../index.html
    // In the case below "MyClassLibrary.dll" is the name of the file to load the class from.
    // In this case, the file is loaded from the root of the UIX application.
    // "MyClassLibrary.Class1" is the full class name (including namespace) to instantiate.
    // This class must have an accessible constructor.
    var clrObject = MFiles.CreateObjectCLR( "MyClassLibrary.dll", "MyClassLibrary.Class1" );

    // Call the "ShowMessage" method on the CLR object.
    clrObject.ShowMessage( shellFrame.OuterWindow.Handle, "Hello!" + clrObject.GetString(), shellFrame.ShellUI.Vault );
    };
    }



    Regards,

    Craig.
  • Hello Craig,

    Your suggestion to reboot my computer before I open [color=blue]MyVault[/color] works fine and the added code now works!

    I also tried killing:
    1. Visual Studio IDE (people on the internet say it may be locking the .dlls)
    2. Windows Explorer
    3. M-Files Desktop Client process and then reopen the application with my desktop icon,
    but I got an error message as shown on the picture below.
    https://imgur.com/a/cVlog0k

    Did I kill the wrong process or should I open a different application this time?
    (According to what the error message states)

    I would like to avoid having to reboot my computer because of every test.
    (I understand it is not your fault, that the .dll is being locked by my machine,
    but I could not find out whether just killing and restarting the processes could do the magic,
    due to the issue mentioned above.)
  • Are you a local administrator on your machine? That looks like a permissions issue...

    The process I tend to go through is:
    1. Go to "services" and restart the M-Files Desktop Client service. This will probably get stuck on "stopping".
    2. Go to the list of processes and kill the M-Files Desktop Client process. This should then make the service stop/start properly.
    3. Go to the Windows Explorer process and restart it.

    Normally, at this point, I can replace the managed assembly.

    One thing I'd like to highlight is that managed assemblies are really not used very much in UIX, and I would recommend that you avoid them unless you have a specific reason to use them. One great use I've seen before is to use the Windows file/folder pickers or to interact with the file system (because both of these things are not very easy otherwise). But, for general UIX work, I'd highly recommend that you try and avoid them.

    Regards,

    Craig.
  • I am a student of Creative Media and Game Technologies degree and two weeks ago I started to work on my graduation internship.
    (Deliverables: written report & meaningful product)

    Which leads me to the reason why I want to use managed assemblies together with M-Files:

    I have a SFML/OpenGL/C++ backend which is going to take care of visualizing M-Files metadata in 3D.
    This backend is wrapped in C++/CLR and imported into a C# project as a .dll.
    Next, I will be building this C# project into a .dll so that I can connect it with M-Files the way we have been discussing in these posts.
    This is the state of my research so far.

    Next to come:
    1. I still have to find out how to properly receive metadata from [color=blue]MyVault[/color] and send it over to the 3D visualizer, so that it can adjust.
    2. Another requested feature is to be able to pass adjusted or new data (documents, reports, relationships) from the 3D environment into [color=blue]MyVault[/color].
    3. Last preferred feature is to have this 3D representation rendered inside of M-Files on one of the tabs.
    (If this is not possible, 3rd party window will do, but if it is possible, but hard, I will give it a go!)

    Please have a look at the 3. one and let me know if this is even possible with what M-Files has to offer, if you will.
    (All I would need is the TAB (window) handle to render to. By TAB I mean a tab such as the Metadata tab in M-Files Desktop Client)

    I am not yet sure if managed assemblies are the way to go in order to assure these two main features, but here I am to find out.
    If you perhaps get what I aim for and see where I could change the track, do not hesitate to give me a pointer.
  • Okay, that sounds cool. Really interested to see what you end up building!

    Regards,

    Craig.
  • Hi Marian,

    Custom tabs can be added to M-Files through the UIX (github.com/.../ShowWebPageInIFrame). The tab itself shows a HTML page. Whether you can do #3 or not will depend on whether there's a viewer/renderer available that you can embed within one of these HTML "dashboards" (and whether our web viewer control allows it to be used, which is another potential issue!).

    Regards,

    Craig.
  • Craig,

    Thank you a lot for your guidance!

    With hope to save the SFML/OpenGL backend option, I have one question:
    Is there a way to get the "dashboard object" handle, so that I can create an SFML rendering area into an already existing control?
    SFML RenderWindow constructior definition - https://imgur.com/a/op0fKDf
    SFML RenderWindow documentation for additional information - https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1RenderWindow.php#a25c0af7d515e710b6eebc9c6be952aa5

    Otherwise it seems like I would have to construct a completely different backend to be able to render into a HTML page.
    Perhaps one which uses THREE.js https://threejs.org/
    (This would be an option, but due to lack of knowledge about web apps development and time, I am still trying to squeeze out all I can from the first option.)
  • If you could use a popup window instead of a tab, then you may be able to use IDashboard.Window.Handle (www.m-files.com/.../ I've never tried to do something like this, though, so I am unsure how M-Files would cope with you potentially altering the window contents in this way.

    If you're looking to get as much done as possible then part of me does wonder whether you'd be better off doing this via an external application instead; you could use the standard COM API to push and pull data back and forth to M-Files, and maybe use the UIX to add a button to the M-Files desktop which launches your application (github.com/.../OpenExternalApplicationOnCommand).

    You could then look at creating a custom tab/dashboard using something like threejs.org after you've gotten the functionality working in a more forgiving environment.

    Regards,

    Craig.