28 Aug 2016 @ 1:08 AM 

As anybody knows, there can be a lot of incorrect information on the internet. Internet “Just so” stories can spread like wildfire if they are believable and explain something neatly. One of those “just so” stories involves older game consoles and computers; over time, we find that our once-white and gray plastics on old systems like Apple II’s, NES consoles, SNES consoles, and so on change colour; they change from white or gray to yellow, and over time that yellow darkens, sometimes even turning brown.

This phenomena is “explained” here . Or is it? Does what is stated there about the process reflect reality? Does it make chemical sense? To the layman or casual observer- hey, it makes sense. Bromine IS brown, after all, it’s added to the plastic. But is there a chemical basis and support for it? What reactions actually take place?

“RetroBright”- which is basically just Hydrogen peroxide – is commonly recommended to “reverse” the effects. The reason I care about the actual chemical properties is because the yellowing itself goin g away isn’t an indication that everything is back to how it was. Colour changes can be the result of all sorts of things. More importantly, if we learn the actual chemical processes involved, perhaps we can come up with alternative approaches.

Basically, the story put forth in the article is a rather commonly repeated myth- a Chemical “just-so” story of sorts- “Bromine is brown so that must be it” Is the extent of the intellectual discussion regarding chemistry, more or less. Generally though there isn’t much drive to look further into it- it all makes sense to the layman on the surface, or even one with rather standard chemistry knowledge. But when you look deeper than the surface of the concept- you see that the commonly held belief that Brominated Flame Retardants are responsible doesn’t seem to hold up.

First we can start with the first inaccuracy in that link- Bromine is not added as a flame retardant- that is flat out, categorically and completely wrong, and trivially easy to refute. Bromine compounds are added as flame retardants, But as they are compounds, the colour of elemental Bromine (brown) is irrelevant, because elemental Bromine is not added to the plastic. Specifically, chemicals like Tetrabromobisphenol A. (C15H12Br4O2).

The article also says that “The problem is that bromine undergoes a reaction when exposed to ultraviolet (UV) radiation” But Bromine doesn’t photo-oxidize. It doesn’t even react with anything in the air on it’s own; creating Bromine dioxide either involves exposing it to Ozone at very low temperatures alongside trichlorofluoromethane, alternatively, gaseous bromine can be made to react with oxygen by passing a current through it. Neither of these seem like they take place in a Super Nintendo. Not to mention elemental bromine is brown, so if it was in the plastic, oxidization would change it from the brown of elemental bromine to the yellow of bromine dioxide.

Back to what IS in the plastic, though- Tetrabromobisphenol A is not photosensitive; it won’t react with oxygen in the air due to UV light exposure, and the bromine cannot be “freed” from the compound and made elemental through some coincidence in a typical environment. It is simply not the cause of the yellowing; (it will yellow without BFR’s as well, which sort of indicates it’s probably not involved).

The Yellowing is inherent to ABS plastics, because it is the ABS plastic itself that is photo-oxidative. On exposure to UV light (or heat, which is why it can happen with systems stored in attics for example), the butadiene portion of the polymer chain will react with oxygen and form carbonyl-b. That compound is brown. There’s your culprit right there. Retrobright works because thsoe carbonyls react with hydrogen peroxide, and create another compound which is colourless. but the butadiene portion of the polymer remains weak- oxalic acid is thought to be one possible way to reverse the original reaction.

So why does it sometimes not affect certain parts of the plastic or certain systems? here the “just so” story is a bit closer to reality- the “story” is that the plastic formulae has different amounts of brominated flame retardants, This is probably true, but as that compound isn’t photo-reactive or involved in the chemical process, it’s not what matters here. What causes the difference is a variance in a different part of the formulae- the UV stabiliser.

UV Stabilisers are added to pretty much All ABS plastic intentionally to try to offset the butadiene reaction and the yellowing effect the resulting carbonyl has. They absorb UV light and dissipate it as infrared wavelength energy which doesn’t catalyze a reaction in the butadiene. Less UV Stabilizer means more UV gets to the Butadiene and causes a reaction and the plastic yellows more quickly. more UV stabilizer means less UV catalyzes reactions and the plastic takes longer to change colour.

As with anything related to this- the best way is to experiment. I’ve decided to pick up some supplies and test both approaches on a single piece of plastic. some standard “retrobright” mixture using hydrogen peroxide, and a variation using oxalic acid. I can apply both to the same piece of yellowed plastic, and observe the results. Are both effective at removing the yellowing color? what happens longer term? It should be an interesting experiment.

Posted By: BC_Programming
Last Edit: 28 Aug 2016 @ 01:08 AM

EmailPermalinkComments (0)
Tags

 24 Aug 2016 @ 10:32 PM 

User Account Control, or UAC, was a feature introduced to Windows in Windows Vista. With earlier versions of Windows, the default user accounts had full administrative privileges, which meant that any program you launched also had full administrator privileges. The introduction of UAC was an attempt to solve the various issues with running Windows under a Limited User Account to make the more advanced security features of Windows far more accessible to the average user. The effective idea was that when you logged in your security token, which was effectively “given” to any software you launched, would be stripped of admin privileges. In order for a process to get the full token, it would require consent, this consent was implemented via the UAC dialog, allowing users to decide whether or not to give or deny that full security token.

It was a feature that was not well received; users complained that Vista was restricting them, and making them ask for permission for everything- something of a misinterpretation of the feature and how it works, but an understandable one somewhat. Nowadays, it is practically a staple of Windows, being present in the default user accounts through 7, 8, and now 10. Even so, it has had some design changes over the years.

One interesting aspect of the UAC consent dialog is that it will differentiate between a “Verified”, or signed, executable, and an unsigned one, displaying slightly different designs based on the evaluation of the executable. A signed executable effectively includes a digital signature which is able to verify that the program has not been altered by a third party- so if you trust the certificate authority as well as the publisher, it should be safe.

