Wednesday, January 23, 2013

Encodings - what are they ?

At the very lowest level a string is represented as bunch of bytes.

In some programming languages that's about as sophisticated as it gets.

In most of the very early computers everything was "English" which eventually got standardized. This was known as ASCII, there is another known as EBCDIC but it's less common on PC's. In the very early days of digital computing, each byte represented one and only one character (as they only used 7 of the 8 bits) so there were bytes with values from 0-127 to make up a "string". Using ASCII, a value of 65 was used to indicate an "A", for example.

But not everyone reads and write English, so eventually computer vendors came up with "extended versions of ASCII" by using the 8th bit and adding in whole new sets of characters (from 128 to 255). These are referred to in several ways - code pages, extended ASCII and a few others.

But since there are thousands of languages and there are only 256 possible values for each byte you had to know which specific "extended ASCII" set was being used to determine what the extra characters were. This was the "encoding" for what has become known as single byte languages. And there are many of them.

Eventually, it was apparent that even all 256 possibilities could not represent some languages, for example Chinese, so new schemes were devised.

Over time these have evolved and a standard called Unicode was devised. Now there are several Unicode variations (UTF-8, UTF-16, UCS-2. UTF-32/UCS-4, etc) that can handle representing every "character" in every written language. However Unicode variations no longer use just single bytes to represent the various characters. UTF-8 for instance may use several successive bytes to represent one character.

All of this is essentially a long way of saying that you have to know the encoding of a bunch of bytes in order to get the correct string value from it. If you have a string of data that is encoded in UTF-8, but try to use it as if it were in ASCII encoding, you may find that some characters will not be what you expect.

So what does this mean for Real Studio developers? If you are creating and dealing with strings entirely from within your Real Studio apps, you have it easy. Everything is treated as UTF-8, which is a versatile and popular encoding. Perhaps one of the best things about UTF-8 is that you never have to worry about the byte order of the data (or endianness) across platforms. UTF-8 is always the same on every platform.

But problems can occur for you when you start to accept data from outside sources that should be treated as text, such as from databases, files, serial ports or the Internet.

There are two methods that are particularly helpful when dealing with text from outside sources: DefineEncoding and ConvertEncoding.

You use the DefineEncoding method to specifically state the encoding of the incoming text. This is how you tell your app to "interpret the following bunch of bytes as if it is this encoding". Of course, this means that you actually have to know the encoding of the incoming data so you can tell your app what it is. This code specifies that data in a MemoryBlock (perhaps that was read in using a BinaryStream) contains text using the UTF-16 encoding:

Dim myString As String
myString = DefineEncoding(MyMemoryBlock.StringValue(0,8), Encodings.UTF16 )

When you already have text in one encoding, but need to work with it in another encoding you use the ConvertEncoding method. For example, you may have a database that only works with UTF-16, so you want to convert text entered by the user to UTF-16 before you write it to the database:

Dim name As String = NameField.Text
name = ConvertEncoding(name, Encodings.UTF16)

The Encodings module includes an enumeration with dozens of common encodings predefined for you.

So make sure when you get data from outside of your applications that you know what encoding it is or that you have defined it before you being using it! 

Monday, January 14, 2013

WebSDK: Supporting User Applied WebStyles

One area of creating custom controls that developers often forget is dealing with user applied WebStyles. If your control will allow user defined styles, it is important that you add the correct attributes to your controls (if not, see the SDK docs for instructions on how to hide the Style property in your control).

User defined WebStyles are sent to the browser as class styles, so to initially render the correct style, you would add an attribute to your control's HTML tag:

