Posted By: littleguru | Jun 27th, 2006 @ 12:17 PM
page 1 of 1
Comments: 19 | Views: 6414 | Downloads: 210
littleguru
littleguru
<3 Seattle
Another managed wrapper for a nice feature that is available since Windows XP but becoming more and more popular with Windows Vista.

In Vista and IE7 you get always a little text message in the search text boxes (when the text box hasn't the focus and no text has been entered) telling you what you could do by entering text.

In IE7 it's the name of the search engine: "MSN Search", "Google", whatever. In the Vista start menu you get a little text that says: "Start Search".

This text box control allows you to add that little text also to your text boxes. To use it in your application set the BannerText and BannerFont property to specify the text of the cue banner and the font.

I hope you enjoy my work.

Edit: Fixed bug with detecting Windows 2000 as supported OS.
The source code says:

        /// <summary>
        /// Returns whether the OS supports banner texts. It is fine if the application
        /// runs on XP or higher.
        /// </summary>
        private bool IsSupported
        {
            get { return (Environment.OSVersion.Version.Major >= 5); }
        }

However, this'll return true for Windows 2000. Windows 2000 is v5.0 and XP is v5.1, so you need to look at the minor component of the version as well.
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
It's not working here, I don't see the banner text (Windows XP Professional x64 Edition).

EDIT: And, checking the code, you've introduced a new bug. Now you do this:
  Version v = Environment.OSVersion.Version;
  return (v.Major >= 5 && v.Minor >= 1);

Unfortunately, now it would fail on Vista, because Vista's minor version is not >= 1.

You need to do "v.Major > 5 || (v.Major == 5 && v.Minor >= 1)"

EDIT2: Stepping through the code, the SendMessage call succeeds (it returns 1), but I still don't see the banner.
footballism
footballism
Another Paradigm Shift!
I think this check is more appropriate:
private Boolean IsSupported
        {
            get
            {
                Version currentVersion = Environment.OSVersion.Version;
                Version minVersion = new Version(5, 1);
                return currentVersion.CompareTo(minVersion) >= 0 ? true : false;
            }
        }

Sheva
footballism
footballism
Another Paradigm Shift!
littleguru wrote:
  Creating a new Version object is quite nice, but introduces a lot overhead that is not required...

I don't think instantiating a completely managed object like Version will cause any significant performance overhead, and I think that Sven's code is less readable in comaprison with mine, you know when choosing between readability with a non-trivial performance overhead and good performance but with poor readability, I will always choose the former.

Sheva
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
footballism wrote:

littleguru wrote:   Creating a new Version object is quite nice, but introduces a lot overhead that is not required...

I don't think instantiating a completely managed object like Version will cause any significant performance overhead, and I think that Sven's code is less readable in comaprison with mine.

I think this, like so many issues, is purely one of personal preference. I think both your and my version are equally readable, and yours does seem slightly more elegant. In this case, the performance difference is negligable.

However, I would like to comment on your use of the phrase "a completely managed object". Instantiating an object in a managed environment such as .Net incurs more overhead than doing so in one where memory is managed manually. If this had been C++, you could've allocated the Version instance on the stack, so its memory management would've been implicit with the stack scope. Even if not it's just a simple new and delete call. In .Net, the newly instantiated object needs to be tracked by the GC, flagged when no longer reachable, and collected in the next collection cycle, so there's far more overhead. This is why it's a very bad idea to instantiate objects in a tight loop (not that that's a very good idea in C++ either).
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
littleguru wrote:
To Sven: try to click the "Search" button. Is the cue banner showing up?

I just tried it on regular XP (non x64), and it still doesn't work.
eddwo
eddwo
Wheres my head at?
Simplest and and most readable of all.

private bool IsSupported
{
  get { return Environment.OSVersion.Version >= new Version(5,1);}
 }

I wouldn't worry about a single extra object with four ints. You are already creating two other objects in that expression, an OSVersion and a Version, what difference is one more Version object going to make? The GC likes things that are very short lived anyway.

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
littleguru wrote:
It is in the guidelines: don't create very short living objects. Sometimes you need to do it, but sometimes it is not required. In this case it is not required. You could create the instance as static member, that would help, but that means that you have always an object in memory.

It's still better to create a very short lived object like this than it would be to create an object that lives just long enough to get promoted to a higher generation and is then discarded.

littleguru wrote:
To Sven: creating instances in .NET takes less then creating them in C++, or even JAVA. I have read a few benchmarks about that. But you are right that the GC needs to track them, move them in the No-Longer-Reachable list, etc.

Yep, I know allocation is cheaper in .Net, but memory management for the entire lifetime of the object is more expensive, which is what I was getting at.
Daniel Moth
Daniel Moth
Developer

It is great to see so much content by this author inspired from other places on the web. I enjoy the wrappers to my posts... thanks!

http://www.danielmoth.com/Blog/2006/06/textbox-prompt.html

Daniel Moth
Daniel Moth
Developer

Hello Christian, thank you for your comment. I had downloaded the library you uploaded and had seen the reference.

This is a bit like the offline conversation we had about your glass example. I see you have emailed me privately a lengthier message so I have replied to you privately and am confident you will see the point there.