Windows Vista

We start our tour, perhaps unsurprisingly, with Vista.

Vista_Verified

Vista UAC Dialog, shown for an executable with a verified signature.

Vista_Verified_expanded

Vista UAC Dialog, shown for an executable with a verified signature, after expanding the Details option.

When the executable is verified, we see a relatively straightforward request. Expanding the dialog, as shown in the second image, provides access to the application path; There is no way, within the UAC dialog, to inspect the publisher’s certificate- that needs to be checked via other means.

Interestingly, once we start looking at unverified executables, however, we see quite a different presentation:

Vista_Unverified

Windows Vista UAC Dialog displayed for a Unverified executable.

Vista_Unverified_expanded

Windows Vista UAC Dialog shown for an unverified executable, after expanding the details option.

Rather than the more subdued appearance as seen when the application is verified, the dialog displayed for an unverified application is more bold; the options are presented as TaskDialog buttons, and the entire dialog has a very “Task Dialog” feel; additionally, the colour scheme uses a more bold yellow. Interestingly, Expanding the “Details” really only adds in the file location to the upper information region. Kind of an odd choice, particularly since the UAC dialog will usually be on it’s own secure desktop and thus screen real-estate is not as valuable as it might otherwise be.

Windows 7

On Vista, elevation tended to be required more frequently and thus UAC dialogs were rather common for standard Windows operations. Users needed to give consent for many standard Windows tasks such as adjusting Windows settings. Windows 7 adjusted some of the default behaviour and it does not by default present consent dialogs for many built-in Windows operations. The design of the UAC dialog also was adjusted slightly:

Win7_Verified

Windows 7 UAC dialog on a verified/signed executable.

Win7_Verified_Expanded

Windows 7 UAC dialog on a verified executable, expanded.

For verified executables, the dialog is rather unchanged; The biggest changes we see are in the title copy “Windows needs your permission to continue” changes to an ask regarding whether the user gives permission to a particular program. The dialog now includes a hyperlink in the lower-right that takes you right to the UAC settings, and publisher certificate information is now available when the details are expanded.

Win7_Unverified

Windows 7 UAC Dialog for an unverified Program.

Win7_unverified_expanded

Windows 7 UAC dialog for an unverified program, expanded

The Unverified dialog is quite a departure from the Vista version. It takes it’s design largely from the “Signed” version of the same dialog; perhaps for consistency. It dumps the “TaskDialog” style presentation of the options, instead using standard Dialog buttons, as with the “Signed” Appearance.

 

Windows 8

Win8_Unverified

UAC dialog on Windows 8 for an unverified executable.

Win8_Unverified_expanded

UAC Dialog on Windows 8 for an unverified executable, expanded.

Win8_Verified

UAC Dialog on Windows 8 for a Verified executable.

Win8_Verified_Expanded

UAC Dialog on Windows 8 for a Verified executable, Expanded.

 

 

For the sake of completeness, I’ve presented the same dialogs as seen on Windows 8. There have been no changes that I can see since Windows 7, excepting of course that the Win8 Windows Decorator is different.

Windows 10

Win10_Nov_Unverified

UAC Dialog from the Windows 10 November Update, running an Unverified executable.

Win10_Nov_Unverified_Expanded

UAC Dialog from the Windows 10 November Update, running an unverified executable, showing details.

Win10_Nov_Verified

UAC Dialog running a Verified executable on the Windows 10 November Update.

Win10_Nov_Verified_Expanded

UAC Dialog from the Windows 10 November Update, running a Verified executable, showing Details.

 

Yet again, included for completeness, the UAC dialogs shown by Windows 10 in the November Update. These are again identical to the Windows 8 and Windows 7 version of the same, providing the same information.

 

This all leads into the reason I made this post- the Anniversary Update to Windows 10 modified the appearance of the User Account Control dialogs to better fit with UWP standards:

 

Win10_Anniversary_Unverified

Windows 10 Anniversary Update UAC dialog for an Unverified Executable.

Win10_Anniversary_Unverified_expanded

Windows 10 Anniversary Update UAC dialog for an unverified Executable, after pressing “Show Details”.

Win10_Anniversary_Verified

Windows 10 Anniversary Update UAC Dialog for a Verified application.

Win10_Anniversary_Verified_Expanded

Windows 10 Anniversary Update UAC Dialog for a Verified Application, after pressing Show Details.

 

As we can see, the Windows 10 Anniversary Update significantly revised the UAC dialog. It appears that the intent was to better integrate the “Modern” User Interface aesthetic present in Windows 10. However, as we can see, the result is a bit of a mess; the hyperlink to display certificate information appears for unverified executables, but in that case, clicking it literally does nothing. The information is presented as a jumble of information with no text alignment, whereas previously the fields were well defined and laid out. I’m of the mind that updating the dialog to UWP should have brought forward more elements from the original, particularly the information layout; The “Details” hyperlink in particular should be more clearly designated as an expander, since as it is it violates both Win32 and UWP Platform UI guidelines regarding Link Label controls. I find it unfortunate that parsing the information presented in the dialog has been made more difficult than it was previously, and hope that future updates can iterate on this design to not only meet the usability of the previous version, but exceed it.

 

 

 

 

Posted By: BC_Programming
Last Edit: 24 Aug 2016 @ 10:35 PM

EmailPermalinkComments (0)
Tags

 03 Aug 2016 @ 4:37 PM 

I wrote previously , where I found that the Group Policy added to the insider build of Windows 10 did not have any observable effect.

This is merely a quick note as I re-tested on the recently released Anniversary Update, and with the group policy set in addition to the new “longPathAware” manifest setting, Functions like CreateDirectoryW do in fact allow access to long path names beyond MAX_PATH without the special prefix. Basically, the group policy is now active.