dim tag as string
tag = "<div id=""" + self.controlid + """"

if not then
  tag = tag + " class=""" + + """"
end if

tag = tag + "></div>"

return tag

When a control has the default style, there is a method on the WebStyle class named IsDefaultStyle which will return true. In that case, you don't need to apply the style because it should match the style that was passed into SetupCSS.

In addition, users expect to have the ability to change styles at runtime. To support runtime changes, you should implement the FrameworkPropertyChanged event and check the style name like this:

Select Case Name
Case "Style"
  Dim st as WebStyle = WebStyle(value)
  If right(,8) <> "_default" then
    ExecuteJavascript("RS.addClass('" + me.controlid + "','" + + "');")
  End If
End Select

Lastly, if you want to support the case where a user removes a style at runtime (sets it to nil), you'll need to keep track of the last class name that was applied to your control. Add a property to your control:

Private Property mLastStyle as String = ""

Then add some code to the SetupHTML event:

dim tag as string
tag = "<div id=""" + self.ControlID + """"

if not then

  tag = tag + " class=""" + + """"
  mLastStyle =
end if

tag = tag + "></div>"
return tag

and some code to the FrameworkPropertyChanged event:

Select Case Name
Case "Style"
  Dim st as WebStyle = WebStyle(value)
  If not then
    ExecuteJavascript("RS.addClass('" + _
      me.controlid + "','" + + "');")
    mLastStyle =
    If mLastStyle<>nil then
      ExecuteJavascript("RS.removeClass('" + _
        me.controlid + "','" + mLastStyle + "');")
    End If
  End If
End Select

Now your control should work with user defined styles!

Friday, January 11, 2013

Making Choices in IDE Scripting

If you use IDE Scripting, you probably know that the Print() method shows a dialog containing your specified text and an OK button, but there are times when it would be nice to be able to make an interactive choice during script execution.

In Real Studio 2012r2, we introduced a new IDE Script method called ShowDialog which gives you the ability to create a MessageDialog with up to 3 buttons.

The method signature is:

   Message as String,
   Explanation as String,
   DefaultButtonCaption as String,
   [CancelButtonCaption as String,]
   [AltButtonCaption as String,]
   [Icon as Integer] ) As String

You may pass an empty string to any of the String properties if you want that item to be ignored. The Icon parameter uses the same values as the Icon property of the MessageDialog class.

Note: This method returns a String. The returned value will match the caption of the button that the user pressed.

WebSDK: Olark Web Widget - Part 5 - Wrapping Up

Welcome to Part 5 of this tutorial on converting the Olark notification widget into a Web control for use with Real Studio! If you haven't read Parts 1, 2, 3 & 4, I suggest you do so because we'll be building on the project from last time.

Today we're going to talk about making sure the widget persists while your user moves from WebPage to WebPage in your web app and some basic information about localizing for different languages.


Through all of the examples I've given so far, you have only used the Olark widget with a single WebPage. In most cases, when you use a widget like this, you want it to appear and stay visible while your user navigates through your website. While the widget we created in Part 1 would work perfectly for that, The events, methods and properties we implemented in parts 2-4 will all become inaccessible if you ever called WebPage1.close because the control itself would get removed from the session. Because of the construction of the control, it will persist, but you won't be able to interact with it any more.

There are a few ways to handle this. The simplest of all is to attach the widget to the initial page and never close it. If your initial page is a Login page, that's really simple and will take next to nothing in terms of memory.

The next way to do this is to create a blank loading page to which you would attach the Olark widget, set the App.DefaultWebPage property to the new page and then add code to the Shown event to show your initial page. The disadvantage to this is that if your main page is complicated, there may be a significant delay. You may want to add your own "loading" message.


With the recent addition of dynamic constants to our web framework, why not make it so developers can specify the messages they want displayed? The Olark website has a great blogpost which outlines the different configuration properties to use! Remember that any changes that use olark.configure must be put in the SetupJavascriptFramework event and can't be changed at runtime.

If you want to download a completed version of this project, you can get the project file here. If you want to see the different localizations (I used Google Translate for French, German and Spanish), just set the language code in the Session.Open event like this:

Self.LanguageCode = "de"


Self.LanguageCode = "fr"


Self.LanguageCode = "es"


The last thing we recommend doing for all developers using the WebSDK is to add a comment to any SDK related events that you haven't used. In this case the SetupHTML and SetupCSS events have no code in them, but if a developer using your control implemented one or both of these events weird things may happen. To avoid confusion, we ask that you add a simple comment to each unused SDK specific events so the end-developers don't see these events. A simple "//" will suffice.

Wrapping Up

So that's it! As you can see, translating a 3rd-Party control is not a terribly difficult thing to do, but you do need to spend some time learning the API and figuring out how much of it you want to implement. I strongly suggest that you do this in pieces and troubleshoot each section as you write your code. Make sure you save incremental versions of your controls as well, just in case!

If you're interested in seeing my version of the project, you can download it here.

I want to wish everyone good luck in creating and converting controls to our framework... we're looking forward to seeing what types of controls you make!

Thursday, January 10, 2013

WebSDK: Olark Web Widget - Part 4 - Setting Properties

Welcome to Part 4 of this tutorial on converting the Olark notification widget into a Web control for use with Real Studio! If you haven't read Parts 1, 2 & 3, I suggest you do so because we'll be building on the project from last time.

Width, Height and Visible Properties

By default, the Olark widget appears in the lower right corner of the browser window and has a size of 300x300 pixels. This works as long as there is nothing about your site that would be obscured in this position. Today we are going to set up some of the properties that allow you to change the initial appearance.

Because we have set this control to appear in the tray, the width and height properties are technically unused. Lets override their behavior for our purpose. We will also be overriding the Visible property to set the initial and runtime visibility of the widget.

First of all, the Olark API has two different methods for setting properties – one for setting properties at runtime and one for setting them before the control loads. The initial visibility, and the Width and Height need to be set as part of the configuration before the control loads so we need to set them as the library is loaded in the SetupJavascriptFramework event. Lets make a few changes:

dim c as string = code.ReplaceAll("<<SiteID>>",Trim(SiteID))

if not Visible then
  c = c + "olark.configure('box.start_hidden', true);"
end if

c = c + "olark.configure('box.width','" + str(width,"0") + "');"
c = c + "olark.configure('box.height','" + str(height,"0") + "');"

return c

Note: The Width and Height don't work with all themes.

In the FrameworkPropertyChanged event, let's add some code to intercept changes to the visibility property:

Select Case Name
  Case "visible"
    if ControlAvailableInBrowser then
      if value then
      end if
    end if

End Select

In the Shown event, we need to add a bit of code to set the initial hidden state, after the 4 EventIsImplemented calls:

if not Visible then
end if

Lastly, there is a property that can be used to set the initial position of the widget on the browser window named box.corner_position. Lets set that property up now.

1. Add a property to your control:

Position as Integer

2. Right-click on the property and select Property List Behavior.
3. Click the checkbox next to the Position property to make it visible in the IDE.
4. To make it a little easier to understand in the IDE,  we'll use an enum to set the value. Under Enumerations, change the popupmenu from None to Custom.
5. Create 4 entries:

0 = Bottom Right
1 = Bottom Left
2 = Top Right
3 = Top Left

6. Set the default value to 0.
7. Click OK.

Now let's add the code to the SetupJavascriptFramework event:

Add the code in red to the event: 

dim c as string = code.ReplaceAll("<<SiteID>>",Trim(SiteID))

if not Visible then
  c = c + "olark.configure('box.start_hidden', true);"
end if

c = c + "olark.configure('box.width','" + str(width,"0") + "');"
c = c + "olark.configure('box.height','" + str(height,"0") + "');"

dim positions as String = "BR,BL,TR,TL"
c = c + "olark.configure('box.corner_position','" + _
  NthField(positions,",",position+1) + "');"

return c

Note: Like the Width and Height properties, not all of the box position values are supported with all themes. The holiday theme (the one with the Santa hat) only works in the Bottom Left and Bottom Right positions. You can change the theme of your Olark widget from your control panel at

Now when a developer wants to change the position of the Olark widget, they can simply choose the descriptive name of the position.

Phew! There's a lot going on there! Our control is almost complete. Next time we will be making it so this control will stay visible even if your user changes pages, but also make it possible to keep receiving the events!

Wednesday, January 9, 2013

WebSDK: Olark Web Widget - Part 3 - Exposing Methods

Welcome to Part 3 of this tutorial on converting the Olark notification widget into a Web control for use with Real Studio! If you haven't read Part 1 & Part 2, I suggest you do so because we'll be building on the project from last time.


Last time, we hooked up four events so that when they fire on the browser, the corresponding events fire in the Real Studio application. If you look at the API page ( there are a bunch of methods that can be called (ten as of this writing, with six more in beta). Today we're going to create server side methods so developers can can Show, Hide, Expand or Collapse the widget themselves.

Allowing users to call methods in JavaScript is as easy as calling the ExecuteJavascript method. Before we implement each of the methods, lets write a hidden method that will do the heavy lifting for us:

Add a method to your control:

Private Sub CallOlarkMethod(Name as String)
  ExecuteJavascript("olark('" + Name + "');")
End Sub

Now we can add each of the methods:

Public Sub Expand()
End Sub

Public Sub Collapse()
End Sub

Public Sub Show()
End Sub

Public Sub Hide()
End Sub

Two notes about the code above:

1. You'll notice that I used Collapse instead of Shrink. Collapse is more consistent with the rest of the Realbasic API, and in the events, I would have had to name one "Shrunk" which really doesn't translate very well to other languages :)

2. Show. This is a tricky one. Technically I've overridden the already existing method for showing a control. The issue is that with a traditional non-visual control, Show means nothing anyway. We're simply going to use that to our advantage here.

Go back to WebPage1 and add 4 buttons, one each for Expand, Collapse, Show and Hide, and have them call the new methods. When you run the project, you'll see that you can now make the widget appear, disappear, expand and collapse from code!

Next time we're going to talk about setting some properties to control the initial appearance of the widget.

Tuesday, January 8, 2013

WebSDK: Olark Web Widget - Part 2 - Events

Welcome to Part 2 of this tutorial on converting the Olark notification widget into a Web control for use with Real Studio! If you haven't read Part 1, I suggest you do so because we'll be building on the project from last time.


Now that we have a control that works, we're going to hook up some of the basic events that are available. As of this writing there are only ten of which we will be hooking up four: Expand, Shrink, Show and Hide.

First, let's prepare the class for receiving events from the page:

Add four event definitions, one for each event. These will be the events that your user implements at design time.



Notice that we duplicated the Hidden and Shown events. We're going to override the behavior of these events to reflect the events from the widget instead of the web control instance itself. Since we want to be able to raise those events from code, we need a new event definition.

Because we've created a duplicate Hidden event and there's already an unimplemented event named Hidden that we're not going to use, the compiler will complain if you try to build right now. In the Hidden event of the control, simply add a comment like this:

//These are not the droids you are looking for...

Now that we have the events, we need to add some code to fire them when an event comes in from the browser. Go to the ExecuteEvent event and add the following code:

Select Case Name
Case "oExpand"
  RaiseEvent Expanded

Case "oCollapse"
  RaiseEvent Collapsed

Case "oShow"
  RaiseEvent Shown

Case "oHide"
  RaiseEvent Hidden

Case Else
  Return False

End Select

Return True

So you're probably wondering why I prefixed each of the incoming event names with "o". The reason is avoid a conflict with the existing Show and Hide events for the control! I also used shortened names because every byte that you send from the browser takes time. Not a lot of time, but it does add up, and for most mobile users that have data plans, every byte costs money!

Now that we have the infrastructure in place, we can tell the browser to listen for the events. Before we do that though, lets talk a little more about bandwidth. As I mentioned above, when designing controls, bandwidth should be foremost on your mind. One area that developers often forget about is the fact that some events may not be implemented by users at all. Sending event data from the browser in this case is an outright waste! We'll use the EventIsImplemented method to check at runtime whether or not there's actually code in an event. Back to the tutorial!

In the Shown event, we'll tell the browser to listen for the Olark events as specified in the Olark API:

If EventIsImplemented(GetTypeInfo(OlarkWidget), "Expanded") Then
ExecuteJavascript("olark('', " + _
  "function() { RS.triggerServerEvent('" + Self.ControlID + _
  "','oExpand', [] ) } )")
End If

If EventIsImplemented(GetTypeInfo(OlarkWidget), "Collapsed") Then
ExecuteJavascript("olark('', " + _
  "function() { RS.triggerServerEvent('" + Self.ControlID + _
  "','oCollapse', [] ) } )")
End If

If EventIsImplemented(GetTypeInfo(OlarkWidget), "Shown") Then
ExecuteJavascript("olark('', " + _
  "function() { RS.triggerServerEvent('" + Self.ControlID + _
  "','oShow', [] ) } )")
End If

If EventIsImplemented(GetTypeInfo(OlarkWidget), "Hidden") Then
ExecuteJavascript("olark('', " + _
  "function() { RS.triggerServerEvent('" + Self.ControlID + _
  "','oHide', [] ) } )")
End If

Now go to WebPage1, add a WebListBox to the page and add this code to each of the new events:

Listbox1.InsertRow 0,CurrentMethodName

This listbox is simply for testing purposes to allow us to see that each of the events is firing when we want it to.

Save and Run the project! The Shown event should fire fairly soon after the page loads, and the Expanded and Collapsed events should fire as the user expands, shrinks or closes the control (if the theme1 has a close control).

We've come a long way, but the Olark API still has a lot of configurability available through properties and methods.

Next time we'll look at some methods that trigger the behavior whose events we've implemented today.

1) The theme of the Olark widget is determined by settings in your Olark account.

Monday, January 7, 2013

iOS6 Mobile Safari Web Applications - Redux

This blogpost was accidentally deleted a little while ago, but it has been recreated here in response to popular demand!

Sept 9, 2012

As many of you begin upgrading your iPhones, iPads and iPods to iOS 6 over the next couple of days, you may find that a lot of AJAX web apps (not just ours, but also others created with other tools that output HTML, CSS and Javascript) no longer run very well. Symptoms include: missing images, unresponsive interfaces, random disconnects, etc.

Many Web Apps created today use a technique called long-polling to download commands from the server to the browser. This means that, at any given time, there needs to be at least two connections to the same server, one for uploads and one for downloads. 

With iOS6, it appears that the number of allowed concurrent connections per server has been lowered to one.  Being a common practice for these types of web apps, this means that any web application that uses this technique may be affected.

We have filed a bug report with Apple and as of today, its status is "Critical Bug".

As a workaround, users can use Google's Chrome browser for iOS to access your apps.

November 1, 2012 - Update

With the release of Real Studio 2012r1.2, we have a partial fix for this bug. While server originated events are still not working, projects that only use user triggered events work just fine now.

December 4, 2012 - Update

With the release of Real Studio 2012r2, mobile Safari on iOS now uses the HTML5 EventSource events to get updates from Real Studio web apps. There is a major advantage to this new technology...the browser can change the poll rate based on user activity and network conditions which leads to better battery life. As an added bonus, this also allows the browser to hide the loading indicator!

WebSDK: Olark Web Widget - Part 1 - Getting Started

It seems like every day I'm getting questions about how to convert this or that to a web control using the new WebSDK. Over the next five days, I'll walk you through the process of creating an Olark web live chat widget. Today's post is all about getting the widget to appear in your project.


First of all, if you don't already have one, go to the Olark website and sign up for a free account. After you sign in, they will provide you with a piece of javascript code and a Site ID. I suggest copying each of these to the text editor of your choice. It is probably worth having the API documentation open in a browser as well: Whenever converting a control, it is extremely important that you spend a little time familiarizing yourself with the API and the examples provided.

In preparation for creating the control, look at the javascript that you just copied. You'll notice that the SiteID that was provided for you exists in several places in the code. If you leave it this way, anyone who uses this control will use your account (and their tech support chats will likely come to you!). Lets fix that. Copy the SiteID into your clipboard and do a search & replace on the javascript code. Change all instances of the SiteID on the clipboard (looks something like 0000-000-00-000) to <<SiteID>>.

The last piece of the prep stage requires that you think ahead a little. We'll be sending this code to the browser as part of the SetupJavascriptFramework event. This event expects you to return raw Javascript code with no <script> tags around it. If you look at the provided code, not only does it contain a <script> tag, but there is also a <noscript> tag. Remove everything up to and including the first <script> tag (and its attributes) as well as everything from the </script> tag to the end of the script (including the whole <noscript> section and the trailing comment).

Creating the Widget

Next, launch Real Studio 2012r2 and create a new Web project.
  1. Create a new class called OlarkWidget with the Super set to WebControlWrapper
  2. Open the OlarkWidget class and add a constant to specify the control's javascript namespace. Replace "example" with your own namespace. If you haven't registered a namespace with us, please see the excerpt from the WebSDK docs at the end of this article, for information about doing that.
    Private Const JavascriptNamespace as String = "example.olark"
  3. Add a second constant to make the control appear in the tray instead of on the page:
    Private Const ShowInTrayArea As Boolean = True
  4. Add a third constant for the javascript code, and paste in the javascript code we prepared above:
    Private Const Code As String
  5. Add a SiteID property so users can set it in the IDE at design time:
    Public Property SiteID as String
  6. Implement the SetupJavascriptFramework event. Notice that we're inserting the user supplied SiteID.
    Return Code.ReplaceAll("<<SiteID>>",Trim(SiteID))
  7. Lastly, right-click on the SiteID property and select Property List Behavior. In this dialog, set the Width and Height default values to 32 (otherwise it'll look a little weird when you drag the control in) and check the box next to the SiteID property to make it visible in the WebPage editor. You can add a header by right-clicking in the property list and choosing "Add Header".

Using the Widget

Now go to WebPage1 and drag an instance of OlarkWidget to the page. It should automatically appear in the tray and if you select it, you'll notice that the SiteID property is visible. Copy and paste your SiteID into that field.

If you run the project, soon after the page loads, the default Olark widget should appear on the bottom right corner of the browser!

Next time we'll hook up some basic events!

How to Register a Javascript Namespace

Real Software is maintaining a Javascript namespace registry to help developers avoid namespace conflicts.  Developers may register a root namespace for use with all of their controls. Using the examples above, the registered namespace would be “Acme”. From then on, you would be permitted to create:
  • Acme.Button
  • Acme.Listbox
  • Acme.SourceList
This does NOT permit you to use AcmeControls or AcmeProducts without creating a separate namespace registration.
To request a root namespace registration, send an email to and tell us what root namespace you would like to use. You will receive an email from us confirming your namespace choice. 
Namespaces will be registered on a first come first served basis. We reserve the right to deny a namespace request that infringes on the trademarks of another company or would be otherwise confusing or offensive.

Thursday, January 3, 2013

Are User Conferences Worth it?

Attending a conference of any kind can be an expensive proposition. There's the cost of the conference itself along with hotel and airfare and finally just the time away from work. You can easily end up spending $1500 or more. Apple charges that just for a pass to their developer conference. So attending is not something to consider lightly. Having said that, there are a lot of great reasons to go as well.

Long before I founded Real Software, I was a software developer using other development tools. I regularly attended conferences and seminars. I was in California and most of those that I attended happened to be in California as well which made it easier. At first I wasn't sure if going would be worth it. I would look over the session descriptions and there were always many that I found interesting but were they worth the cost and the time? Couldn't I obtain this knowledge elsewhere for less? In some cases perhaps, but in others I couldn't. Session descriptions rarely adequately describe the value of the session and almost always end up being worth it.

But the most valuable part of attending a conference I found was something not described (or at least not sufficiently described) in the conference marketing materials: networking and interacting with fellow developers. Spending a few days with others that use the same tools I was using was always extremely valuable. Talking to the developers that actually created the tools was great too. I better understood why things worked the way they did and often picked up pointers that I wouldn't have discovered any other way. Discussions with other users about how they use tools, the kinds of software they create, etc., were always far more valuable than I had thought they would be.

Seminars and conferences can also be valuable if you are just considering using a particular development tool. When NeXT was gearing up to start selling their new computer, I went to a seminar to check out the tools they intended to provided, talk to the people from NeXT and see what other developers like me thought.

Now that I run a development tools company, we of course have our own conference which will take place this April in Orlando, Florida. For me, some of the reasons I attend our conference are of course different than the reasons I attended conferences in the past. But the most important reason has not changed: talking to other users. Those in-person, one-on-one and group discussions with Real Studio users are terrific. It's not just being able to put a face with a name. It's getting to know these developers and understand them better. To hear what they are doing with Real Studio and why they do it, is extraordinarily valuable and there's just no other way get it.

In this amazing world of technology in which we live, there's really nothing that can replace face-to-face. With all the time we devote to our tools, the cost of a conference continues to be well-worth the value.

Picture courtesy of  Thomas Tempelmann

Wednesday, January 2, 2013

Format, CStr and the Web

Since this issue keeps coming up, and the reason isn't terribly obvious in all cases, I want to point out a subtle problem with numbers when dealing with web projects.

If you are at all familiar with the Format and CStr commands, you know that they convert a number into a string using the localization of the computer that they are running on. For example:

Dim s as String = Format(1.23,"0.00")

// United States, s = "1.23"
// Europe, s = "1,23"

The same goes for CStr.

There are two issues with this when dealing with the web:

1. Remember that the code that runs these methods is on the server! The localization information is not pulled from the individual browsers, so you'll need to take that into account when displaying numbers.

2. If you're sending JavaScript commands to the browser that include numbers, like if you're using our WebSDK, JavaScript requires numbers to be in the U.S. English format (using "." as the decimal separator).

To get around this, there is a special version of the Str command that applies the same kind of format string, but does not apply the region format. Using the example from above:

Dim s as String = Str(1.23,"0.00")

// United States: s = "1.23"
// Europe: s = "1.23"