Jump to content
Sign in to follow this  
IBerg

Win32 API "Get Last Error"?

Recommended Posts

There are many functions in the Win32 API for which error information is supposed to be retrievable via "Get Last Error". Is this do-able from a LabVIEW block diagram?

Case Study:

I have been able to call into the Win32 API for "Locale" information in order to retrieve such infomation as "What is the user's region?" "What is the name of the local currency?" "Does this locale use metric?" "What is the name of the user's language setting in their own language? in English?" etc.

This was done by a simple wrapper VI to call "GetLocaleInfo" within "kernel32.dll" found in Windows\system32 ... well-documented on MSDN.

But as with many functions in the Win32 API, an incorrect call's error information is to be retrieved via a call to "Get Last Error"... which supposedly (from my understanding of the documentation for "Get Last Error" stores the error information placed there when a function being called uses "Set Last Error" to retrieve a numeric error code, which can then be passed to "Format Message" in order to retrieve a string describing the error. The documentation cautions that "Get Last Error" should be called "immediately" after a return value from a function call indicates that an error has occurred and that error information should be available. But when I try to do this from the block diagram, the GetLastError always seems to return 0, for the cases where I purposely make the inputs invalid (such as inputting TRUE for "return number" with an LCTYPE input beginning with S --- (only LCType inputs beginning with "I" are allowed to return numeric inputs).

:headbang:

To me this suggests that either LabVIEW itself makes another call to kernel32.dll (and/or other system dll's?) which succeeds, (thus clearing the error info) between the call to GetLocaleInfo and the call to GetLastError. Is this the best explanation everyone else has also? Has anyone come up with a work-around to help LabVIEW compile in such a way that these two calls occur more closely to one another so that the proper error information can be retrieved?

The VI submitted seems to work adequately if it is reasonable to assume there will not be an error, :)

but if LabVIEW could call GetLastError and have it work correctly, would this not make a lot of tasks easier to implement in pure G? :thumbup:

Maybe it is not worth worrying about, since one of the advantages of pure G ideally should be platform independance which has already been lost the minute we use a Win32 API. But on the other hand, while platform independance would be nice, to date my application has not been targeted to non-Windows NT-based platforms anyway. :wacko:

Or maybe someone else has used "Get Last Error" in another context in which it works like it should, providing a useful point of comparison?

Is it perhaps safe to say that the only solution to make a Win32 call with a GetLastError error output interface is to write a dll (or .NET assembly) in another language and call into that from LabVIEW?

Share this post


Link to post
Share on other sites
There are many functions in the Win32 API for which error information is supposed to be retrievable via "Get Last Error".  Is this do-able from a LabVIEW block diagram?

Been there, done that, never got the T-shirt ;-)

At one point, I did a lot of LV coding around the Windows API using the Call Library Node. In fact, much of it centered around the Windows locale functions. At the time, I was using the old SQL toolkit which manipulated database date/time values using an unavoidable interim conversion to string - and I was trying to avoid parsing failures if the user changed their date/time 'picture' to some alternative format. Is this close to what you're pursuing?

Anyway, I coded my CLNs with followup calls to the 'GetLastError' function, enforcing execution order with little single-frame-sequences, etc. I also experimented with whether or not the CLNs were marked threadsafe - you know, the orange vs. yellow thing - all in an effort to make the two calls happen more or less atomically, and (this is crucial) execute in the same thread .

Bottom line, after LV 6i, I think, or maybe it was 6.1, it seemed that the threading mechanism of LV changed, and I could never guarantee the results would be as desired, short of changing the INI file entries that control LV thread usage and seriously hobbling the application's efficiency.

The thread-management change was plainly observable when I wrote some VIs to determine thread- and-process-specific times (I was looking for a foolproof way for a LV subsystem to be able to determine what its CPU utilization was between elapsed calls to a VI which calculated thread times). I started getting inconsistent results and realized LV was calling the same code, on successive iterations, on different threads.

Hope sombody else has a better answer to this - I'd love to hear how they worked it out.

Best regards,

Dave

Share this post


Link to post
Share on other sites
Anyway, I coded my CLNs with followup calls to the 'GetLastError' function, enforcing execution order with little single-frame-sequences, etc.

Share this post


Link to post
Share on other sites
Thankyou a million for the encouragement! 

You're welcome, although I don't know that I provided any answers. You definitely need the dummy dataflow to at least make sure the two API calls happen in the specified order, though! I hadn't realized this was missing in your code, I'm sorry, I admit I hadn't downloaded your attachment. :(

I was interested in being able to look-up which character should be the default for a user according to their region setting after I modified my code to be able to control which character is used on input and output seperately. 

If you're not already aware, you should read up on LV's platform-independent features for comma vs. decimal-point localization. This can be found in the format specifiers help for Scan From String and Format Into String, you can programmatically specify the localization or let LV use the system defaults.

I also have added custom distance-unit rings throughout my application which can be toggled between metric, Imperial/English/U.S., or both modes. 

You can also apply physical units to LV floating-point numeric controls and indicators, and with the recent enhancements to LV, you can control these programmatically at runtime as well.

Best wishes,

Dave

Share this post


Link to post
Share on other sites

Isaak-

I took a quick look at your first attached LLB - I hadn't seen the GetLastError support VI from MGI before, although I am aware of David Moore/MGI, mostly through Info-LabVIEW. You should note that his VI calls GetLastError() through a Call Library Node that is not marked reentrant- which guarantees that you'll be getting GetLastError() results on the UI thread. This may be what you want, as long as all your other CLNs are set to run in the UI - which is the default.

Where I ran into problems was when I tried to set locale items, which are (if you believe MSDN documentation) globally inherited, but controlled on a per-thread basis. In the case of the SQL toolkit, I think my problem was that I could never guarantee that I was modifying the settings for the same thread that ended up handling the innards of the SQL toolkit, which called DLLs that NI had licensed from Intersolv/Merant.

I recall that LabVIEW in its recent versions, by default, creates something like four threads per execution system/priority combo. Though I also seem to recall that there are limitations on the UI execution system, that would tend to work in your favor if you're trying to ensure that GetLastError() reflects the WinAPI call you just made in the UI.

Enough rambling - back to work.

Dave

Share this post


Link to post
Share on other sites

Note: I have removed my earlier attachments on this topic ... thinking that those interested in "Get LocaleInfo" or an example where "GetLastError" has been made to work, or an example where a dll function specified to pass multiple types of pointers is successfully called from LabVIEW with different argument types in different places in the same block diagram (hmm wonder why I couldn't find an example like that in NI's example finder? :P ), would rather see the cleaned up version of what works rather than the somewhat messy version of what didn't work.

E-mail me if you really want to see the earlier attempts. (and consider getting psychological help :laugh: )

Download File:post-1165-1102611339.llb

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.