GribApiDotNet / GribApi.NET

A powerful .NET library for reading and writing GRIB 1 and 2 files
Apache License 2.0
54 stars 28 forks source link

GribApi breaks when running under Windows Forms Application mode #22

Closed xavierpena closed 8 years ago

xavierpena commented 8 years ago

This API looks great and it is something I had been waiting for a while (reading gribs in .net is quite a nightmare). But I stumbled upon this bug that had me scratching my head for a while:

Apparently, in a Windows Forms Application the code breaks if it is called after Application.Run(new FormMain()); ... but not before, in this case it works like a charm (as it does under any case of Console Application mode).

Not many details are given, just this:

> Loaded 'Grib.Api.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
> The program '[11188] DbManager.vshost.exe' has exited with code 3 (0x3).

The line var gribMessages = new GribFile(filePath) works fine. The error comes when trying to iterate over each gribMessage. The application exits directly without throwing any exception.


Update:

The source of the error is the GribApiProxyPINVOKE.GribUtilSectionsCopy in this function of GribApiProxy.cs:

  public static GribHandle GribUtilSectionsCopy(GribHandle hfrom, GribHandle hto, int what, out int err) {
        System.IntPtr pVal = GribApiProxyPINVOKE.GribUtilSectionsCopy(hfrom.Reference, hto.Reference, what, out err);

        return pVal == System.IntPtr.Zero ? null : new GribHandle(pVal);
    }
0x1mason commented 8 years ago

Thanks for the report. I'm guessing this is thread related. Are you storing anythung between UI events? E.g., do you store the GribFile in a member variable and then read it when the user does something?

xavierpena commented 8 years ago

Are you storing anythung between UI events? E.g., do you store the GribFile in a member variable and then read it when the user does something?

No, I don't. I have made some more tests and I have found the pattern in which the problem appears (although have not found the real source of the problem, just the chain of events in which it appears).

The pattern seems almost unbelievable: the GribApi breaks if and only if I previously click on this function =>

        private void lnkSelectGribFile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {

            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Filter = "All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    var fileFullPath = openFileDialog.FileName;
                    this.txtGribFilePath.Text = fileFullPath;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Operation failed: " + ex.Message);
                }
            }

        }

This function was used in my Form to set the file path of the grib file, but for the tests the path was strongly typed inside the code in order to isolate the cause of the problem.

After clicking this function (or not, depending on the test), in both cases the Grib reader is invoked via "button click". As I mentioned: the read will work if the function above (called through a link label) has NOT been clicked before, and conversely it crashes it before clicking the button the link label had been called.

No fishy threads or Taks are involved, as far as I can see... I am really scratching my head trying to figure out what's going on.

0x1mason commented 8 years ago

Ok, I got it figured out. When you use the OpenFileDialog, it changes the current working directory and grib_api can't find definitions folder it needs.

Easiest fix I found is calling GribEnvironment.Init() at the entry point to your app. If that doesn't work set GribEnvironment.DefinitionsPath with an absolute path to the Grib.Api/definitions folder.

Let me know if this works. I'll improve either the docs or the code (probably both).

0x1mason commented 8 years ago

Looks like I've got it fixed for the next release.

xavierpena commented 8 years ago

Easiest fix I found is calling GribEnvironment.Init() at the entry point to your app.

This works like a charm, thank you!

I've got it fixed for the next release.

I'll use the GribEnvironment.Init() fix until the update of the nugget package is available.

And thanks again for the killer project, I was tired of dealing with the limitations of GribCS (specially being limited to x86). Kudos.

0x1mason commented 8 years ago

Thanks, delighted people are using it. Let me know if you have any suggestions for new features. I'm not using it anymore, so new features and fixes will have to be driven by request.