Dot Net Dev

Historically FalconView™ has used UnmanagedCode exclusively but FalconView™ has several overlays written in C# and number of other programmers are using C# with FalconView™. Here is a place to try to document issues that you come across.

There is a very simple ManagedCode example here.


Debugging .Net PlugIns? with Visual Studio 2010

Q) We've noticed that when debugging a FalconView PlugIn with Visual Studio 2010, FalconView will start, but the debugger is not actually attached even though Visual Studio 2010 thinks it is.

A) If you detach and re-attach the debugging session, things proceed normally, but that is hardly a nice solution. Instead, create (or edit) a file next to the fvw.exe named fvw.exe.config. In this file, list the .Net runtime that VS will be using for your PlugIn. It does not seem to matter how many are listed, but only the FIRST one is useful in this case. In the case below, .Net 2.0 PlugIns? to FalconView will debug as expected.

     <?xml version ="1.0"?>    
     <!-- fvw.exe.config -->
     <configuration>
       <startup>
         <supportedRuntime version="v2.0.50727" />
         <supportedRuntime version="v4.0.30319" />
       </startup>
     </configuration>

VS 2005 Compiler Problem Question?

Q) I've been trying to compile the "Sample Managed C++ application" Visual Studio 2003 project using Visual Studio 2005 and encountering compiler errors. The FVW.TLB, FalconView COM seems to be references properly (Solution Explorer->Right-click on Project_Title->References) being displayed as "Interop.fvw.1.0" but I'm recieving the following error:

1>c:\projects\sample_managed_cpp\Form1.h(31) : error C2653: 'Interop' : is not a class or namespace name

Visual Studio Intellisense (showing valid function parameters for FVW) doesn't seem to recognize "Interop::fvw::Layer* m_pLayer;" but does see "fvw::Layer* m_pLayer;" Commenting out "/*Interop::*/" only prodced this error:

1>c:\projects\sample_managed_cpp\Form1.h(76) : error C3867: 'Sample_Managed_C::Form1::Connect_Click': function call missing argument list; use '&Sample_Managed_C::Form1::Connect_Click' to create a pointer to member

The errors produced above have been the same following and upgrade from FalconView 3.2 to 4.0 with the program running in the background. It would be terrific to start using FalconView SDK; and any suggestions would be greatly appreciated.


Map Creation Performance

Q) I am using FalconView to display a moving map on my own WinForm. Each time I get a position update, I call !IMap CreateMap, then take the resulting bitmap and !blit it onto my WinForm. At a modest update rate of about 5Hz, depending on the type of machine running the map, performance can be fair to extremely poor. !fvw.exe seems to take anywhere from 75% to 100% CPU usage. Recently I have been asked to add the ability to show various overlay elements as well. These include threats and drawing files. When I add these the CPU usage goes way up. What factors affect FalconView performance concerning map creation? Is FalconView heavily dependent on !GDI or OpenGL? Maybe my technique for drawing maps could be improved?

A) FalconView uses !GDI for all of its drawings. I would not be surprised by a 5Hz update rate depending on the size of your window and the location of your data. When you call CreateMap, FalconView needs to:

  • Find the requested !AOI in the coverage files to determine what files need to be displayed
  • Open the files, read the data (this is usually the bottleneck for internal FalconView drawing)
  • De-compress the data
  • (possibly) re-project, stretch and/or rotate the data
  • Draw whatever overlays are open which may themselves require file reads
  • Write it to a safe array
  • Pass the data to your program (across a process boundary)

Once you get the data

  • You need to create a bitmap from the safe array
  • You !blit the data to the windows form

If you want faster out-of-process performance, I recommend you set up your own cache to refresh the screen from so you only go back to FalconView every few seconds. Since you are in control of the cache and you know that the airplane does not warp to new locations, you can perform more efficient refresh functions.

A second possibility is to embed the !FV 4.0 MapRenderingEngine into your program. This will allow the data to be drawn directly onto your Device Context and will save the safe array stuff a couple of memory copies and will not need to pass the data across process boundaries. The downside of this is you will not have access to FalconView's overlays.