Of course, with the standard .NET File API, This has no effect, as the .NET File API does it’s own checks that restrict the path length.

Posted By: BC_Programming
Last Edit: 03 Aug 2016 @ 04:37 PM

EmailPermalinkComments (0)
Tags
Categories: .NET, C#

 02 Aug 2016 @ 1:27 PM 

Sometimes you hear people say you should never use black. But you should like always use it. Look at the sky? is that black? No, because of the Earth’s Atmosphere. What about if you go outside the atmosphere? Is that black? No, because of the stars and reflected light on dust. But what if you are in a completely opaque location? Then it’s black. You know what’s completely opaque? That’s right- a Woman’s Uterus. So You should use Black to evoke when people were a fetus and before they were born, It’s a symbolic colour that represents life.

Posted By: BC_Programming
Last Edit: 02 Aug 2016 @ 01:27 PM

EmailPermalinkComments (0)
Tags
Tags: , ,
Categories: Nonsense

 01 Aug 2016 @ 12:40 PM 

I like to have control over when and if my system(s) perform Update tasks. As a result, I’ve configured Windows 10 Pro via Group Policy to the option to notify that updates are available, but wait for me to install them.

For the most part, this works exactly as it did with Windows 7 and 8.1. With Win10 I sometimes get a only mildly intrusive notification which doesn’t prevent anything and just tells me  there are updates. That’s fine by me.

However, it would appear Microsoft is not in any way fine with this. At intervals, My entire screen darkens, and a single, small dialog appears stating that “Important Updates are Available”. This dialog presents one option- “Get Updates”. Pressing the button or escape has the same effect; it opens the “Windows Update” options in settings. I can only presume it tries to force the update to take place but cannot proceed because of the Group Policy settings.

This notification angers me unreasonably for some reason, though after mentally telling it off I’ve usually forgotten about it. What spurred me to look into it and try to do something about it was that I had the sheer audacity this evening to watch a movie. Right in the middle of the movie, suddenly I get the “Important updates are available” notification. It’s crossed the line and now it must die permanently.

One “rebuttal” of sorts I’ve seen to resistance to run Windows Update is that this problem can be avoided by just running it as soon as it wants to run. Aside from not wanting to wait a good 30 minutes to use my PC again, none of the updates it deems so are even important. There’s a flash player update (I’ll address this later) There’s a Windows Update which addresses a problem when a Windows 8 PC is upgraded to Windows 10, where Manufacturer bloatware is disappointingly removed, and an update to the servicing stack which applies to the creation of ISO media for Win10. “Important”? Hardly. And even if they were “important”- important to whom? If I am in the middle of, say, a work skype meeting, or I’m currently remoted in to fix a database issue on a customer server, why are the updates for my local system somehow more  important than me being productive ? Fact is they are not. The FUD surrounding Windows Updates and how we should just lay down and let Microsoft handle everything for us, how we should be Happy- not annoyed- when we find our systems rebooted overnight and thus we have to re-open all our work in progress again and find out what we were doing.

Anyway enough ranting! Thankfully as noted the Group Policy generally works as intended, just with that one annoying caveat. Can we eliminate that full-screen Prompt telling us there are important updates and instructing us that we must install them like we are some sort of child?

The first obvious place was Group Policy Editor. For example, is there a setting “Present full-screen dialog to interrupt user and tell them about important updates”? No, nothing similar either. Well, so much for that approach. After some investigation,l I found that the notification itself is basically just Windows launching “MusNotification.exe” and/or “musnotificationUI.exe”, presumably at times of it’s own choosing for wholly undocumented reasons and triggers. Whenever it feels like it I guess, or Maybe once a day. Who knows. Anyway, This suggested to me that replacing those files with a do-nothing stub program might solve the problem. However, I’m sure the issue would be “fixed” in a later update- in that those files would return. So I decided to take a batch file approach. If I update later and Win10 reverts the behaviour- such as with the anniversary update- I’ll be able to run the batch file to hopefully get it back to the way I want.

I created a do-nothing stub program by basically compiling the Visual Studio default template. (And removing the window creation of course) The files in C:\Windows\System32 are set as owned by TrustedInstaller, so it was necessary to take ownership of the files, then give full control on the files to administrators. I then renamed the originals and copied the stub into their place. The  batch file I ended up creating to do this looks like this.

 

  1. takeown /f %SYSTEMROOT%\System32\Musnotification.exe
  2. takeown /f %SYSTEMROOT%\System32\MusnotificationUX.exe
  3. icacls %SYSTEMROOT%\System32\Musnotification.exe /grant Administrators:(F)
  4. icacls %SYSTEMROOT%\System32\MusnotificationUX.exe /grant Administrators:(F)
  5. rename %SYSTEMROOT%\System32\MusNotification.exe musold.exe
  6. rename %SYSTEMROOT%\System32\MusNotificationUX.exe musoldUX.exe
  7. copy stubcs.exe C:\Windows\System32\MusNotification.exe
  8. copy stubcs.exe C:\Windows\System32\MusNotificationUX.exe

I went ahead and put this in the same directory alongside the stub program. It appears to work as intended,  though given how sporadic the original “full screen takeover” behaviour was it will be some time before I’m sufficiently convinced it has worked as intended. I’ve put this on a flash drive so I can run it on my various Windows 10 systems (excepting the one system I have running preview builds).

I mentioned  I’d talk about Flash as well. As it happens, Windows 10 apparently includes Adobe Flash Player, which was news to me. Aside from the updates failing to install anyway, I really do NOT want Adobe Flash on my system(s) in any, way, shape, or form. I was able to do something similar with it- in this case, Adobe Flash installs to the directory “C:\Windows\Syswow64\Macromed”. So I adjusted my batch file to take ownership of that folder, set security to full control on the folder, and delete it, adding these to the end of said file:

  1. takeown /F "%SYSTEMROOT%\SysWow64\macromed" /R /A
  2. icacls  "%SYSTEMROOT%\SysWow64\macromed" /grant everyone:(F)
  3. rmdir /s /y "%SYSTEMROOT%\SysWow64\macromed"

