Wednesday, July 27, 2016

Asus Reboot Loop after installing SSD

Just a note about a problem I had installing an SSD into my Asus Laptop.

The whole "AI Recovery" thing was a piece of work. First I used the "AI Recovery Burner" to create four recovery disks. Well, it claims 6 disks will be needed...

But in fact it creates only four. Anyway, it wouldn't work, saying there wasn't enough disk space - although it didn't say how much disk space it wanted or even which volume should have free space on it. It turns out that it demands about 50 GB of free space on C:, even though it only needs about 14 GB to write the DVDs (a single DVD holds 4.3 GB, and it uses a little over three DVDs).

After installing my new 480GB SSD and booting from the DVD, it takes about 40 minutes copying data from the disks to the SSD (I happen to know it places the data on a 25GB hidden volume, yes, 25GB to store 14 GB of data, and this will decrease your SSD's capacity.)

After that it rebooted and Windows did a bunch of first-time setup, and then rebooted a second time.

After that, it gets into a horrible reboot loop. Right after the Windows 7 splash screen it says "Setup is preparing your computer for first use" on a black background. Windows boots and shows a message telling you not to use the computer since it is setting itself up. Unfortunately, after a few seconds it will reboot, and this process repeats forever.

The first time this happened, I dealt with the problem as follows: I quickly pressed Alt+Shift+Esc as soon as the taskbar appeared, to show Windows Task Manager, then I found a process with "Asus" in the name (I don't remember what the process was called exactly) and I quickly clicked End Process to terminate it (Alt+E, Space). This terminated the reboot loop; unfortunately, the setup process was left incomplete and the computer had no drivers installed - no video driver, no WiFi support.

Although the computer was left with a 25GB recovery partition, it's useless because the recovery partition is hidden and Asus somehow made it inaccessible to mounting by Windows, and I couldn't find any way to invoke the recovery functionality. Therefore I went through the entire 40-minute copy-from-DVDs process again.

The second time, it occurred to me (because I'm a software engineer) that since the people who wrote the AI software were clearly idiots, they might have written the software with a race condition - maybe they ran two processes simultaneously, one of which is assumed to finish first and the other is assumed to finish second and forces a reboot. If the first process was CPU-bound and the second was IO-bound, then the second process would run much faster on an SSD than a normal hard drive, and therefore finish before the first process.

Based on this hypothesis I tried stressing the SSD in various ways as soon as humanly possible after the system booted. It took several attempts, but eventually the following strategy seemed to work:

  1. The instant the Taskbar appears, very quickly press the Windows Key (to show the Start Menu), then type C: and press Enter. The contents of the C: drive (your SSD) are shown instantly.
  2. As fast as humanly possible, click the Windows folder (one click only), then Ctrl+C (which means "copy"), then Ctrl+V (which means "paste"). This will cause Windows to start making a copy of the Windows folder, which is very large and therefore keeps your SSD busy. If you do it fast enough, some of the installation process will complete.
  3. If the computer hasn't restarted by the time copying is half-done, start making a second copy of the same Windows folder to keep the SSD busy.
  4. This will take several attempts, so you will end up with several folders like Windows - Copy (2), Windows - Copy (3), Windows - Copy (4). Be sure to delete old copies periodically, otherwise your SSD will fill up and copying will fail. Press Shift+Delete to delete permanently, which bypasses the Recycle Bin, but be sure NOT to delete the original Windows folder or any of the other folders that are not copies.
  5. As you keep trying, eventually all the drivers and software should be installed successfully. The computer will restart one last time and Windows will ask you what OS language to use (English, Chinese, Spanish, etc.) When this happens, it indicates all is well! The reboot loop should be over and all your drivers should be installed.
  6. Once the reboot loop is over, make sure you delete those copies (Windows - Copy (2), Windows - Copy (3), Windows - Copy (4), etc.) to avoid wasting SSD storage space.

I know this is a challenging solution, and I can't guarantee it'll work on your laptop, but it worked on mine, and it has the virtue of not needing a second computer or special software in order to escape the reboot loop. If I were a better hacker I could no doubt find a more reliable solution, so I apologize that I'm not a better hacker.

Friday, September 26, 2014

CPSC 217 T03 2014 @ UCalgary

I'm a TA for Tut03 at University of Calgary... what fun! I'll put a link to my UCalgary CPSC217 web space here in the hopes that Google will eventually index it.

Thursday, June 19, 2014

Painkiller Black ending script

Alistor is extremely difficult to understand so here is a transcription.

Daniel: Hold on Eve, I’ll get you out of here. (Demons surround Daniel. Alastor draws near.)

Alastor: Well done Daniel... well done.

Daniel: Alastor? What... I... I thought I killed you?

Alastor: Wha... Kill me? [laugh] You can’t kill me up there... you simply sent me back here. We can, however, be destroyed down here. [Motions toward Lucifer] I think he should have finished you off when he had the chance... but in the end, he was blinded by his infatuation with Eve, and it got the best of him... [laugh] I knew it would.

You put up more of a fight than I thought you would… Absorbing those demon souls has given you a tremendous amount of strength... I think it might have clouded your judgment.... Welcome to hell!

Daniel: I... I don’t understand...

Alastor: Of course you don’t, you foolish human. We could have overthrown Heaven ages ago, but Lucifer wasn’t confident we were ready. He thought we needed more demons... He thought we lacked the strength necessary. He gave them too much credit and wasted too much time. He was weak, he was shortsighted... and he had to be removed from power. [...sentence inaudible...] We all came here for Lucifer... You just happened to beat us to it. I didn’t think you could destroy him... regardless, had you not done it, we surely would have. I must admit I was shocked to see that you declined the offer into heaven. Ooh... bad decision.

Daniel: When I’m finished here, I’ll make my way up there.

Alastor: When you’re finished here? Ha! You’ll never be finished here! Ooh, I’m going to torture you for eternity... I’m going to enjoy watching you scream with pain as I slowly gut you. Don’t worry... you won’t feel much.

Daniel: Bring it on.

Thursday, June 12, 2014

Writing a Useful Windows Service in .NET in Five Minutes

This helpful blog post about writing a Windows Service didn't allow comments so I'm writing a comment here.

I don't like to have to call external utilities to install and uninstall things; I think programs should be able to install and uninstall themselves, so I tried to figure out how to write Install() and Uninstall() methods using .NET code. Here's what I came up with:
[System.ComponentModel.RunInstaller(true)]
public class MyServiceInstaller : Installer
{
    private ServiceProcessInstaller processInstaller;
    private ServiceInstaller serviceInstaller;

    public MyServiceInstaller()
    {
        processInstaller = new ServiceProcessInstaller(); // "to write registry values associated with services you want to install."
        serviceInstaller = new ServiceInstaller();        // "to write registry values associated with the service to a subkey within the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services registry key"

        processInstaller.Account = ServiceAccount.LocalSystem;
        serviceInstaller.StartType = ServiceStartMode.Automatic;
        serviceInstaller.ServiceName = ServiceBaseClassName.Name;

        Installers.Add(serviceInstaller);
        Installers.Add(processInstaller);
    }

    public static void Install() // throws on failure
    {
        // MyServiceInstaller has an Install() method but we can't call it 
        // directly, because a NullReferenceException occurs in its bowels.
        //var installer = new MyServiceInstaller();
        
        // So instead we will ask AssemblyInstaller to scan this assembly,
        // and call Install() on our behalf.
        var installer = new AssemblyInstaller(Assembly.GetExecutingAssembly(), new string[] { "/ShowCallstack" });
        // Doc says: «Setting this property to true creates a new file named 
        // "{Assembly name}.InstallLog" to log messages for this assembly. Setting 
        // UseNewContext to false prevents the new file from being created.»
        installer.UseNewContext = true;

        var pointlessComplication = new Hashtable(); // who knows why
        // The documentation states "If all the Install methods succeed, the 
        // Commit method is called. Otherwise, the Rollback method is called."
        // That is WRONG, Install() does not call Commit().
        installer.Install(pointlessComplication);
        // However it probably doesn't matter if we call Commit() or not 
        // because ServiceInstaller and ServiceProcessInstaller do not override 
        // the Commit() method.
        installer.Commit(pointlessComplication);
        // Note: the service is not started yet (no, I don't know how.)
    }
    public static void Uninstall()
    {
        // Likewise, don't call Uninstall(), it throws NullReferenceException.
        // The exception that occurs on failure is wrong. For instance if the
        // service is not installed, the debugger tells you that an exception
        // occurs with the following message:
        //   "The specified service does not exist as an installed service."
        //
        // However, this exception is discarded (not preserved as an 
        // InnerException as it should be). Instead you get two nested 
        // InstallExceptions and both of them contain this brain-dead message:
        //   "An exception occurred while uninstalling. This exception will be 
        //   ignored and the uninstall will continue. However, the application 
        //   might not be fully uninstalled after the uninstall is complete."
        // 
        // The real exception is appended in the *.InstallLog file, although
        // there is no clear separation in that file between the install 
        // information and the uninstall information (e.g. no newlines).

        //var installer = new MyServiceInstaller();
        var installer = new AssemblyInstaller(Assembly.GetExecutingAssembly(), new string[] { "/ShowCallstack" });
        installer.UseNewContext = true;
        var pointlessComplication = new Hashtable();
        installer.Uninstall(pointlessComplication);
        installer.Commit(pointlessComplication);
    }
}
As you can see, I had an (undocumented) problem with NullReferenceException, but I worked it out.

Install() seems to work perfectly (the service appears on the service list, and no exception occurs), but Uninstall() doesn't work properly; the service is uninstalled, yet an exception occurs that says "Service was not found on computer '.'.". This exception is discarded by the uninstaller, then the uninstaller deletes the ServiceName.InstallState file, then it throws the following idiotic exception: "Could not find file 'C:\...\bin\x86\Debug\ServiceName.InstallState'."

Further investigation suggests that something silently went wrong during the install process, even though ServiceName.InstallLog does not show any problems. After a "successful" installation, running "C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil" /u C:\...\bin\x86\Debug\ServiceName.exe produces the following warning:
The file containing the saved state for the C:\...\bin\x86\Debug\ServiceName.exe assembly, located at C:\...\bin\x86\Debug\ServiceName.InstallState, could not be read, and the file might have been corrupted. The uninstall will continue without the saved information.
Huh. Okay. So next, based on a decompilation of System.Configuration.Install.ManagedInstallerClass.InstallHelper(), I basically uninstalled the same way it does:
public static void Uninstall()
{
    var installer = new AssemblyInstaller(Assembly.GetExecutingAssembly(), new string[] { "/ShowCallstack" });
    installer.UseNewContext = true;

    TransactedInstaller tInstaller = new TransactedInstaller();
    tInstaller.Installers.Add(installer);

    tInstaller.Uninstall(null);
}
Internally, the same exception occurs, "Service was not found on computer '.'." But the exception is caught and discarded and, as before, the service actually is uninstalled. Thanks TransactedInstaller! Unfortunately, using TransactedInstaller to perform the installation doesn't make any difference (if you use TransactedInstaller to perform the installation, InstallUtil /u still claims that the InstallState "might have been corrupted".)

Finally I tried this simple version:
public static void Install() // throws on failure
{
    ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location, "/ShowCallStack", });
}
public static void Uninstall()
{
    ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location, "/ShowCallStack", "/u" });
}
If you decompile InstallUtil you'll find that it's an "empty shell"; all it does it call this InstallHelper() method! However, still this code does not behave quite the same way as the real InstallUtil.exe; in fact it behaves exactly as before: the install and uninstall both succeed, but the uninstall involves a swallowed "Service was not found on computer '.'." exception and if you use InstallUtil.exe /u to uninstall, there is a message saying that the InstallState "could not be read". And again, if uninstall fails, the exception that contains the actual reason is thrown away and replaced by a generic message.