The biggest savings would be if you wrote your application to plug into FalconView instead of trying to plug FalconView into your application. I know this is not always possible, but it would speed thing up considerably and exposes a lot of additional functionality.

Follow up) I'm glad you clarified that FalconView uses !GDI to draw the maps. According to the FAQ the recommended requirements include a OpenGL supported graphics card.

I am in the process of getting access to FalconView 4.0. I am quite interested in the MapRenderingEngine. Once I've had time to experiment with it, I'll report back with performance results. I am also dissapointed to hear that the MapRenderingEngine does not support overlays.


Layer Initialization Problem

Q) I'm getting an error in a very simple example, and it happens on the following line of code:

this.layer = new fvw.Layer();

Here's the full method:

public Form1()

                        //
                        // Required for Windows Form Designer support
                        //
                        !InitializeComponent();

                        this.layer = new fvw.Layer();
                        this.layer.!RegisterWithMapServer("RSM CLient",(int)this.Handle, this);
                        int layerHandle = this.layer.!CreateLayer("RSMLayer");
                        this.layer.Refresh(layerHandle);

A) It looks like we have found the issue but we don't exactly know why ".NET" is doing what it is doing. The same lines work fine in !unmanaged code.

When an OLE object is created via C#, it does the following:

  1. Posts a message which ends up calling AfxOleLockApp in FalconView
  2. FalconView creates an instance of the object
  3. Finally, posts a message that eventually calls AfxOleUnlockApp

AfxOleUnlockApp will shut down the application when all the objects have been released (the application's reference count goes to zero). But, the application will only shut down this way in the case that the user is not in control of the app. The user is not in control of the app when the app is started by automation, for instance. When message 1) is handled, the reference count becomes one. When message 3) is handled the reference count becomes zero and the application exits.

The route server is not at fault but without it the app will work. The reason is that the windows message queue gets pumped while connecting to the route server. This allows other messages to be processed (in this case the messages from 1 and 3). The same problem can be demonstrated by replacing the call to connect to the route server with a call to AfxMessageBox, say. Anything that allows messages to be pumped.

For some reason, the messages in 1) and 3) are not posted to FalconView when an object is created via C++ or VB. I'm not sure what C# is doing different.

Currently, the solution in 4.0.0 is to make sure the user is control of the app before making any calls that can pump messages and then restoring the control state after the call. Better would be to figure out why C# is creating objects differently that C++ and VB and figure out to create them in a similar manner. If you figure out anything with regards to this please let us know.

We don't have a solution in 3.3.x or earlier so the only work around is to ensure that FalconView is running before starting the calling application.

John A) I solve this issue with the following code: while (mapHandle == 0) { this->m_pIMap->GetMapDisplay(&lat, &lon, &rotation, &cat, &mapHandle, &zoom, &m_ProjectionType); Sleep(1); } FV will return 0 until fvw.exe starts.

Q) - I hate to be dense, but what exactly does this statement mean (see excerpt below) and how do you implement what you are referring to? I have had the same result in all 3 languages. Does OnFalconViewReady? help this problem? I have never had this callback execute.

Excerpt: Currently, the solution in 4.0.0 is to make sure the user is control of the app before making any calls that can pump messages and then restoring the control state after the call. Better would be to figure out why C# is creating objects differently that C++ and VB and figure out to create them in a similar manner.

-- Mike Samsel - 18 Jan 2007

A) The excerpt is referring to the solution in fvw.exe code to make sure the application stays alive when created via a C# automation client. Specifically,

AfxOleSetUserCtrl(TRUE);

-- Bob De Young - 06 Apr 2007 *

A) VS2005 differs a little from VS2003 when you create a project using the windows forms template. I had this exact same problem until I compared the assemblyInfo.cs files. In your new project, open this file and look for:

[assembly: ComVisible?(false)] -- false is the default.

set that value to true ( [assembly: ComVisible?(true)]) and you're good to go...


How did you implement ICallback in C#?

A) - Define an object that inherits from the callback interface you want to implement. Once you do this C# tells you that if we pressed Tab it would fill in empty implementation methods. We did, and that was handy.