After doing that, I hid the Flash Player update using this troubleshooter . Unfortunately I suspect future updates will attempt to reinstall Flash. Best case scenario is to create the folder and deny TrustedInstaller access to it, so it cannot install the updates, but of course this will cause the update to fail all the time and may cause problems with Windows Update until it’s hidden anyway.

Posted By: BC_Programming
Last Edit: 08 Aug 2016 @ 06:47 PM

EmailPermalinkComments (0)
Tags
Tags: ,
Categories: Windows

 13 Jul 2016 @ 5:02 AM 

Previously , I wrote about my Unicomp Ultra Classic keyboard and my experiences with it. As it happens, that keyboard no longer works; The issues I mention there ended up resulting in the keyboard failing outright; it would no longer connect to the system and my attempts to repair the keyboard resulted in it getting worse. I ended up replacing it with a new one (going for a Black case this time around). Unfortunately, that keyboard eventually started to see the same symptoms, and it appears that it is the result of the same design failure. I couldn’t really expect much else. It may be the case that other models than the Ultra Classic itself did not suffer from these design issues, however I couldn’t justifying buying a third keyboard from them given my experiences, and particularly given the lack of user-servicability to the keyboards, with rather consumer-hostile properties such as using melted plastic to hold together parts of the keyboard as well as double-sided tape.

This left me in a bit of a spot, though. Unicomp is, after all, the only way to get a buckling spring keyboard, and I had grown rather fond of the Typing experience afforded by such a keyboard. Alternative keyboards didn’t use Buckling Spring, with most of them instead opting for something like a Cherry MX switch.

After a bit of hemming and hawwing about the decision, I ended up deciding on a Corsair K70 keyboard with Cherry MX Brown keyswitches. I’m typing on it right now and it works well enough. I still prefer the typing experience of the buckling spring, but a keyboard that actually works reliably comes out on top regardless of any other differences, as far as I’m concerned. It’s also nice to have Media keys again, as that is one capability I actually missed going from my Microsoft Wired 500 to the Unicomp Keyboard.

The backlighting feature is interesting, and the backlight programmability is, well, actually it’s kind of funny, to be honest. Kind of a bit overboard arguably. I have it configured to change the Color when I press a key and fade back to the original colour, with different sections set to different colours, for no particular reason.

I have found the software slightly lacking, in particular, I find that when it is running for some time, it has a serious resource or memory leak that exhibits itself in the program being rather unusable. Restarting the program fixes this, but it’s still a rather odd issue given the program has to run in the background for the custom backlighting setup to work.

I haven’t taken it apart, of course, however it doesn’t appear that doing so is particularly difficult; unlike the Unicomp keyboard it would probably be possible to actually put it back together, that’s a plus, and not having to take it aparet to fix a design flaw related to lacking any strain relief is a nice bonus too.

Posted By: BC_Programming
Last Edit: 13 Jul 2016 @ 05:02 AM

EmailPermalinkComments (0)
Tags
Categories: General Computing

 28 Jun 2016 @ 12:14 AM 

13528937_552711404912444_1600866348616493512_n

In the image, we see a lot of claims about history. Let’s start from each one.

In 1891, you didn’t need permission from the government to…

1. Go fishing or hunting

Fishing and hunting licenses date back to the 16th century. Their use expanded heavily after the “Great chain of being” theory regarding natural life fell out of favour. Under that concept, it would be impossible to damage ecosystems or animal populations so there was no reason to regulate it. Once that fell out of favour (likely pushed forward by several ecosystem extinctions made people go, “huh, maybe we have this a tad wrong here mates?”) it became necessary to regulate Fishing and Hunting in order to preserve those animal populations.

2.Build a home or renovate it

Building permits were required for many renovations and construction long before 1891, with most cities incorporating bylaws and regulations regarding new construction to prevent city planning problems.

3.Get married

Marriage Licenses in North America Date back to the 1600’s, with most states and provinces having marriage licenses by the 1700’s. They serve as an official record of marriage.

4.use a transportation vehicle

This is correct- you did not need a license to drive in 1891. Of course, part of this may be related to the fact that there were less than 100 cars on the road in 1891, given the automobile had only recently been invented. Countries slowly introduced regulations- perhaps ironically given these sorts of image macros, after public outcry because unregulate vehicle traffic was causing fatal accidents with horse drawn carriages and pedestrians, because the drivers didn’t know what they were doing.

Driving a car requires a license because you need to prove that you aren’t going to kill people. Even with licenses, it doesn’t prevent it, but at least it gives legal recourse to get dangerous drivers off the road. Anybody suggesting that it is some sort of fundamental right to control a ton of steel hurtling down the road is insane.

6.become a tradesmen

“guilds” date back to the middle-ages, so this is just outright nonsense. Back then, being in a guild meant you had some minimum level of competency- otherwise you wouldn’t be accepted or would be kicked out. Modern Licenses and certifications serve the same purpose without the heraldry. These certifications and licenses to practice trades are why your house isn’t falling apart or using drywall for a load-bearing wall.

7. Ask permission to protest or reddress the Government

1891, coincidentally, was the year of the New Orleans Massacre, in which a District Attorney headed a mob to kill 11 Italians who had protested his work. Or 100 years earlier where 15 protesters were killed and several hundred others were wounded when government cavalry charged an otherwise peaceful protest in Manchester. Oh- by the by, the former case was written about in newspapers and it was suggested that perhaps the same actions could be taken against other unwanted minorities… Sounds pretty familiar.