If you wish to bring the conversation back to the public, please let me know. Otherwise, I'll consider this resolved.

Keep up the nice work and good luck with your studies and summer work!

Cheers

Daniel

Sadly when using AutoCompleteCustomSource the cue text disappears. [C]
littleguru wrote:

Sven Groot wrote: It's still better to create a very short lived object like this than it would be to create an object that lives just long enough to get promoted to a higher generation and is then discarded.


Agreed.

Sven Groot wrote: Yep, I know allocation is cheaper in .Net, but memory management for the entire lifetime of the object is more expensive, which is what I was getting at.


Exactly. But I can't see why to create a Version object here... Internally it is then (when calling CompareTo or <=) using also the properties of the both version objects and compare them.


Hmmm... I'm not sure if the overhead even exists. I'm not exactly an expert on these, but I heard that .Net and Java JIT compiler optimizes codes. It might optimizes your code to 

private bool IsSupported
        {
            get { return true; }
        }

if you're running windows xp and above and false for other. Or even it may inlined the function altogether. AND it may optimizes both version the same way. However, I heard that it's better to write clear code that reflects what you intent exactly (this return Environment.OSVersion.Version >= new Version(5,1);} version might be the best option) so that the JIT compiler can infer what you're trying to do and it may get better chances of being optimized.

for an example, consider this fragment:

List<String> a = new List<String> ();
for ( int i = 0; i< 10; i++ ) {
   a.Clear();
   a.Add( i.ToString() );
   Debug.Write ( a [0] );
}

and

for ( int i = 0; i< 10; i++ ) {
   List<String> a = new List<String> ();
   a.Add ( i.ToString() );
   Debug.Write ( a[0] );
}

(Not a very good sample, I know... but thats what I can think of right now)
If you're writing in C++, the first version will be the prefered way, but I read that if you're writing in .Net and Java, the second version is the prefered way. Because the list object is more closer to where it is being used, enclosed in the same scope and have a better chance of being optimized. (Note that I avoided using String because it's immutable in Java and .Net, so no real effect)
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
punkouter wrote:

Hmmm... I'm not sure if the overhead even exists. I'm not exactly an expert on these, but I heard that .Net and Java JIT compiler optimizes codes. It might optimizes your code to 

private bool IsSupported
        {
            get { return true; }
        }



Sadly not. Reducing a statement like this requires inspection of the Version class (and the overloaded greater than operator), both of which are beyond the scope of the JIT compiler, whose primary purpose is to be fast. If any optimisation like this were to be imposed, it could only be done at compile time, at which point you cannot treat the Environment.Version as constant.

On the plus side, there are people like me working on compilers that do crazy things to make your code go faster - for example, a call to the IsSupported function would be inlined.

punkouter wrote:


However, I heard that it's better to write clear code that reflects what you intent exactly (this return Environment.OSVersion.Version >= new Version(5,1);} version might be the best option) so that the JIT compiler can infer what you're trying to do and it may get better chances of being optimized.



You're absolutely right! It's much more important for you to write good, maintainable code than it is for you to consider performance. It's up to the compiler developers (and to a lesser extent, the JIT) to optimise it.

For example, littleguru suggested above that (statement)? true : false was bad programming practise, and I would agree with him - it's harder to read and understand, but they will both compile to the same bytes, since the compiler automatically checks for well known programmer bugs such as the above.

Even Sven's problem of repeatably instantiating an object within a tight loop can be optimised if the constructor fulfills certain properties, and can be extracted to outside of the loop.

for an example, consider this fragment:

punkouter wrote:


List<String> a = new List<String> ();
for ( int i = 0; i< 10; i++ ) {
   a.Clear();
   a.Add( i.ToString() );
   Debug.Write ( a [0] );
}

and

for ( int i = 0; i< 10; i++ ) {
   List<String> a = new List<String> ();
   a.Add ( i.ToString() );
   Debug.Write ( a[0] );
}

(Not a very good sample, I know... but thats what I can think of right now)
If you're writing in C++, the first version will be the prefered way, but I read that if you're writing in .Net and Java, the second version is the prefered way. Because the list object is more closer to where it is being used, enclosed in the same scope and have a better chance of being optimized. (Note that I avoided using String because it's immutable in Java and .Net, so no real effect)


Actually in this case (which as you say isn't the best example) the first one is preferable in both cases. List<T> is difficult to optimise for a number of reasons, one of which being that it is completely different (although conceptually simmilar) to an array.

A better example would be:


string a = "";
for ( int i = 0; i< 10; i++ ) {
   a = i.ToString();
   Debug.Write ( a );
}

and

for ( int i = 0; i< 10; i++ ) {
   string a = "";
   a = i.ToString();
   Debug.Write ( a );
}


In this case, C++ would definitely prefer the first option, and C# developers would prefer the second option.

By the way, when you mention that strings are immutable, that doesn't mean that they can't be replaced or generated. It only means that constructing a string literal can be done "for free", and that string operations are slightly more expensive than you'd expect - (("Hello" + "World") + "!") + "!" takes longer than "Hello" + ("World" + ("!" + "!")) and these all take longer than String.Concat("Hello","World","!","!");
page 1 of 1
Comments: 19 | Views: 6414 | Downloads: 210
Microsoft Communities