An example:

        public class ICallbackImpl : fvw.ICallback
        {
            #region ICallback Members
 
            ....

            public void OnFalconViewExit(int layer_handle)
            {
                // TODO:  Add ICallbackImpl.OnFalconViewExit implementation
            }

             ....

            #endregion

- Nothing fancy is needed to supply your object as a callback-valued argument. - Apparently, C# is very smart about making the appropriate conversions in this case. An example:

private fvw.ILayer iLayer = new fvw.LayerClass(); public const int FAILURE = -1; public const int SUCCESS = 0;

....

ICallbackImpl callback = new ICallbackImpl();

if (this.iLayer.RegisterWithMapServer(this.Name, this.Handle.ToInt32(), callback) != SUCCESS) {{{{

throw new Exception("RegisterWithMapServer() failed");

}}}}

  • ILayerTester.zip Download: Sample C# code which draws a line and adds a right click "Options" Callback on the line

Passing COM Variants to .NET Object

Q) I'm currently writing in C# managed code in the Visual Studio .NET 2002 environment using FalconView 4.0 Beta. The way I have the interfaces set up is:

falconServer = new fvw.MapClass();

ownshipLayer = new fvw.LayerClass();

ownshipLayer.RegisterWithMapServer("My Amazing Layer", windowHandle, this);

These register and display just fine, and I am happy. The problem comes in when I try to use the QueryMapTypes? method. The 4.0 ICD shows:

        long !QueryMapTypes(long category, VARIANT* map_handle_lst,

        VARIANT* deg_per_pixel_lst, long* map_type_count,

        !BOOL available_map_types_only); 

…where the VARIANTS are actually a SAFEARRAY of longs and a SAFEARRAY of doubles respectively. When I call the method, .NET Intellisense shows that the SAFEARRAYs are seen by C# as objects. So I tried the following implementation:

        object mapHandleList = new object(); 

        object degreesPerPixelList = new object(); 

        int numOfMaps = 0; 

        falconServer.!QueryMapTypes(CLIENT_DNC_CATEGORY, ref mapHandleList, 

        ref degreesPerPixelList, ref numOfMaps, 1); 

This compiles just fine, but I get a run-time Type Mismatch error on the QueryMapTypes? method call. I suspect it has something to do with the object mapHandleList and object degreesPerPixelList variables.

My question then is this: what variables do I need to send into the QueryMapTypes? method that will allow me to receive the map information? If not an object, then how do you suggest I implement a SAFEARRAY in C#?

A) I did the following after searching the web for the answer (there may be a cleaner way that I don't know)

    object !MapList = null; 

    object !MapDegPerPixelList = null;

    mMap = new fvw.!MapClass();

    int numOfMaps = 0; 
      
    const int CLIENT_RASTER_CATEGORY = 2;
      
    falconServer.!QueryMapTypes(CLIENT_RASTER_CATEGORY, ref !MapList, ref !MapDegPerPixelList, ref numOfMaps, 1); 
      
    // now unpack the array

    Array !MapHandles = (Array)!MapList; 

    Array !DegPix = (Array)!MapDegPerPixelList;

    for (int i=0; i<!MapHandles.Length; i++)
    {
  
 System.Console.W!riteLine(!MapHandles.!GetValue(i).!ToString()+ " "+ !DegPix.!GetValue(i).!ToString());
  • [ ILayerTester.zip]: This sample C# code has a button "Get Map Types" which performs the above code.

NET Exception from uninitialized variable

Q) Can you tell me why I get an exception when I call CreateMapFromGeoBounds for the following code: try

            short no_data = 0;

            int width = 0;

            int height = 0;

            object dib = null;

            object corners = null;

            
            ret = map.CreateMapFromGeoBounds(42.95785, -123.22801, 42.99204, -123.16662, 2, -2, 0,
               1, 0, ref no_data, ref width, ref height, ref dib, ref corners);

            Debug.Assert(ret != -1);


            byte[] dibBytes = (byte[])dib;

            MemoryStream dibStream = new MemoryStream(dibBytes);

//Invalid cast!!! See sparrow.zip in attachments section

            Bitmap mapBitmap = new Bitmap(dibStream);

            mapPicture.Image = mapBitmap;

         }

         catch (Exception em)

         {

            StringWriter sw = new StringWriter();

            sw.WriteLine(em.Message);

            sw.WriteLine(em.StackTrace);

            sw.WriteLine(em.Source);

            sw.WriteLine(em.TargetSite);

            MessageBox.Show(sw.ToString());

A) The problem seems to be that ".Net" understandably chokes when ever it tries to return an uninitialized pointer which is happening because -2 is not a valid Map_Handle (there is a error in our documentation). Using a valid Map_Handle (obtained by querying the map types) will be a partial fix in this exact case but more importantly YOU WILL ALWAYS NEED TO SET THE DRAW IF NO DATA FLAG TO 1 or else we will return empty objects which will cause a similar exception. In version 4.0 we will need to return a valid pointer even when data is not available.