Fundamentally this is just gibberish; it has no basis in fact and reads like a sovereign citizen manifesto. It’s some idiot waxing nostalgic over little house on the prairie without even a basic understanding of the time period.

have your income illegally taxed

The 16th amendment to the U.S constitution WAS ratified on February 3, 1913.

Posted By: BC_Programming
Last Edit: 28 Jun 2016 @ 12:14 AM

EmailPermalinkComments (0)
Tags
Categories: Programming

 27 May 2016 @ 8:04 PM 

Edit: 06/17/2016: I’ve gotten a few comments that for some reason mention “Long Path Tool”. I’m not clear why that is the case. Any posts mentioning Long Path tool as an “Alternative” or because you were “encountering the same problem” will be treated as spam. In the meantime, I’ll continue to use the Search Program I wrote almost a decade ago in Visual Basic 6 to delete files that are beyond the MAX_PATH limit (it uses my BCFile library which has the ability to support long path names).

 

Starting in Windows 10 Build 14352, a new Group Policy has appeared, “Enable NTFS Long Paths”. This setting is found under Administrative Templates\System\File System\NTFS:
NTFS Long Paths gpedit setting

This setting relates to the somewhat ubiquitous 260 character path limit. But what exact is the limit, how did it come about, and how has it persisted to this day in such a way that, as the setting itself requires, programs need to explicitly declare that they can handle them?

First, the initial origin. This limitation actually dates to MS-DOS, and originates with Interrupt 21h with 47h in the high byte of the accumulator register. This function was defined as “returns the path description without the drive letter and the initial backslash”. the 256 byte path excluded the drive letter and backslash (as noted) and didn’t use a null terminator. Adding the path and appropriate null terminator brings the maximum buffersize for a full directory path specification to 260 bytes.

Windows 3.1, and Windows 3.x more or less stuck with these same limitations, being mostly built over top of MS-DOS. With the introduction of the Unicode API, it was decided that Windows ought to allow for longer paths, particularly as File Systems such as NTFS were being developed that did away with many of those DOS-Derived limitations. So with those NT functions, the Unicode version of file functions could accept a \\?\ prefix at the front of the path string. This specified to the function to enable support for longer path names, up to the NTFS maximum of 32768. The requirement for \\?\ was added to allow older programs that weren’t compatible to continue to function; since they would not send the \\?\ prefix, they would continue to work as before.

However, as it happened, it turned out that this hasn’t been a particularly good solution. It wasn’t well popularized that File API calls should include such prefixes, and furthermore Microsoft’s own, built-in software didn’t even use it properly. Programs such as Windows Explorer don’t send the prefix string; and the .NET File API doesn’t support Unicode long path names either.

To demonstrate this difference, I’ve constructed a crude example in C#. It builds a long path that is 500+ characters long, then attempts to create it using the .NET API, and then using CreateDirectoryW:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace longnametest
  10. {
  11.     class Program
  12.     {
  13.         //Native methods.
  14.          [DllImport("kernel32.dll",CharSet=CharSet.Unicode)]
  15.          [return: MarshalAs(UnmanagedType.Bool)]
  16.         static extern bool CreateDirectory(string lpPathName,
  17.         IntPtr lpSecurityAttributes);
  18.  
  19.  
  20.         static void Main(string []  args)
  21.         {
  22.             String ProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
  23.             //attempt to create a 500+ long path.
  24.             while(ProfilePath.Length < 500)
  25.             {
  26.                 ProfilePath = Path.Combine(ProfilePath, "long");
  27.             }
  28.             Console.WriteLine("Constructed Path of length " + ProfilePath.Length);
  29.  
  30.             Console.WriteLine("Attempting to create path using Directory.Create…");
  31.             try {
  32.                 Directory.CreateDirectory(ProfilePath);
  33.             }
  34.             catch(Exception exx)
  35.             {
  36.                 Console.WriteLine("Exception attempting to use Directory.Create:" + exx.ToString());
  37.             }
  38.  
  39.             Console.WriteLine("Using CreateDirectoryW…");
  40.  
  41.             String []  PathParts = ProfilePath.Split(Path.DirectorySeparatorChar);
  42.  
  43.             String CreateDir = Path.Combine(PathParts [0]  + Path.DirectorySeparatorChar, PathParts [1] ,PathParts [2] ,PathParts [3] );
  44.              
  45.             for(int i=3;i<PathParts.Length;i++)
  46.             {
  47.                 if(!CreateDirectory("\\\\?\\" + CreateDir, IntPtr.Zero))
  48.                 {
  49.                     int lastError = Marshal.GetLastWin32Error();
  50.                     if (lastError != 183)
  51.                     {
  52.                         Console.WriteLine("CreateDirectory Failure…" + lastError);
  53.                         break;
  54.                     }      
  55.                 }
  56.                 CreateDir = Path.Combine(CreateDir, PathParts [i] );
  57.             }
  58.  
  59.  
  60.             Console.ReadKey();
  61.         }
  62.     }
  63. }

This gives output similar to the following. Note that this is the case on earlier Windows versions as well, going back to XP:

 Constructed Path of length 501
Attempting to create path using Directory.Create...
Exception attempting to use Directory.Create:System.IO.PathTooLongException: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
   at System.IO.PathHelper.GetFullPathName()
   at System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
   at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
   at System.IO.Path.GetFullPathInternal(String path)
   at System.IO.Directory.InternalCreateDirectoryHelper(String path, Boolean checkHost)
   at System.IO.Directory.CreateDirectory(String path)
   at longnametest.Program.Main(String []  args) in c:\users\michael\documents\visual studio 2015\Projects\longnametest\longnametest\Program.cs:line 32
Using CreateDirectoryW... 