Friday, May 16, 2014

The Calgary Naturists Meetup Group...

...has moved to GroupSpaces.

Wednesday, December 18, 2013

The FastNav® GIS mapping component

FastNav is a commercial, offline mapping component for Windows XP/7, Windows CE (ARM) and Android. The Windows versions of this mapping component can be embedded in C# (Compact Framework or .NET Framework) programs, C++ programs, or any other language that supports COM. The Android mobile map software, pictured below, is currently a standalone app that accepts basic commands via intents, but it too could easily be altered to support embedding in other apps.


FastNav is currently used in Trapeze Mobility, which is used in Ranger® mobile devices for Taxis, Buses, Paratransit, and other commercial vehicle fleets; it's also being added to the Trapeze MDC software:


Here it is running inside a couple of Desktop Windows apps:


It also has been used as a non-graphical server-side component for routing computations.

FastNav was first deployed in the field over five years ago, and I always thought it should be something my company, Mentor Engineering, should market to other businesses, but they never did so. Other commercial mapping components have fantastically espensive licensing fees, so we could have easily undercut the competition and laughed all the way to the bank. However, to this day FastNav has never been marketed outside the company, even after Mentor Engineering was acquired by Trapeze Group. To this day there is not a single page on the internet about FastNav, so I decided to change that by writing this blog post.

