ThinkGeo.com    |     Documentation    |     Premium Support

New ArgumentException with raster image layer

We are now getting the following exception intermittently with a Tiff image loaded in a RasterLayer. Most of the time it seems to work just fine. But when making edits that require full map reload, we get this maybe 5% of the time on this map. So far we have not reproduced it anywhere else except with this map running in the full product (I don’t have a reduced repro for you).

System.ArgumentException: Parameter is not valid.
   at System.Drawing.Bitmap..ctor(String filename)
   at ThinkGeo.MapSuite.Core.GdiPlusRasterSource.OpenCore()
   at ThinkGeo.MapSuite.Core.RasterSource.Open()
   at ThinkGeo.MapSuite.Core.RasterLayer.OpenCore()
   at ThinkGeo.MapSuite.Core.Layer.Open()
   at Toro.Client.Shared.Map.Core.StaticMap.GetBoundingBox(LayerOverlay layerOverlay) in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\Core\StaticMap.cs:line 697
   at Toro.Client.Shared.Map.Core.StaticMap.LoadStaticMap(String mapFilesPath) in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\Core\StaticMap.cs:line 270
   at Toro.Client.Shared.Map.LynxMapControl.ReloadStaticLayersCore() in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\LynxMapControl.cs:line 373
   at Toro.Client.Shared.Map.MapInterface.ReloadStaticLayersCore() in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\MapInterface.cs:line 327
   at Toro.Client.Shared.Map.MapInterface.ReloadStaticLayers() in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\MapInterface.cs:line 161
   at Toro.Client.Addin.AdvancedSetup.Map.MapStateManager.SaveStaticMapConfiguration() in D:\Toro\Archer\Solution\Client\Addins\AdvancedSetup\AdvancedSetupAddin\Map\MapStateManager.cs:line 160
   at Toro.Client.Addin.AdvancedSetup.Map.Tabs.GeneralSettings.btnCommit_Click(Object sender, EventArgs e) in D:\Toro\Archer\Solution\Client\Addins\AdvancedSetup\AdvancedSetupAddin\Map\Tabs\GeneralSettings.cs:line 43
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)

I can’t believe I did not notice it before, but if I catch it in the debugger, when it stops on my line for layer.Open (last line of ours in the call stack), I can see the exception, look inside your layer to verify the file path and such, nothing seems amiss with the TIF raster layer instance. But then if after stopping in the debugger, I simply run from there, the next time it will run without the exception.

Based on that, I’ll bet this is your code not correctly closing open file handles. And the argument exception should actually be an exception related to attempting to open a read locked file. If so, then this is likely related to one of my other complaints regarding your component opening and holding a lock on shape files even after they are flushed from map overlays. Your response there was basically “by design”, and that even though I didn’t explicitly open them, I should iterate and call close before flushing the overlay, which is a decision I still strongly disagree with. If I’m right, this code works most of the time only because there is so much going on that the finalizer runs in time before the reopen occurs. But sometimes it does not, and “boom!”

Ok, looks like I’m answering my own question.

I went back and added code to our product that is similar to what I was forced to add to the aforementioned prototype where I previously ran into a similar issue when the prototype tried to delete files that were nowhere in use and should not have been locked. More specifically, I modified our overlay.Clear to first iterate all layers testing “IsOpen” and Closing if true. It was terribly intermittent before, so it’s hard to be sure, but so far I can no longer reproduce this problem.

And this again underscores why I maintain that silently opening files behind the scenes and then keeping them locked (seemingly) forever unless the finalizer runs OR developers using your code somehow mystically determine that layers must be explicitly closed when cleared from an overlay to avoid intermittent timing based exceptions related to unexpectedly locked files. If you continue to claim this is desirable and “by design”, then I would ask, is this even documented anywhere other than my previous post in this forum? I certainly haven’t read everything you have available, but I certainly don’t recall seeing this in any documentation, not even in your samples (which appear to also rely on the finalizer). In summary, I believe most developers would stongly reject any code pattern that relies solely on the finalizer (or out of band knowledge to implement non-obvious defensive programming) to unlock/free resources.