What happened? the .NET Function failed when it saw the path would be too long and gave up. CreateDirectoryW however was able to create the full path length. I was able to verify it’s length because neither Command Prompt nor Windows Explorer are able to enter it. Interestingly, on Windows 10, this is the case regardless of if the Group Policy is Enabled or not.

Now, my current suspicion is that the feature will enable the functionality of \\?\ from those unicode functions without \\?\ being specified. In this case, this likely means that the internal .NET functions will still not function with longer path names, as the .NET File API is currently stopping it from going any further; it is checking the path length and going “Nope, won’t work, I give up” and throwing an exception. If my assertion is correct, however, it means that CreateDirectoryW will work as it does now if I remove the \\?\ prefix text if I add the appropriate manifest declaration to the program.

Which, naturally, led me to the next question- what exactly needs to be added to the manifest? First, I dumped the manifest from explorer.exe, hoping it perhaps declared support (which I was skeptical of given that I wasn’t able to browse the folders that were created as part of the test code). The Windows 10 Explorer.exe from build 14352 current has the following information from SysInternals sigcheck:

 c:\windows\explorer.exe:
	Verified:	Signed
	Signing date:	n/a
	Publisher:	Microsoft Windows
	Description:	Windows Explorer
	Product:	Microsoft® Windows® Operating System
	Prod version:	10.0.14352.1002
	File version:	10.0.14352.1002 (rs1_release.160522-1930)
	MachineType:	64-bit
	Manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<!--
    This is the manifest file only for Explorer.
    It only differs from windowsshell.manifest in the <dpiAware> tag.
-->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    name="Microsoft.Windows.Shell.explorer"
    processorArchitecture="amd64"
    version="5.1.0.0"
    type="win32"/>
<description>Windows Shell</description>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="*"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
        </requestedPrivileges>
    </security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">Explorer</dpiAware>
    </windowsSettings>
</application>
</assembly>
 

Well, no clues there. Dang. I tried paving my own roadway here, but can’t identify what xml namespace the app manifest would refer to nor the actual setting; I tried <longPaths> “ntfsLongPaths” and a few other permutations; however it may be the case that the xml namespace has not been published and this feature simply hasn’t been documented. The group policy setting may even be a placeholder in this build, given built-in Windows applications currently possess no support for it’s manifested capabilities. (Note that with the setting enabled, without a manifest, using CreateDirectoryW without the prefix results in an error once it goes beyond 260 characters).

This is a topic I will certainly revisit once more information on how we can utilize this feature comes to light. However, as it is, it doesn’t seem terribly useful. The big use here will be if Windows’ built-in software is written to support the policy setting. At any rate, I intend to update this posting when new information is available about this feature and how it can be used by developers. as well as it’s effect on the software.

Update 1:

Windows 10 does NOT display a correct error message when deleting a folder created in the manner above; When I attempted to delete the folder created above that is longer than MAX_PATH, I receive the following error dialog:

Incorrect Error

It claims that the source file names are larger than is supported by the file system. There are a few issues with that sort of error. I’m not copying files, so there is no “Source” or “Destination”; more importantly, the file system is NTFS and the fact that it currently contains the files I’m trying to delete seems to be presentable as evidence that the file system does, in fact, fully support the file path length.

These are the sorts of misleading error messages that have plagued Windows because of this MAX_PATH limitation for decades. Whether  this group policy- which isn’t enabled by default to begin with- is some sort of lead-in to a wider solution to this problem and to solve misleading and straight-up incorrect error messages like the above will be interesting to see.

Update 2

Allegedly , the setting in the manifest is “longPathAware”. However, I’ve yet to identify different behaviour when adding such a node to a manifest. The example program above is unable to use CreateDirectoryW and construct the 600+ Character path; it still requires the special prefix string. I’m looking through “Strings” output to verify that longPathAware is likely the manifest name.

I’ve found a RtlIsLongPathAwareProcessByManifest function as well as a direct reference to the string longPathAware which seems to indicate that is the correct manifest element. I found it references the schema http://schemas.microsoft.com/SMI/2016/WindowsSettings, which I wasn’t using. However adding that xmlns didn’t seem to work. So The manifest element is correct and the xmlns seems to be correct but I cannot make the feature do anything.

Posted By: BC_Programming
Last Edit: 17 Jun 2016 @ 04:48 PM

EmailPermalinkComments (0)
Tags
Categories: .NET, API, C#, Programming, Windows

 21 May 2016 @ 12:27 PM 

Keeping on top of new software development platforms is a full-time job… but I’ve already got one! One of my own personal frustrations about my current work is that we are still using Windows Forms. This is fine in that it does the job and I’m familiar with it, but it means that if I want to “remember” how to use WPF or learn anything about UWP, I have to do it on my own time. But when I’m writing or working on apersonal project I want something that words as fast as possible so I often fallback into using Windows Forms.

I recently posted about the Doom WAD File format, and noted that I would be targeting a WPF Application for actually using it, and I’ve held fast to that capability. It has been so long that I’ve forgotten a lot about how WPF and XAML work, so I’ve been relearning a lot. I’ve been referring to “Pro WPF in C# 2008” as a reference on some of the basics (Command Bindings and such).

It got me thinking about all the different platforms and libraries that are available. A recent comment on this blog regarding a code sample could be summarized as “It’s not on Nuget, this sucks, and you suck in particular”. Mind you, as it happens the libraries used there were used again in a later project for the same task which did in fact use NuGet Packages. But it set the mind in motion about how there is something of an unhealthy Dogma surrounding almost anything that is not new and cool and pop’n fresh. Even WPF is old hat tat this point; The ‘cool’ thing to do is abandon the well-fleshed out environment of Windows desktop applications and make UWP and Modern UI ‘Apps’ which themselves have quite a few limitations. In a way we’ve come full circle; we went from dumb terminals that interacted with a server, to fat-client applications that contained a lot of logic and perhaps communicated information with a server such as a database, and now we’re at thin “apps” which exclusively access the outside world through separate web services.

