dotNET & MapInfo Extensibility

566 views
Skip to first unread message

Sancarn

unread,
Jun 7, 2017, 7:06:32 AM6/7/17
to MapInfo-L
Hi all,

I'm reading up in the MapInfo Pro Extensibility Reference as I would like to start using .NET in applications. In the 'Getting Started' section it says:

The Main Extensibility Interface is
MapInfo.Types.IMapInfoPro which provides access to MapInfo Pro core functionality such as windows, events, MapBasic applications, etc. You must use SYSTEMINFO(SYS_INFO_IMAPINFOAPPLICATION) method to access the MapInfo Pro instance, which returns IMapInfoPro type object.

How exactly does one do this?

For example in VB.NET:

    Dim MI as Object = GetObject(,"MapInfo.Application.x64")
    Console.WriteLine(MI.Eval("SystemInfo(20)"))

With the above code I get 'Error 440 - No valid mode specified', something I already expected. I think I've been down this road before.

I have downloaded a sample already showing how to use C# / VB.NET code inside MapInfo using MapBasic, E.G.

VB Code:
    Namespace MapInfo.MiPro.Samples
        ''' <summary>
        ''' Sample code demonstrating how to call .Net from MapBasic 
        ''' </summary>
        Public Class HelloWorld
            Public Shared Sub SayHello(ByVal s As String)
                ' Display a greeting in a standard .Net dialog box
                System.Windows.Forms.MessageBox.Show("Hello, " + s)
            End Sub
        End Class
    End Namespace

MB Code:
    '
    ' Declare a .Net method (for source code, see HelloWorld.cs or HelloWorld.vb)
    '
    Declare Method SayHello Class "MapInfo.MiPro.Samples.HelloWorld"  Lib "MapBasicSamples.dll" (ByVal strName As String)

    Declare Sub Main

    Sub Main

        'Call the .Net method.  
        Call SayHello("Chris")

    End Sub

Do you have to call code from inside an MBX as above if you want to hook onto events / modify the ribbon?

Cliff B

unread,
Jun 18, 2017, 7:58:16 PM6/18/17
to MapInfo-L
SystemInfo(SYS_INFO_IMAPINFOAPPLICATION) returns a type THIS (32bit int) , which you'll need to cast to a string to return from the .eval then convert it back in to an intptr once back in .net

Sancarn

unread,
Jun 19, 2017, 2:50:16 AM6/19/17
to MapInfo-L
Have you tried this and does it actually work? :O

Javier García (Genasys)

unread,
Jun 19, 2017, 5:11:47 AM6/19/17
to MapInfo-L

Hello Scarn,

 Dim MI as Object = GetObject(,"MapInfo.Application.x64")
 
 With this option you get the COM object. It supports only 2 mnethods for OLE automation: DO and EVAL and I think you can't manage the mapinfo ribbon.
 
 How Cliff says you have to use SystemInfo(SYS_INFO_IMAPINFOAPPLICATION) for get mapinfo object and pass to .net
 
 Theese are the steps
 
 1. In .net you have to reference MapInfo.Types.dll in a class library
 2. In .net you have to use MapInfo instance like this 
     
Imports MapInfo.Types
Namespace MapInfo.MiPro.Samples.BasicRibbon
    Public Class Class1

        Public Shared Function getCountTabs(ByVal mapInfoApplication As IMapInfoPro) As Integer
            Dim count As Integer

            count = mapInfoApplication.Ribbon.Tabs.Count

            Return count

        End Function

    End Class

End Namespace
 
 
 3. In Mapbasic you have to get instance of MapInfo Pro x64 
 
 This is the full code in Mapbasic
 
Include "mapbasic.def"
Include "IMapInfoPro.def"

Declare Method getCountTabs Class "MapInfo.MiPro.Samples.BasicRibbon.Class1" Lib "BasicRibbon.dll" Alias getCountTabs (ByVal p1 as refptr) as integer 
Declare sub main()


Sub main()
Dim  mapinfoApplication as This
Dim  nTabs as integer 
    
        mapinfoApplication = SYSTEMINFO(SYS_INFO_IMAPINFOAPPLICATION)
  nTabs = getCountTabs (mapinfoApplication)

note nTabs
End Sub

Sancarn

unread,
Jun 19, 2017, 11:42:18 AM6/19/17
to mapi...@googlegroups.com

Thanks for the full example. This is also the way it is documented to work. However I was mainly wondering if I can avoid:
1. Compiling code to a dll, I'd prefer a .exe
2. Calling methods via mapbasic, ideally I would call my methods directly from the host application.

Something akin to this:

So in step 3 the difference is we are modifying the ribbon directly rather than through the MBX medium.

I guess it would be possible to instead declare a single method in MBX which can be called directly via OLE, which passes data directly to the .NET DLL, and from there we can manipulate the ribbon or anything really. But that's by far an ideal solution. I would need to wrap the entire MapInfo .NET APIs to be dynamically callable in this way... 


Edit:

Just had an idea which might just work. If I wrap the .NET objects in a COM wrapper I would be able to, through a static MBX, wrap all .NET functionality which isn't available by the 'do/eval' commands. This may be the simplest solution there is instead of setting up a router in MapInfo via an MBX.

Will still have to do some shenanigans to run the MBX on the correct instance of MapInfo though I guess I could simply register each different MapInfo instance to it's own CLSID

Cliff B

unread,
Jun 22, 2017, 9:42:42 PM6/22/17
to MapInfo-L
I've just tested this and the SystemInfo(20) even run from the mapbasic window in MIPro gets the same error even assigning it to a "This" type variable . No idea what causes that but clearly that approach isn't going to work.

As for identifying the "correct" instance of MapInfo, how do you know which is the correct instance when you first start your exe?

I have an MBX that calls everything and still uses the DispatchID(as a string to get around the integer length issue) and implements it as a DMapInfo in .net because I have had lots of race conditions and threading issues with IMapInfoPro.
EvalMapBasicCommand
I then do all my Ribbon Manipulation from the MBX using the IMapInfoPro.def calls directly. Again its not clean but it functions.

Sancarn

unread,
Jun 24, 2017, 4:56:15 AM6/24/17
to MapInfo-L
Yeah I believe this type variables don't work at all in the MapBasic window and/or OLE. My question was rather could the MBX get Systeminfo(20) and return that to the exe somehow? :P I don't think this is possible though... I think, to use the .NET interface it has to be part of the same process as MapInfo, so I would have to inject a DLL into MapInfo for that, and even then .NET may not be initialised...

As for identifying the "correct" instance of MapInfo. I determine the most correct instance to be the window belonging to MapInfoPro.exe which was last activated by the user. From the window I get the HWND. Then I get a list of active COM objects from the RunningObjectTable (ROT), loop through all objects with prefix "!MapInfo.Application" and call MI.Eval("systeminfo(7)"). When this value == HWND then we know we've got the correct instance of MapInfo. From here we can use the retrieved COM object to manipulate MapInfo.

The real problem for me with using an MBX is that it's for the JavaScript engine :P For that reason I would want to choose the option which wouldn't require a huge amount of maintenance... MapBasic isn't so good here unless I know how to dynamically compile into MBX, which I am slowly getting closer to so that's good...

Cliff B

unread,
Jul 4, 2017, 8:14:40 PM7/4/17
to MapInfo-L
If you just need to make sure any tables you open are in the same instance you run queries on you could start your own instance of MapInfo from .net

Have a look at C:\Program Files (x86)\MapInfo\MapBasic\Samples\DOTNET\IntegratedMappingWinForms
Reply all
Reply to author
Forward
0 new messages