FastNav is available as an SDK with numerous C# and C++ sample applications and about 200 pages of documentation in PDF and HTML format. Its drawing speed is competitive with similar products on the market (while showing a more detailed map), and its routing performance is excellent. For prospective customers, here's the most important page of that documentation:

SDK capabilities & limitations

This SDK was originally designed for map display and routing capabilities that you would find in handheld or in-car GPS navigation devices:
  • Read and decode NMEA data from a COM port
  • Show maps in 2D or 3D, in night or day mode.
  • Display and follow a vehicle as it moves on the map, display a computed route, display the current destination point, or display the entire map.
  • Display a map centered at a specific location and zoom level
  • Display a customizable number of street labels
  • Display and speak imperial or metric units
  • Allow the user to select a location on the map, and show information about the road at that location.
  • Look up cities, street names, house numbers, addresses, and points-of-interest (POIs), and retrieve the coordinates of, or route to, the location found.
  • Get the nearest approximate address to a longitude and latitude.
  • Find a route from the vehicle's location to a specific location selected programmatically or by the user.
  • Recalculate the route automatically when the vehicle moves off-route.
  • Give spoken turn-by-turn directions using either pre-recorded voices or a text-to-speech engine. Your program can obtain the current instruction in text form.
Beyond these basic features, FastNav APIs allow you to
  • Compute special routes with waypoints, or "reverse-geocode" routes from a series of points (new in FastNav 2.0)
  • Dynamically apply delays or block routing on specific road segments or sequences of roads (new in FastNav 2.0). TomTom licenses a real-time traffic API that could be used in conjunction with this feature.
  • Use multiple independent map controls in a single application.
  • Hide parts of the display such as the compass, polygons and POIs.
  • Select custom colors for your map.
  • Put any number of custom lines, polygons, POI markers, vehicle markers, icons and text strings on the map (in geographic space, pixel space, or geo-relative pixel space). New in FastNav 2.1: self-positioning text balloons and temporary messages that fade away after X seconds.
  • Produce GPS logs (NMEA format) from real or simulated data, and play them back.
  • Find out the latitude and longitude corresponding to mouse coordinates, or vice versa (new in V01R09)
  • Find the shortest or fastest route (new in V01R10)
  • Avoid or prohibit routing on ferries, toll roads, or other "undesirable attributes" if they are present in the map file (V01R10)
  • Examine individual elements or layers in a map file programmatically (V01R10)
  • Draw new shapes on the map "instantly", or do animations, using the animation layer (V01R12)
  • Search for either a city name or street name first, with a completion list that offers both city and street names (V01R13)
  • Search for complete addresses at once ("free-form" address search)
  • Get a list of turns on the current route (V01R13)
  • Find one or more roads or other elements near a specified location, sorted by distance, with address estimation (V01R14)
  • Find building numbers with non-numeric components (e.g. N4500-W4500 in Wisconsin) (V01R15)
  • Detect speeding, control a Virtual Car with the arrow keys, translate DLS and NTS coordinates, or speak directions in French.
