Weird number casting issues when running GH_RhinoScriptInterface object

Hi,

I am facing a weird issue when runnning GH in automated mode from an external program (by using GH_RhinoScriptInterface, as explained here :

Some components sitting inside the GH_Document are raising number casting exceptions like “Expression generated an error : string 1.5 cannot be cast to double” (seriously???) When this definition runs manually, everything works fine.

My guess is that it comes from a Culture specific problem : in French (my computer language is set to French despite Rhino+GH are in English)., “1.5” is written “1,5”. So, I guess somehow, Grasshopper switches to French because it finds somewhere that the caller thread is French. I set the calling software thread to be “en-US” but it didn’t change anything.

How can I force GH to switch to English and forget about French forever (which sucks for programming anyway) ?

I have little hope that someone has ever seen this issue before though :sleepy:

Thanks!

There’s a method in Grasshopper that fixes the UI thread culture, but that is not accessible from the script interface. Would be nice to know whether the parsing really does fail because of the culture settings. It sounds like a plausible explanation, and I can’t think of a better one (or even another one), but we need to figure out a way to test this.

This file runs a C# script which copies the current thread culture into the clipboard. Can you test invoking a gh file which contains this script object?

CultureTest.gh (5.6 KB)

Thanks David, actually your component doesn’t work when running via COM, I get an exception saying " current thread should be STA “Single Threaded Apartment” before any OLE call can be made". I tried to decorate the client program with a STAThread attribute but didn’t change anything. I keep digging.

I am now 90% sure all this mess comes from a culture issue : the exception is actually in French! Furthermore, on my previous script, only Function Evaluator Components were crashing. I narrowed the problem down to the GH_ExpressionParser and, surprise, I get an exception which is half English, half French :slight_smile:

Expression generated an error for (-variables-): La conversion de la chaîne “2.5” en type ‘Double’ n’est pas valide. – which means string 2.5 couldn’t be cast to double)

So, when you rethrow the exception, it is actually showing that the inner exception was actually in French.

My guess is that when the Rhino COM Component is created by the application, it takes a thread from the pool (or from wherever COM initializes) regardless of the current culture of the client. Since the OS culture is in French, it kind of overrides GH setting.

So, now I need to figure out how to change this either from the COM side, either from GH itself. Is the UI Thread Culture changer method documented? I found a CultureTable property in GH_Convert class but it states “do not touch it unless you know what you are doing”. And I don’t.

Cheers

That’s for converting culture data types, not for setting thread cultures.

The method I use to force the Grasshopper UI thread into Invariant is Grasshopper.Instances.EnforceInvariantCulture. But it does nothing more than:

  Public Shared Sub EnforceInvariantCulture()
    If (Not Settings.GetValue("Culture:Invariant", True)) Then Return

    Dim T As Thread = Thread.CurrentThread
    T.CurrentCulture = CultureInfo.InvariantCulture
  End Sub
1 Like

Great! I just placed a small script component doing this into the doc and it actually forced the thread back to the invariant culture. Exceptions appear when the document is opened at first but whenever the script has run, everything goes back to normal.

Many many thanks David! :smile:

1 Like

If you put the script component at the bottom of the display stack Ctrl+B a few times. It’ll be the first one to solve, it may make it work even for the first time.

Ok, Ctrl+B is said to be a shortcut for ‘Put to Back’, is that related to the way GH expire and solve components when a new solution is triggerered?

Related yes, identical no. The order in which components are solved is initially the same as the order in which they are drawn, however if a component has sources then it will solve those first. But since the C# component has no sources, if it is put at the bottom of the display stack it will also be the first object that gets solved.