See sparrow.zip in the attachments below for an operational example

-- Daniel Longhurst - 03 Aug 2006


Active X control to simplify .NET code

Q) Man where was this wiki a few months ago. I developed a C# app that displayed a moving map that is controlled via a web service. I'd like to share a few of my experiences with using !FV in C#.

At first I wanted to create a user control that displayed the map I asked FV to create. However the !IMap interface a few methods that don't play well with C#.

For example, QueryMapTypes? takes pointers to Variants...Yuck! As well as CreateMap. Since I needed a place to draw my maps anyway, I decided to put the !FV functionality is not an ActiveX control.

The ActiveX control was easily hosted on the C# form. I them was able to solve the variant issue down in the control.

I took SAFEARRAY** as the parameters for the map names. These translate to ref System.Array in C#.


.NET Wrapper for GEO Library

I have developed a C# wrapper around the DoD? GEO library. There is a functional interface to the library as well as an object-oriented interface. With the object oriented interface you can do things like take the difference between two GEO.Point objects and get a RangeBearing? object. It is fairly comprehensive in scope. Feel free to add features, fix bugs.

-- David Crowley - 02 Aug 2005


Exporting Static Overlays From FalconView

Q) Is it possible to get static overlay data from FalconView? For example, if the user had airports selected is there a way to get the airport data (location, length, etc.) and the icon from FalconView for each airport? After looking at the SDK, I would think the answer is no. Could this functionality be added?

A) You can get the information out of the DAFIF Database by using the DAFIF DLL. We recently did some work on the documentation and I'll try to dig up a better example than what has traditionally been in the SDK. To find the exact airport you probably need to do a query based on location but I'll try to dind a definitive answer.

-- Ben Morrison - 21 Sep 2005


Implementing ILayerEditor in .NET

Q) How do you implement the ILayerEditor in .NET? I have found examples on implementing the ILayerEditor via an ActiveX object using COM, but have not found any examples on implementing an ILayerEditor plugin using the .NET framework. Is this possible? If anyone has written a plugin to implement the ILayerEditor interface in .NET instead of, could you please provide some insight on how you did it?

A) See the sample attached below.

-- Paul Reisdorf - 13 Jan 2006


RouteEditor: Using Routesvr.dll

Q) I am having trouble using the GetInfo?() and SetInfo?() methods inside the CRouteServerClass?() in the Routesvr.dll. I get the error message "The server threw an exception" when I try. My goal is to programmatically add a new route to FalconView, so I am attempting to model the actions shown in RouteServer when a new route is added. In the function definition:

GetInfo( int clientID, ind msg_id, int param1, int param2, int param3, short mnem1, short mnem2, short mnem3, out object pvSafeArray)

I haven't been able to find what the 3 short mnem parameters are used for, so I just supply them with 0's. I'm not sure if that would be the problem or not... The only reference I have been able to find has been the RouteServer ICD v3.3.1. I was wondering if anyone had any suggestions or knew of any references that might help me.