Limitations of the FastNav library:
  • Facilities for creating NaviMap files or modifying them are not currently available outside the company. Contact Trapeze if you need to create maps. We currently deliver NavTeq map data.
  • Although the map control can display multiple maps, routing doesn't work between two different files, and the blue info box only works for the main file (this can be overcome by handling mouse input manually).
  • TMC is not supported directly; it requires an external database of roads, which is not included.
FastNav is owned by Trapeze Group. I don't know what Trapeze would want to charge you for licensing FastNav, but it can't hurt to give them a call. My suggestion would be, tell 'em how much you have been quoted as a price for Destinator or Telogis mapping, then ask how much you can save by switching to FastNav. You can also talk to me directly by leaving a comment on this post or mailing qwertie256 [at] gmail.com.

As the author of FastNav, I, for one, welcome your questions. Update: please note that I recently left Trapeze for different-colored pastures.

The views expressed in this post are my own and were not approved or endorsed by Trapeze.

Friday, November 29, 2013

.NET will not inline methods with many parameters (in practice)

By examining disassembly of this method in the debugger, I learned that the .NET inliner (x64) is too dumb to take into account the cost of calling a method in its inlining decision. .NET will not inline the last three methods, even though I only add a single additional instruction for each additional parameter. So it seems the inlining decision is based only on the cost of the method body; .NET ignores the cost *savings* of not having to shuffle registers or stack space around when it inlines a method.
private static long InliningTest(long a, long b, long c, long d, long e, long f, long g, long h)
{
    long total = 0;
    total += Foo(a, b, c);
    total += Foo(c, d, e, f);
    total += Foo(d, e, f, g, h);
    total += Foo(f, g, h, a, b, c);
    total += Foo(h, a, b, c, d, e, f);
    total += Foo(a, b, c, d, e, f, g, h);
    total += Foo(a, c, e, g, b, d, f);
    total += Foo(a, b, c, d, e, f);
    total += Foo(a, b, c, d);
    total += Foo(a, b, c);
    return total;
}
private static long Add(long a, long b)
{
    return a + b;
}
private static long Foo(long a, long b, long c)
{
    return a * b * c + a + b + c;
}
private static long Foo(long a, long b, long c, long d)
{
    return a * b * c * d + a + b + c;
}
private static long Foo(long a, long b, long c, long d, long e)
{
    return a * b * c * d * e + a + b + c + d;
}
private static long Foo(long a, long b, long c, long d, long e, long f)
{
    return a * b * c * d * e * f + a + b + c + d;
}
private static long Foo(long a, long b, long c, long d, long e, long f, long g)
{
    return a * b * c * d * e * f * g + a + b + c + d;
}
private static long Foo(long a, long b, long c, long d, long e, long f, long g, long h)
{
    return a * b * c * d * e * f * g * h + a + b + c + d;
}

