Summary
I'm using C# .NET 4.0 Framework on 64 bit Windows 7 to write to the registry, and one of the values I write seems to change when I log off (or on, I can't tell), but only the first time I log off and back on.
Please help me understand what I'm missing.
Full Story
Before we begin, there are valid reasons to do this, so please don't tell me "AH!! NEVER DO THIS!!" I understand that in the general case, this is not something you want to do to someone's computer. This is a controlled, limited distribution bound for specific machines that run embedded systems.
With that caveat, I'm trying to programatically change the DPI to 96 and the window border width to very small. It seems I can do one or the other successfully, but doing them both stomps on each other.
For testing, I use the Control Panel tool shown in the screenshot below to modify the DPI to the wrong settings, then run my program, snippets shown below.
Here is the code:
Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics\\", "AppliedDPI", 0x60); // fix the DPI.
Microsoft.Win32.Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI", "LogPixels", 0x60);
Microsoft.Win32.Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware Profiles\\0000\\Software\\Fonts", "LogPixels", 0x60);
Microsoft.Win32.Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware Profiles\\0001\\Software\\Fonts", "LogPixels", 0x60);
Microsoft.Win32.Registry.SetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts", "LogPixels", 0x60);
Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop", "LogPixels", 0x60);
Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics\\", "BorderWidth", "-15"); // fix the border width.
Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics\\", "PaddedBorderWidth", "-15"); // fix the border width.
Now, in order for Windows 7 to actually apply these changes, I have to log off and back on. Prior to logging off, if I look in the registry, I see the values above all show up as I want them to. Once I log off and back on, PaddedBorderWidth has somehow become -60 instead of -15. I don't think it has to do with PaddedBorderWidth being the last in the list. I tried it first with the same results.
I think Windows 7 has some other Windows Theme thing that still has a hold on the window border width and is causing this on log on or log off. Once I log back on, if I run my C# program again, this time the setting sticks. Again this points me at a Windows Theme still holding on.
I don't know why nor how to stop this. Can someone point me in the right direction?
UPDATE
Experimentally I have determined that the border width changes only when I change "HKEY_CURRENT_USER\Control Panel\Desktop\LogPixels and then log off and back on. Unfortunately, this is one of the keys I really need to change. It seems that changing LogPixels triggers some sort of border width default. Any thoughts?
Again, I know this is a very non-standard thing to do, but such is life.
Workaround Update
I worked around this issue by creating a small executable that sets these registry values when run as an elevated user. In the help file, the user is told to run this if the GUI doesn't look right, then they must log off and back on. If it still doesn't look right, they have to do it again, at which point, the settings will finally stick.
While this "solves" the issue, it leaves me feeling extremely unsatisfied, as I feel there should be a nice, clean technical fix so the user never has to do this, but I'm out of time and have to ship. If anyone comes up with a better way, please speak up. I'd love to fix this for the next rev.
Hopefully sometime in the future we can just fix the GUI to be DPI-aware, but that's much easier to say than do with this legacy code.
Related
Here is my previous question, if you want some further information regarding my current problem:
WinForm: Inherited Panel wont Autosize
If you don't want to read through it, I'll give you some general information:
I'm not working directly via the programme, I'm just editing a specific DLL, that is used by this programme
That means, that I don't have any access to the source code of this specific programme
That also means that I have to fix this problem via some changes in the DLL, that is - as I mentioned before - used by this programme.
What I found out so far:
It works without any problems, if I attach the programme to the DLL's source code in VS2015.
But it has some glitches if I build the code and then copy the DLL into the programme's folder - that's also my actual problem: it somehow shrinks the tableLayoutpanel to half its actual size and I get some weird glitches in the other half of its actual, in normal start somehow not used, size.
What I tried out:
I changed the size manually, not via "Dock = Fill" or "Autosize = true" and it worked. But that's, as you all may know, not the best solution and we only want to use it, if there is absolutely no other way around it. No one likes to hard-code.
I tried to inherit its Parent's Size via:
this.tablelayoutPanel.Size = this.Size;
and
this.tableLayoutPanel.Size = new Size(this.Height, this.Size);
So do you guys have any ideas?
Okay, I did not figured out why the debuger worked and the release/debug build not. But I just forced a redraw on the tableLayoutPanelMainwith with Application.DoEvents(). I never tried this out before, because Invalidate() + Update() or Refresh() did not work - I was like: okay, that wont be that easy, so just forget about that.
But after some trial & error and a lot of time...well, I was working for two weeks on it...I tried the simpliest thing out and YEAHY, it worked!
Anyways, thank you for your help, guys. I appreciate that.
datagridview on vb.net is looking very wrong on xp, picture boxes inside the grid are not showing and if I change the width of a columns u see the lines marking on the screen until u refresh... only on windows xp.
This wasnt happening before on xp though, I did a lot of changes to code and when I later put them on a client with xp it showed.
I already tried going through what I changed but I couldn't figure it out. An older build of the application doesn't show this problem which means its definetly the change in the code.
I know I can remove the hardware acceleration and that would work, but I want to know what may cause this to happen codewise.
Below is two images the first from windows 7 and the second from xp... u can see what Im talking about
My question is: What usually causes something like this codewise?
I'm working on a WPF/.NET 4 app that lives in the system tray and periodically shows messages to the user.
I would like to have my NotifyIcon promoted from the overflow area of the system tray to the visible portion each time there is a message. This works fine if I call 'ShowBalloonTip' on my NotifyIcon; however, I don't wish to use the standard OS balloons (I have a custom control for this, which supports multiple instances and custom animations).
Is it possible? It doesn't seem to allow showing an empty/invisible balloon, and disposing/re-adding the icon does not have the intended effect. I wonder if I should look into creating a secondary tray icon each time I have a message (like the Outlook 'new mail' icon) and removing it when my message fades away.
This is not possible. A significant problem with the notification area is that every programmer thinks that his app is important enough to be next to the clock. Modesty is not a programmer's trait and that's a good thing.
The user however sets different priorities. He's liable to run more than three apps that all think they should have the exalted location. This got really out of hand, I've seen screenshots of Win98 machines where 75% of the taskbar was covered with Important Programs.
This was not sustainable and Microsoft did something about it. They added the overflow area to provide a home for notification icons that the user doesn't think are all that important. Being a computer user myself, it is very quickly populated with whatever shovelware icons come with a new machine I purchase. From there, the rate I uninstall this stuff is inversely proportional to the number of times it balloons me with completely useless or inscrutable info. The only ones that ever really survive are the ones that never show a balloon.
A core feature of the overflow area is that programs cannot do anything to elevate themselves back next to the clock. That would completely defeat the point of having it. Other than showing a balloon, the user needs to know where it came from. That better be something meaningful and relevant to the user. If it is not then your uninstaller is the part of your product that gets tested most.
You are a computer yourself and have battled annoying notify icons too. Apply the exact same logic to your own. And don't forget to ask somebody else what they think about yours. And if your notifications are useful enough, this just takes care of itself. Your user will move it back. Because that's what he can do.
I've got a problem that's driving me nuts. We have a C# project that has a few types of custom controls, but has several hundred instances of those controls (don't ask). Every time I do anything that requires compile I get the following behavior:
The project appears to build very quickly (like 3 or 4 seconds).
Then VS becomes totally unresponsive for quite a while (maybe 15 seconds to a minute)
The status at the bottom of the window shows "Build Succeeded" during the unresponsive period.
Clicking just about anything will cause a spinner to appear.
Eventually the spinner will go away and the status will show "Ready" at the bottom, at which point I'm back in business.
I'm almost certain that this is a self-inflicted problem, but for the life of me I can't figure out what is going on during the "spinning" period. Is there any way to see what's going on during the build process so that I can determine precisely how I'm shooting myself in the foot?
UPDATE: I tried a strange experiment. I created a new application using the exact same user controls and then just plopped down about 2,000 of them on my form. No problem at all, this application works fine. How incredibly odd...
Close the form design view before compiling the project.
If that did not work (which worked for me but not for you as you've mentioned in your comment) then I think it's something about your custom control like trying to connect to a server and validating it's licensing. Check your internet traffic with something like Wireshark. I hope that helps.
i want to write an application, which reads under windows xp the quick launch items in the order like they are located in the taskbar,
and sets hotkeys for each of these item.
windows + 1 should start the first application
windows + 2 the second, etc.
(like in windows 7)
all of these items are found i a folder, but if i read the items of this folder, i dont get the right order of these items.
i found two solutions the get the right order - first:
in the registry an entry is found, where its saved how they are located, but not in plain text. i dont know how to read this, and cant reverse engine it.
the second:
read via winapi the items tooltip from the taskbar, so i can (if there are not items with the same name) search via the name in the quick launch folder.
the quick launch bar is just a listview (syslistview32).
via sendmessage i got it work to count the items, and start one (faking a click on this item), but how the hell can i read the tooltip?
i have googled a lot, tried everything, but i didnt get it run.
i hope you have any snippets for me, to solve this problem.
cheers
Determining the order of the items in the Quick Launch toolbar programmatically is going to be inherently fragile. There's not an API exposed for this, which means that it's subject to change in future versions of Windows, breaking your code that relied on assumptions about undocumented implementation details.
However, this is less of a problem in this specific case than it normally would be, since the Quick Launch toolbar doesn't exist anymore (or, at least, no one uses it anymore). The last version of Windows that used the Quick Launch toolbar was Vista, so if you make sure that your code is compatible with Vista and earlier, you should be fine. It won't work with newer versions anyway.
The positions of items in the Quick Launch toolbar is stored in the Registry in the following key:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Streams\Desktop
You can extract the information from there, parse and interpret it, and then use it as you like. As you mention, this information isn't stored in plain text form because that would be very slow for the shell to load and parse itself. Since this is undocumented and not designed to be used by clients, they had no particular benefit in making it user (or developer) friendly. All that matters is what's most efficient for the shell, and storing the binary information from its internal structures is the obvious choice.
You will need to reverse engineer this in order for it to be useful to you. The way I'd go about it is probably by setting up a test environment with a couple of items in the Quick Launch bar in a particular order, exporting the information from the Registry, moving one of the items around, exporting the updated information from the Registry, and comparing the two exported Registry files to see what changed. Rinse and repeat as many times as necessary to deduce the pattern. (Really makes you wonder why so many developers actually do take the time to reverse-engineer undocumented aspects of Windows, doesn't it?)
The other option would be to use Spy++ to investigate the windows that implement the taskbar and its Quick Launch toolbar. I don't have a pre-Windows 7 system around, but it sounds like from the question that you've already done this and determined that the Quick Launch toolbar is implemented using a standard ListView. If you know the name of that window (and the names of its ancestor windows), you can walk through those windows to obtain a handle to the window you're interested in. And then you can determine the order of the items in the window as if it were a standard ListView in your own application.
The documentation for ListView controls is here; that should get you started in the right direction. You can get the text of one of the subitems by sending the LVM_GETITEMTEXT message.
This is probably the easier way of doing it. The same caveats apply--there is nothing keeping future versions of Windows from changing the names of those windows or the way that the taskbar is implemented, but since the only versions of Windows that have a Quick Launch toolbar have already been released (and therefore aren't likely to change), this may not be a big problem.
Then again, with the fact of the Quick Launch toolbar's obsolescence in mind, I struggle to comprehend why this endeavor is even worthy of investing developer time.
Also, even once you get this program all written and installed, consider what happens when the user adds a new item to the Quick Launch toolbar or re-arranges the existing items. How is your utility going to know that and adjust the keyboard shortcuts accordingly? What if an installer adds/removes an item from the Quick Launch toolbar?