New Platforms, libraries, and technologies come out on such a consistent basis that keeping up is a very difficult task; especially when those new technologies themselves bounced off of previous technologies that you haven’t got a strong grasp on (In my case, XAML and WPF). For me personally I’ll be aiming to make all my future .NET programs in WPF so that in the process I can become more familiar with it (And stop forgetting everything I knew about it from when I worked on BCJobClock).

As a side note, Yesterday (May 21st, 2016) was Visual Basic’s 25th Birthday/Anniversary of it’s release on May 21st 1991. One of these days I have to finish up the drafts of each version of Visual Basic from my ‘series’ of posts on each version. (VB4 I hope to be particularly interesting!)

Posted By: BC_Programming
Last Edit: 21 May 2016 @ 12:27 PM

EmailPermalinkComments (0)
Tags
Categories: News, Personal, Programming

 16 May 2016 @ 11:59 AM 

Occasionally, I like to fire up gzDoom and play through some of the old Doom and Doom II Games and megawads. I use a Random Level generator, Obhack, which I also hacked further to increase enemy and ammo. However, one alteration I like to make is to have higher Ammunition limits. As it happens, the way I had it set up, this information was in a DEHacked patch file within the WAD. As a result, to make changes, I had to use a tool called “Doom Wad Editor”.

Doom WAD Editor, or DWE for short, is about the most up to date tool I could find, and it is rather messy internally. It performs a lot of up-front processing to load the file and show previews and it doesn’t support a lot of modern capabilities. I recently came to a realization that the WAD Format is not some major secret- I could create my own tool.

So far, I’ve been able to construct the Format handler that is able to open and save the internal LUMP files. I’ll likely expand things to also use the KGROUP format (which is used by sole Build Engine games like Duke Nukem 3D) and create a Modern Application for current Windows versions for modifying those older file formats.

The WAD File Format

The WAD (For “Where’s All the Data?”) Format is a format used for Doom and Doom II as well as games using the same engine as well as modern source ports for those games to store game data; this includes maps, levels, textures, sprites, sounds, etc.

The Format itself is rather straightforward. As with most files, we have a Header. At the very start of the file, we find the characters IWAD or PWAD. These characters determine the “type” of the WAD file; a PWAD is a “Patch” Wad, which means it patches another WAD file’s data by replacing it’s contents. For example, a mod that changes all the sounds to be silly animal noises would be a PWAD which uses the same names for different data. an IWAD can be thought of as an “Initial” WAD. These are the “core” WAD files that are needed to play the games in question. The Header data is followed by a signed 32-bit integer indicating the number of Lumps in the file. (A Lump being effectively a piece of data). After that, is another 32-bit integer which is a file offset, from the beginning of the file, where the Lump Directory begins. The Lump Directory is a sequence of Lump Positions in the file, their size, and their 8-character name.