A?) I don't mind you asking the question here (obviously many FalconView developers use the RouteServer) but I want to point out that the RouteServer is a TYBRIN component of PFPS so I don't know if any of the developers watch this wiki. If you don't get any feedback, I suggest you ask the TYBRIN developers on the eglin mission planning website (see GetTheSdk for pointers to get on the Web Site).


Track / Orbit Data

Q) Is there a way to get points from a track/orbit editor? I am using FalconView 3.3 and developing everything in C#. If so what interface should I use to implement it. Thank you in advance.

A) There is no way to get the data while the track is being edited but after it is saved, you can read the file. The track orbit editor stores its data in the same format as DAFIF, the specs should be in the PFPS ICD. I'll try to give you an exact pointer.

-- TWikiGuest - 23 Jan 2006


Recast returned Object in Managed C++

Q) How do you recast the returned "Object _gc *" from GetOverlayList? to be able to access the layer handles in Managed C++?

-- Mike Samsel - 29 Nov 2006

A) It is just about the same as "Passing COM Variants to .NET Object"

   result = m_pLayer->GetOverlayList(&layerNumbers,&NumOfLayers);

   //Unpack the array

   Array* MapHandles = (Array*)layerNumbers;

            
   for (i=0; i < NumOfLayers; i++)

       //Get value from the array and covert it to the correct type
       tempInt = Convert::ToInt32(MapHandles->GetValue(i)->ToString());
       m_pLayer->DeleteLayer(tempInt);

-- Mike Samsel - 29 Nov 2006


How do you implement !ICallback GetInfoText? in Managed C++?

Q) I can get callbacks for OnDoubleClicked? and other non-OnSelected kinds of callback but nothing associated with OnSelected? or MouseClicks?.

-- Mike Samsel - 29 Nov 2006


Trouble Exiting Falconview After Using ILayer

Q) I used the sample code from ILayerTester? to display lines on the Falconview Map. The code was added to a program I wrote in C# that generates lat/longs. Everything displays correctly, but when I exit Falconview I get a "FalconView application file has encountered a problem and needs to close. We are sorry for the inconvenience." message. I do not get the same message when using ILayerTester? by itself. What would cause FalconView to generate this message upon exit?

private void button2_Click(object sender, EventArgs e)

      mILayer = new fvw.LayerClass();

      System.Console.WriteLine("Got New Layer Object...");
      
      Callback = new ICallbackImpl();

      Int32 result = mILayer.RegisterWithMapServer("NetTester", (int)this.Handle, Callback);

      System.Console.WriteLine("Registered; result = " + result.ToString());

      LayerHandle = mILayer.CreateLayer("New C# Layer");
      LineHandle = mILayer.AddLine(LayerHandle, NewLat1, NewLong1, NewLat2, NewLong2, 0, 0);
      LineHandle = mILayer.AddEllipse(LayerHandle, NewLat1, NewLong1, 3, 3, 0);

The New Lat/Longs are the coordinates generated by other portions of the code.

-- Mike Walsh - 21 Dec 2006


Creating a Child Window in OnSelected?

Q) I am using C# and would like to create a Child Window of Falconview as a windows form during the callback of OnSelected?. My problem is that I have no idea how to use the windows handle to be the parent of the windows form. Does anyone know how to do this and have example code?

-- Mike Samsel - 26 Jan 2007

A) For a modal dialog use ShowDialog? which uses the currently active window as its owner. For a modeless dialog, you can obtain the current active window handle via the Windows API call GetActiveWindow?:

  [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]

public static extern IntPtr GetActiveWindow();


Debugging a C# Client Editor

Q) Has anyone had any problems running the debugger for a C# client editor? I am using VS 2003. I've tried turning on the debugging unmanaged code option in the project properties, but, arghh, it chokes every time. I normally develop with C++, so I could be my inexperience with C# being the main culprit here.

-- Stephen St John - 02 Feb 2007


Hello World Server Updated

I've updated the Hello World sample so that it releases COM objects. This is important to prevent memory corruption that happens when .NET tries to garbage collect COM objects that FalconView has already destroyed.

-- Joel Odom - 15 Jun 2007

I created a new C# example (more complicated than "Hello World" that implements a WmsOverlay. It properly cleans up the COM objects.