Wednesday, November 20, 2013

Re: VSIX with the VS2010 Beta 2 SDK

I found this blog post useful. I tried to leave the following comment, but was told that only "team members" were allowed to leave comments.

Thanks very much! I figured out the MergeWithCTO thing myself by comparison to another project, but then I got this error in ActivityLog:
<description>CreateInstance failed for package [MyExtension.MyPackageClass, MyExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b1460dff8a28f7a7]</description>
...
<errorinfo>Could not load file or assembly 'MyExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b1460dff8a28f7a7' or one of its dependencies. The system cannot find the file specified.</errorinfo>
The error message made no sense at all because (1) the error message knows the name of the Package class, how could it discover the name of the class if it never loaded the DLL? and (2) my extension also contains an implementation of ITaggerProvider that runs properly, so clearly my DLL was being loaded.

Adding those properties to my csproj file fixed the problem.
<PropertyGroup>
 <RegisterOutputPackage>true</RegisterOutputPackage>
 <RegisterWithCodebase>true</RegisterWithCodebase>
</PropertyGroup>

Saturday, October 26, 2013

VS Classification Type Names

If you're programming a syntax highlighting extension for Visual Studio, of course you'll want to use some of the pre-existing classification names in your language. You can use the IClassificationTypeRegistryService passed to the constructor of your IClassifier class to get an existing classification by name, but there does not seem to be any API to get a list of all the existing token types. Some, but not all, of the names are available in PredefinedClassificationTypeNames, which is a class in the Microsoft.VisualStudio.Language.StandardClassification assembly.