This is all, so far, relatively straightforward. So let’s get to it! . Now, this is just a code example of the basic implementation- my plan going forward with this tool is to flesh it out into a WPF Application that provides full editing and manipulation capabilities to WAD files. There is still an active Doom community creating Megawads and it may prove useful to somebody, and it’s unique enough that creating such an application should be interesting. I’ve been able to load and then resave the standard DOOM.WAD and have the newly saved version function correctly, so it would seem I did something correctly so far:

  1. public class WADFile
  2.     {
  3.         public struct LumpDirectoryHeader
  4.         {
  5.             public Int32 LumpPos;
  6.             public Int32 LumpSize;
  7.             public char []  LumpName;
  8.  
  9.             public override String ToString()
  10.             {
  11.                 return new String(LumpName) + " : Pos:" + LumpPos + ", Size:" + LumpSize;
  12.             }
  13.         }
  14.  
  15.         private char []  Header;
  16.         private Int32 LumpCount;
  17.         private Int32 DirPointer;
  18.  
  19.         private List<WADLump> _Lumps = null;
  20.         private String sLoadedFile = null;
  21.  
  22.         public IList<WADLump> Lumps
  23.         {
  24.             get { return new List<WADLump>(_Lumps); }
  25.         }
  26.  
  27.         public WADFile(String sWADFile)
  28.         {
  29.             sLoadedFile = sWADFile;
  30.             using (BinaryReader br = new BinaryReader(new FileStream(sWADFile, FileMode.Open)))
  31.             {
  32.                 Header = br.ReadChars(4);
  33.                 LumpCount = br.ReadInt32();
  34.                 DirPointer = br.ReadInt32();
  35.                 br.BaseStream.Seek(DirPointer, SeekOrigin.Begin);
  36.                 LumpDirectoryHeader []  LumpHeaders = ReadLumpDirectory(LumpCount, br);
  37.                 _Lumps = InitLumps(LumpHeaders).ToList();
  38.                 foreach (var iterate in _Lumps)
  39.                 {
  40.                     iterate.LumpData = ReadData(iterate.Header, br.BaseStream);
  41.                 }
  42.             }
  43.         }
  44.  
  45.         public void Save(String Target)
  46.         {
  47.             using (FileStream fs = new FileStream(Target, FileMode.Create))
  48.             {
  49.                 Save(fs);
  50.             }
  51.         }
  52.  
  53.         //Save needs to write the headers- The Lump Directory header written at this point a placeholder.
  54.         //It then writes out each lump. During this process, the header information is updated with the current seek position within the file before it is saved.
  55.         //once all the lumps are written, write the Lump Directory- (Position, Size, Name). (The position having been updated during the previous step).
  56.         //It would then seek back to the position at in the file header, and write the starting location of the lump directory.
  57.         //And the save is completed.
  58.         public void Save(Stream Target)
  59.         {
  60.             LumpCount = _Lumps.Count;
  61.             using (BinaryWriter bw = new BinaryWriter(Target))
  62.             {
  63.                 long LumpDirectorySavePos = 0;
  64.                 long LumpDirectoryPos = 0;
  65.                 //write the header.
  66.                 bw.Write(Header);
  67.                 bw.Write(LumpCount);
  68.                 //store this location.
  69.                 LumpDirectorySavePos = bw.BaseStream.Position;
  70.                 //and write a placeholder.
  71.                 bw.Write((int) 0);
  72.                 foreach (var lump in _Lumps)
  73.                 {
  74.                     //update Lump Position based on the seek information.
  75.                     LumpDirectoryHeader ldh = new LumpDirectoryHeader() {LumpName = lump.Header.LumpName, LumpPos = (int) bw.BaseStream.Position, LumpSize = lump.Header.LumpSize};
  76.                     lump.Header = ldh;
  77.                     //write the bytes from this lump.
  78.                     bw.Write(lump.LumpData);
  79.                 }
  80.                 //all lumps are written. Write out the Lump Directory itself.
  81.                 LumpDirectoryPos = bw.BaseStream.Position;
  82.  
  83.                 foreach (var lump in _Lumps)
  84.                 {
  85.                     bw.Write(lump.Header.LumpPos);
  86.                     bw.Write(lump.Header.LumpSize);
  87.                     bw.Write(lump.Header.LumpName);
  88.                 }
  89.                 bw.Seek((int) LumpDirectorySavePos, SeekOrigin.Begin);
  90.                 bw.Write((int) LumpDirectoryPos);
  91.             }
  92.         }
  93.  
  94.         public WADFile()
  95.         {
  96.             _Lumps = new List<WADLump>();
  97.         }
  98.  
  99.         private IEnumerable<WADLump> InitLumps(IEnumerable<LumpDirectoryHeader> Headers)
  100.         {
  101.             foreach (var iterate in Headers)
  102.             {
  103.                 WADLump wl = new WADLump(iterate, null, (y) => ReadData(y));
  104.                 yield return wl;
  105.             }
  106.         }
  107.  
  108.         private byte []  ReadData(LumpDirectoryHeader ldh)
  109.         {
  110.             if (File.Exists(sLoadedFile))
  111.             {
  112.                 using (FileStream fs = new FileStream(sLoadedFile, FileMode.Open))
  113.                 {
  114.                     return ReadData(ldh, fs);
  115.                 }
  116.             }
  117.             return null;
  118.         }
  119.  
  120.         private byte []  ReadData(LumpDirectoryHeader ldh, Stream usestream)
  121.         {
  122.             BinaryReader br = new BinaryReader(usestream);
  123.  
  124.             br.BaseStream.Seek(ldh.LumpPos, SeekOrigin.Begin);
  125.             Byte []  resultdata = br.ReadBytes(ldh.LumpSize);
  126.             return resultdata;
  127.             return null;
  128.         }
  129.  
  130.         private LumpDirectoryHeader []  ReadLumpDirectory(int LumpCount, BinaryReader br)
  131.         {
  132.             LumpDirectoryHeader []  BuildHeader = new LumpDirectoryHeader [LumpCount] ;
  133.             //read LumpCount LumpDirectory Headers.
  134.  
  135.             for (int i = 0; i < LumpCount; i++)
  136.             {
  137.                 BuildHeader [i] .LumpPos = br.ReadInt32();
  138.                 BuildHeader [i] .LumpSize = br.ReadInt32();
  139.                 //now read 8 chars.
  140.                 char []  readchars;
  141.                 readchars = br.ReadChars(8);
  142.                 BuildHeader [i] .LumpName = readchars;
  143.             }
  144.             return BuildHeader;
  145.         }
  146.     }
  147.  
  148.     public class WADLump
  149.     {
  150.         //represents a single WAD Lump.
  151.  
  152.         /*0x00  4   filepos     An integer holding a pointer to the start of the lump’s data in the file.
  153.         0x04    4   size    An integer representing the size of the lump in bytes.
  154.         0x08    8   name    An ASCII string defining the lump’s name. Only the characters A-Z (uppercase), 0-9, and  [ ]  – _
  155.         should be used in lump names (an exception has to be made for some of the Arch-Vile sprites, which use "\"). When a string is less than 8 bytes long, it should be null-padded to the eighth byte. */
  156.  
  157.         public WADFile.LumpDirectoryHeader Header { get; set; }
  158.         private Func<WADFile.LumpDirectoryHeader, byte [] > ReadDataCallback = null;
  159.         private byte []  _LumpData = null;
  160.  
  161.         public byte []  LumpData
  162.         {
  163.             get { return _LumpData ?? (_LumpData = ReadDataCallback(Header)); }
  164.             set { _LumpData = value; }
  165.         }
  166.  
  167.         public WADLump(WADFile.LumpDirectoryHeader pHeader, byte []  pLumpData = null, Func<WADFile.LumpDirectoryHeader, byte [] > pReadDataCallback = null)
  168.         {
  169.             Header = pHeader;
  170.             _LumpData = pLumpData;
  171.             ReadDataCallback = pReadDataCallback;
  172.         }
  173.  
  174.         public override String ToString()
  175.         {
  176.             return "LUMP:" + Header.ToString() + " LumpData:" + LumpData.Length + " Bytes.";
  177.         }
  178.     }
Posted By: BC_Programming
Last Edit: 16 May 2016 @ 11:59 AM

EmailPermalinkComments (0)
Tags
Categories: .NET, C#, Games





 Last 50 Posts
 Back
Change Theme...
  • Users » 39646
  • Posts/Pages » 328
  • Comments » 102
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

PP



    No Child Pages.

Windows optimization tips



    No Child Pages.