-- ChrisBailey - 13 Sep 2007


VS 2005 Clearing Layer Problem?

Q) I am plotting a lot of points on a layer and then attempting to clear the layer to redraw new points to reuse the layer. I have found that attempting to use multiple layers and switching between them for the effect of a dynamic display causes FalconView to become unresponsive (plotting 30-35000 points per layer). When i attempt to just reuse one layer by calling the layer.DeleteAllObjects method and reuse the layer for drawing, FalconView memory usage still keeps climbing on the layer re-use like the layer wasn't fully cleared. Is there a problem with the DeleteAllObjects? method. Recreating the layer isn't feasible as it takes to long for smooth layer changes and multiple layers of massive point data almost locks up FalconView. I am plotting changing radar data (weather patterns)

-- Matt Bird - 16 Jun 2007

Are you calling Refresh on the layer after you delete the objects? FalconView stores a list of invalidated objects so that it can optimize the invalidation region. This is why memory does not appear to be freed immediately after calling DeleteAllObjects?.

Yes, I have tried Refresh(-1) and also Refresh(theLayerHandle) with no success.

-- Matt Bird - 29 Jun 2007

I had the same problem as VS 2005 Compiler Problem. Under Protected it should read fvw::Layer* m_pLayer; fvw::Map* m_pMap;

and then for the Click method for each button it should read something like this.

this->Connect->Click += new System::EventHandler(this, &Sample_Managed_C::Form1::Connect_Click);

That should clear up the problem. It did for me anyways.

-- Andrew Paul - 26 Sep 2007


Problem drawing large polygon

I'm using out of process C# to control FV and am running into a problem drawing large polygons. FV will always crash if the poly has >10,000 points, and FV doesn't put anything in the error log file. Is there a limit to the poly's size?

System.Runtime.InteropServices.COMException (0x800706BE): The remote procedure call failed. (Exception from HRESULT: 0x800706BE) at RuntimeType?.ForwardCallToInvokeMember(String memberName, BindingFlags? flags, Object target, Int32[] aWrapperTypes, MessageData?& msgData) at fvw.LayerClass.AddPolygon(Int32 layer_handle, Object lat_lon_array, Int32 num_points)

-- Jeff - 22 Jan 2008


Problem with OnPreClose?

Q) When the overlay has been modified (ie, the overlay has setModified(true)), FalconView shows the overlay name followed by a * to indicate to the user that they might want to save. When FalconView closes, if this overlay has not been saved, FalconView calls the overlay callback OnPreClose?, passing in the layer handle and NULL in place of the integer variable cancel to indicate that the layer is being removed after this action. However, in C#, integer variables cannot be null. How do I handle this?

A)

  public void OnPreClose(int layer_handle, ref int cancel)
{
    try
    {
        cancel = 0;
        //cancel was not NULL - the layer will remain after this action
    }
    catch(NullReferenceException
    {
        //cancel was NULL - the layer will be closed immediately after this action
    }

-- Carl Cox - 21 Jul 2008


Printing .Net Overlays

Q) Why don't my .Net overlays print correctly?

A) .Net does not properly setup the Graphics object for FalconView's printing when the HDC is a printing DC. Given an IActiveMapProj, we can setup the Graphics correctly:

IGraphicsContext pGraphicsContext;
pActiveMapProj.GetGraphicsContext(out pGraphicsContext);
Graphics mapGraphics = Graphics.FromHdc(phdc);
bool isPrinting;
pGraphicsContext.IsPrinting(out isPrinting);
if (isPrinting)
{
    mapGraphics.PageUnit = GraphicsUnit.Pixel;//FalconView handles pixel to printer point translation
}

-- Carl Cox - 28 May 2009


  • GEO.cs Download: An Object oriented .NET wrapper for the DoD? GEO library.
  • Layer_EditorC.zip Download: This Layer Editor Sample was submitted to FalconView as a sample of C# code that demonstrates the use of both ICallback and ILayerEditor from managed code.

Top


You are here: DotNetDev > FVDev > WebHome

Attachments