To get the other names, I inspected the registry object within the debugger and was able to get the following list. Strangely, however, I don't see anything that might correspond to "C# @verbatim" or (what I was really looking for) "Brace matching", which I wanted to use to make Sam's Brace Matching Tagger work properly.
CSS Comment
CSS Keyword
CSS Selector
CSS Property Name
CSS Property Value
CSS String Value
XML Doc Comment
formal language
XML Doc Tag
C/C++ User Keywords
CppInactiveCodeClassification
CppSolidColorClassification
excluded code
cppMacro
cppEnumerator
cppGlobalVariable
cppLocalVariable
cppParameter
cppType
cppRefType
cppValueType
cppFunction
cppMemberFunction
cppMemberField
cppStaticMemberFunction
cppStaticMemberField
cppProperty
cppEvent
cppClassTemplate
cppGenericType
cppFunctionTemplate
cppNamespace
cppLabel
HtmlServerCodeBlockContent
Razor Code
RegularExpression
VB XML Doc Tag
VB XML Doc Attribute
VB XML Doc Comment
VB XML Delimiter
VB XML Comment
VB XML Name
VB XML Attribute Name
VB XML CData Section
VB XML Processing Instruction
VB XML Attribute Value
VB XML Attribute Quotes
VB XML Text
VB XML Embedded Expression
VB User Types
VB Excluded Code
CoffeeScriptRawJavaScript
CoffeeScriptHeRegExSeparator
HtmlClientTemplateSeparator
HtmlClientTemplateTag
HtmlClientTemplateValue
LessCssVariableDeclaration
LessCssVariableReference
LessCssNamespaceReference
LessCssMixinDeclaration
LessCssMixinReference
LessCssKeyword
HTML Attribute Name
HTML Attribute Value
HTML Comment
HTML Element Name
HTML Entity
HTML Operator
HTML Server-Side Script
HTML Tag Delimiter
HTML Priority Workaround
VBScript Keyword
VBScript Comment
VBScript Operator
VBScript Number
VBScript String
VBScript Identifier
VBScript Function Block Start
biDiNeutral
text
quickinfo-bold
MarkerPlaceHolder
word wrap glyph
sighelp-documentation
currentParam
natural language
comment
identifier
keyword
whitespace
operator
literal
string
character
number
other
preprocessor keyword
symbol definition
symbol reference
(TRANSIENT)
url
line number
PageInspectorAutoSyncClassification
XML Doc Attribute
User Types

Tuesday, October 15, 2013

Everybody says you're bad, baby

I really enjoyed this song in the trailer for Euro Truck Simulator 2.
Baby got me feeling sure, 
You're what I've been looking for
Everybody says you're bad for me, everybody says you're bad
But that just makes me want you more

Baby you're hot, na na na na
Hot like summer sun
You're hot hot, na na na na
Baby you're my number one, oh, oh

I just can't believe my luck
I don't ever want to stop
Everybody says you're bad for me, everybody says you're bad
But I just want to soak you up

Baby you're hot, na na na na
Hot like summer sun
You're hot hot, na na na na
Baby you're my number one, oh, oh

(Hot hot, hot like summer, hot hot)
(Hot hot, hot like summer, hot hot, hot hot)
Everybody says you're bad for me, everybody says you're bad
Everybody says you're bad for me, everybody says you're bad
Apparently by Sarah Ozelle.

But sorry Euro Truck Simulator 2, you're not the game for me.