Hi Russ,

Thanks for your post.

I don’t think this issue is caused by “lock”, because the GdiPlusRasterLayer is just for render data and don’t support edit data, in it’s open function, get image operation and get world file operation just call read permission, and in the close function, the only thing is dispose the generated image.

For ShapeFileFeatureLayer, you can also assign ShapeFileReadWriteMode.ReadOnly when initialize it.

About you mentioned the other problem, do you think the map need to dispose the layer and release source after it removed from map? I think if we don’t do that, because load data into memory take some cost, if user hadn’t manually close the layer, we think it perhaps will be added to map and used again, so we want to keep it’s status for save the cost if user open it again. I am not sure whether it’s the best solution, but thanks for let us know your thinking about it.

And for your exception, could you please let us know more your scenario?

Regards,

Don

Not sure what else to say. We were periodically getting that exception when flushing the map and reloading. Our map is rarely changed in the way the static portion is rendered, so that is how I chose to implement the re-render when the user changes something. Basically, it uses the same code used to initially load the map, so there is only one set of code to write/maintain involved with rendering, and no chance of getting something that looks different after next restart. As such, I could hit this exception pretty easily by simply repeatedly clicking the button that makes it reload so it can pick up any edited settings. When I began to suspect it might be as I described, and added the code to explicitly Close each layer when flushing the overlay to reload, the problem no longer manifests despite many subsequent reload clicks.

I did go back through he logs and find one manifestation that was a little different. Below is the lower portion of that call stack.

   System.NullReferenceException: Object reference not set to an instance of an object.
   at ThinkGeo.MapSuite.Core.GdiPlusRasterSource.GetImageWidthCore()
   at ThinkGeo.MapSuite.Core.GdiPlusRasterSource.GetBoundingBoxCore()
   at ThinkGeo.MapSuite.Core.RasterSource.GetBoundingBox()
   at ThinkGeo.MapSuite.Core.RasterLayer.GetBoundingBoxCore()
   at ThinkGeo.MapSuite.Core.Layer.GetBoundingBox()
   at Toro.Client.Shared.Map.Core.StaticMap.GetBoundingBox(LayerOverlay layerOverlay) in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\Core\StaticMap.cs:line 700
   at Toro.Client.Shared.Map.Core.StaticMap.LoadStaticMap(String mapFilesPath) in D:\Toro\Archer\Solution\Client\Shared\SharedMapPanel\Core\StaticMap.cs:line 270

Hi Russ,

It looks i missed an important point, in the top thread you mentioned your scenario is you will “making edits”, I want to make sure whether that means your app edit the image source(.tiff file) by some 3rd part tool on the fly?

If you edit the tiff and tfw file on the fly, I think you should want to close then open the raster layer. Because we will read some header information when read the image file and if you don’t call that again after the source modified, which should take unpredictable exception.

If I misunderstand the “making edits” please let me know. I am keeping test whether I can reproduce the issue local.

Regards,

Don

No problem. We do not ever edit the background files (of any time) in our product. It’s just one more layer the user can change. What I mean by making changes is that the user is adding/removing shape layer, changing the render details for existing layers, and/or adding objects in our dynamic layers.

Basically, this happens fairly infrequently, so to make life easier and share common code, when they do that, they have a “Commit” button that clears everything (all layers etc) from the map component and then runs the same code that would run on initial display. That “load the world” code processes our persistent store defining what to load (layers) in what order, and how to render them. This includes the background image (which may have changed, edited externally or just replaced).

Hi Russ,

Thanks for your detail description.

I think your workaround is good, because it looks this exception hard to reproduce in my end, I have reported that and our developer will notice this problem when they enhancement the RasterLayer.

If you found anything news about this please let us know, and any update about this problem we will update also.

Regards,

Don