Sunday, January 31, 2016

ClickSend Surprise: Dedicated number not used by default

Today I set up a program that uses ClickSend to automatically send text messages to people from a dedicated phone number I purchased. While setting it up, I encountered a couple surprises.

First, the default SMS setting is to send from a random number in ClickSend's pool. That was a surprise because some of their documentation indicates that the default behavior is to use a single number from their pool that can also be shared by other users.

The second surprise was that, even after I adjusted the above setting, messages continued to be sent from random numbers. After calling ClickSend (several times - I couldn't seem to get an actual engineer on the line), I finally got an e-mail response explaining that the HTTP request has to specify the source number once a dedicated number is purchased. There was no documentation stating that anywhere, but once I made the slight code change, everything was good.

Saturday, January 30, 2016

How big are your drive's sectors?

From the days of old, hard drive sectors have been 512 bytes. That created problems, however, when drives started getting bigger than 2 terabytes because MBR-partitioned disks only set aside 32 bits to indicate how big a partition is. Therefore, no partition could be bigger than 2^32 sectors * 512 bytes/sector = 2 TiB. GPT has effectively superseded MBR and solves that problem, but there are other reasons (efficient error detection, for instance) to want larger sectors. Some drives available now are in the Advanced Format, with sectors 4,096 bytes long. Interestingly, though, some of those drives present themselves to the OS as classic 512-byte sector disks for compatibility.

You can see your drive's real and presented sector sizes on Windows by running this command:

fsutil fsinfo sectorinfo c:

(Replace C with your drive's letter if necessary.) In the output will be a LogicalBytesPerSector value (what your OS sees) and a PhysicalBytesPerSectorForAtomicity value (the real deal), among other data.

Friday, January 29, 2016

Bizarre behavior when running programs as a domain user when logged in as local user

Yesterday I tracked down a crash that occurred in a third-party application when that program was run as a domain user but the Windows logon session was of a local user. The interesting thing was that the crash didn't happen on all computers.

After much investigation, I discovered that logging on to Windows with the domain user made the program (running in the local user's session) to start working again. I concluded that the program looked for some files in the profile of the user it was running as. I also guessed that the domain user hadn't logged on to the machine. Once it did, the full profile was established, so the program didn't crash when it looked for that file.

Thursday, January 28, 2016

What taking ownership actually means

There seems to be a lot of confusion on the Internet about what taking ownership of a securable object in Windows actually means. Many people expect it to grant full control of the object, but that is not the case.

The only special power conferred by being an object's owner is control over the object's DACL. The owner (or a member of the group that is the owner) can always read and write the access control list, even in the presence of Deny entries for those permissions. The write-DAC power can then be used, if desired, to grant Full Control to oneself or another, but just being the owner does no such thing.

Therefore, the "Take ownership" privilege on an object is effectively Full Control; it just requires one more hoop to be jumped through. Administrators (or an account assigned SeTakeOwnershipPrivilege) can always take ownership of anything.

Wednesday, January 27, 2016

ODBC driver unexpectedly missing? Check your bitness

Today I debugged a crash that resulted from an alleged lack of an ODBC driver for the database product specified in a .NET OdbcConnection connection string. The exception text indicated that no driver could be found, but the ODBC driver had indeed been registered and appeared in the Registry.

The program had been compiled for the AnyCPU platform. That defaults to having "Prefer 32-bit" enabled. The problem was that the program was indeed started in a 32-bit process, and the driver was 64-bit. Since 32-bit programs can't load 64-bit DLLs, the driver couldn't be loaded, and so the connection failed.

The solution for that machine was to uncheck the "Prefer 32-bit" box so that the process created was 64-bit.

Tuesday, January 26, 2016

Rundll32: Stop

All over the Internet can be found commands that use rundll32.exe to invoke a function inside a DLL. (LockWorkStation is the most common.) This is a Bad ThingTM, because rundll32 is deprecated, and has been since Windows Vista. Why?

It turns out that it's not a good plan to have any DLL's functions run under the environment of rundll32, which opts into all new Windows features like Data Execution Prevention and Terminal Services awareness. More shockingly, rundll32 always passes a window handle and other stuff to the function (since it assumes that the function pumps messages) even if, in reality, the function takes no arguments. Therefore, bogus parameters are passed or the memory after the stack is written over if the function's signature is not what's appropriate for rundll32 invocations.

So, please stop using rundll32 to invoke arbitrary pieces of OS functionality. There's almost certainly a better way - try normal programs, or PowerShell, or WMI, or just write your own program where you control the environment. For more information, see this Raymond Chen blog post.

Monday, January 25, 2016

How can a file's "size on disk" be zero when it contains some data?

I recently wrote an answer to this Super User question that asked why a certain file's "size on disk" value (in the Properties window) was zero despite there being data in the file.

That phenomenon can be caused by several things, but only one of the causes will be commonly encountered by people who aren't server operators, and that cause is NTFS "resident storage." Every file record in NTFS is exactly 1KB, but not all of that space is always used up for file system bookkeeping. Therefore, to save disk space, NTFS keeps the data of small files right inside the file record. That is, no clusters - 4KB chunks in which file data is stored outside of the bookkeeping records - are allocated. Microsoft's "Ask the Core Team" blog did a piece on the growth of NTFS files, which is a great read.

Another possible cause of zero size-on-disk is Windows data deduplication, a relatively new file system feature that moves identical chunks of files out of the file data and into a special store. When a file is an exact duplicate of another, no new clusters have to be allocated.

Sunday, January 24, 2016

FMod - Circumventing GDI+

The bottleneck for Abiathar's performance is graphics operations - bitmap scaling and layering are expensive operations with .NET and GDI+. My last improvement in that area was to switch the image format to 32bppPArgb, which did indeed produce a noticeable speedup.

Today, however, I made a larger change. After consulting the documentation for Bitmap.LockBits, I rewrote the tile render planes to use direct memory manipulation (with Marshal.Copy and pointer math) instead of DrawImage calls. The initial level rendering is now dramatically faster, almost instant for default levels at 100% zoom.

Saturday, January 23, 2016

FMod - Small Fixes

I made a few small adjustments to Abiathar and FleexCore2 today:
  • Abiathar's Export Image command claimed to create BMP files, but the file was actually in PNG format. An option has been added to the save-file dialog to use PNG vs. BMP. Automatically named exported images will be saved in the format appropriate for the given extension.
  • Abiathar's New Project Wizard wasn't correctly displaying the Graphics Files settings when Project Settings (the NPW's edit mode) was used. Specifically, it didn't handle default EGADICT loading correctly. That has been fixed.
  • Abiathar's yet-unreleased "move the tile view offset to include the newly selected tile" feature was triggering even when the new tile was within the view, resulting in unnecessary and jarring jumps. I fixed the logic error that caused this.
  • FleexCore2's NextGenGraphics class (which Abiathar doesn't yet use) didn't preserve all the tables' entries (sprite table, picture table, masked picture table) when the start and end chunks for those resource types weren't specified. Logic has been added to deal with that case.

Wednesday, January 20, 2016

How does RegEdit require admins to elevate, but not standard users?

Some programs, like the Registry Editor and MMC, will require you to elevate if you're logged on as a local admin but will run just fine if you log on as a standard user.

That setting is stored as part of a program's manifest, an XML configuration tree embedded in the executable (usually). The requestedExecutionLevel setting controls the app's elevation behavior.

  • The default (asInvoker) does not require elevation; if you want to run it elevated, you'll need to explicitly do that by choosing the appropriate item from the context menu. Normal stuff like Notepad uses this value.
  • highestAvailable - the value responsible for this phenomenon - requires the best the current user can have.
  • requireAdministrator always requires elevation. System management tools like DiskPart use this.
You can quickly eyeball an executable for a manifest by searching for the string "manifest" in it with a hex editor or even a text editor. The requestedExecutionLevel setting will be shortly after the place you find.

Tuesday, January 19, 2016

Bizarre folder structure behavior with folders named all dots

For a recent Super User answer, I investigated what happens when Windows encounters folders with names that are entirely comprised of periods. These folders can only be created with the special \\?\ full-path prefix, so most people won't ever run into them. If you do have such a folder, however, you're in for some weird experiences.

It does not appear to be possible to cd into such a folder with the command prompt; you just get put in the current directory. (I think this is because . is an alias for the current folder.) Windows Explorer will go into such a folder, but its contents will appear to be the same as those of its parent directory; the listing includes the dot folder itself. (I guess this is because .. is an alias for the parent folder?) If you try to open any file or navigate deeper, Explorer will have problems; it will be as if the thing you tried to open doesn't exist.

To recover files out of such a directory, you need to either use the short 8.3 (dir /x) name or create a normal-named directory symbolic link. Once the dot folder is empty, you'll be able to rd it by its \\?\ name.

Monday, January 18, 2016

Atroxian Realm is out!

If you're following the Keen community's activity (of which I'd like to think Abiathar is a non-negligible part), you've heard of Atroxian Realm, Gridlock's massive Keen Galaxy mod project. Atroxian Realm has been in the works for five years and has gone through several shifts in technology and tools. As of a couple days ago, January 15, 2016, Atroxian Realm has been released as version 1.0. There are always little things to improve and tweak, so the team has left open the possibility of future releases.

Download Atroxian Realm at the PCKF

I have had the privilege to be on the AR team in the roles of primary testing, programming support, and tools support. I thoroughly enjoyed it, and I hope to have the chance to collaborate with these people again in the future.

Sunday, January 17, 2016

FMod - Fixing Graphics Re-import

In writing the NetKeen Tile Migration Tool, I took advantage of the semi-new NextGenGraphics class in FleexCore2. While testing the part where it copies the tiles, I ran into some problems - the tiles were corrupted after being written back to disk. I discovered three problems:

  • An incorrect variable was used in place of a similarly-named variable, causing ColorsToBinary to look at the wrong indexes in the colors array (or crash, in some cases).
  • The actual color part of the color ID in BitmapToColors was shifted left too far, causing the mask to be treated as the actual color in ColorsToBinary.
  • Thanks to some incorrect bit twiddling, the order of the color planes got reversed in ColorsToBinary.
I hadn't found these issues earlier because I had never tested modifying images before resaving the graphics resources. (Just opening and resaving doesn't fully deserialize and reserialize everything, only the modified parts.)

Saturday, January 16, 2016

NetKeen Tile Migration Tool

A relatively new PCKF member asked for tile sheets of Ceilick's excellent unofficial The Universe Is Toast games. He wanted to put the graphics into NetKeen to make multiplayer maps in that style. Copying the right parts of the tile sheets would work, but tileinfo is trickier. Somebody suggested that tileinfo has to be set up manually, but I knew automating it wouldn't be too hard.

So I wrote the NetKeen Tile Migration Tool (NKTMT). It moves tiles and tileinfo from resources of an arbitrary chunk layout into existing NetKeen resources. The program requires an updated version FMod.dll (FleexCore2) for the NextGenGraphics class.

Download NetKeen Tile Migration Tool

nktmt.exe takes 22 command-line parameters, all required, in this order: source EGAGRAPH, source EGAHEAD, source EGADICT, source TLI, source unmasked tile start, source unmasked tile end, source masked tile start, source mask tile end, NK EGAGRAPH, NK EGAHEAD, NK EGADICT, NK GAMEMAPS, NK MAPHEAD, NK unmasked tile start, NK unmasked tile end, NK masked tile start, NK masked tile end, source infoplane icon count, NK infoplane icon count, NK unmasked 8x8 tile chunk, NK unmasked 8x8 count, NK masked 8x8 count.

For example, I used these parameters to put the Keen 8 (based on Keen 6) resources into NetKeen resources (named .CK4): egagraph.ck6 egahead.ck6 egadict.ck6 keen6.tli 438 2813 2814 5549 egagraph.ck4 egahead.ck4 egadict.ck4 gamemaps.ck4 maphead.ck4 777 2288 2289 5240 108 108 775 30 12

Friday, January 15, 2016

Creating Permanent All-User Network Drives with \\?\UNC\

A little-known detail of Windows is that prepending \\?\ to a path makes Windows internals treat it as a literal path, allowing it to exceed the normal limit of 260 characters. A special case of the notation is that \\?\UNC\ indicates a network path. For example,

\\?\UNC\server\share

points to a share called share on server. This fact makes it possible to create network drive mappings that apply to all users with the help of the key called:

HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices

Entries in that key function as DOS-style magic file names, but they can also be used to map network drives. For example, an entry called Z: with the previously-mentioned path as its value would create a network drive lettered Z for all users.

Interesting note: there's advice going around on the Internet that you need two question marks for this to work. That's false - it works just fine with only one, and question marks don't need to be escaped in the Registry or in file paths.

Thursday, January 14, 2016

Windows Power Configuration Registry Settings

This post is based on a Super User answer I wrote today.

Today I did some poking around in the Registry and discovered how power options are stored. The root of these settings is, predictably, HKLM\CurrentControlSet\Control\Power. All "IDs" relating to power management in the Registry are GUIDs, but my quick surveys show that the default ones are the same on all machines.

The User\PowerSchemes subkey of Power has an entry called ActivePowerScheme which contains the ID of the current power plan. The subkeys of PowerSchemes are, well, power schemes. 381b4222-f694-41f0-9685-ff5bb260df2e, for instance, represents Balanced (recommended).


The subkeys of the power scheme keys are categories as they appear in the advanced power options. These are defined in the PowerSettings subkey of Power. For instance, 0012ee47-9041-4b5d-9b77-535fba8b1442 is the one for Hard disk. The subkeys of those are the individual settings. 6738e2c4-e8a5-4a42-b16a-e040e769756e is the Turn off hard disk after setting. Those keys have a DefaultPowerSchemeValues subkey, which has a subkey for every standard power plan. Those keys have an AcSettingIndex and a DcSettingIndex entry which are exactly what you think. The units used vary from setting to setting. So, you can see that the default hard drive power-off timeout for the Balanced power plan is 1200 seconds (20 minutes) when plugged in and 600 seconds (10 minutes) on battery.


Now back to the User\PowerSchemes key. Since the user might not have ever changed the settings, there's no guarantee that the key will have both AC and DC setting entries, the setting subkey, or even the category subkey. If the desired value isn't there, the system checks the default value for the current power plan back in PowerSettings\DefaultPowerSchemeValues.

Note that none of this should be used by serious compiled applications. (For entertainment/scripting purposes only!) Developers of compiled applications should use the documented interface for power management. Call GetCurrentPowerPolicies, and - for the settings we looked at here - get the user part of the POWER_POLICY structure, then look at the SpindownTimeoutAc and SpindownTimeoutDc values.

Wednesday, January 13, 2016

Chrome UI Bug: Menu doesn't disappear on mouse leaving

I have noticed - after several accidental window closings - that Chrome's menu (the one called up by the hamburger icon) leaves the last-moused-over menu item selected even after the mouse leaves the menu entirely. This means that when I accidentally hold down the mouse on the hamburger icon and take the mouse off the menu before releasing the button, I'm probably going to activate some item, and since I tend to drag down, that's usually Exit.

Note that normal Windows menus don't have this infelicity - dragging off the menu and releasing just causes the menu to disappear. I wish Chrome obeyed that convention.

Tuesday, January 12, 2016

Registry settings for console styles

If you've ever used PowerShell, you'll recognize its distinctive white-on-blue color scheme. You might think that such styling is set by the program itself at runtime, but not for PowerShell. PowerShell is styled just like other console programs - by settings in the registry.

In HKCU\Console, you'll find entries that define the fonts and colors for normal console applications. You'll also see subkeys with names that look kind of like file paths. The entries in those subkeys apply only to programs with their EXE at that path. Therefore, PowerShell's styles are kept in:

HKCU\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe

If a program styled in this way is moved or renamed, it will receive the default styles because there won't be a corresponding subkey. Even launching the program with extra backslashes in its full path will cause it to lose its styles, a situation which prompted me to write this Super User answer.

Monday, January 11, 2016

Looking for fonts on your computer that support a certain character

For a Super User answer, I wrote a PowerShell script that figures out which of the fonts you have installed that support a certain character.

$charId = [Int32][char]$args[0]
[System.Reflection.Assembly]::LoadWithPartialName("PresentationCore") | Out-Null
[System.Windows.Media.Fonts]::GetFontFamilies("C:\Windows\Fonts") | ForEach-Object {
 foreach ($face in $_.GetTypefaces()) {
  $glyph = $null
  $face.TryGetGlyphTypeface([ref]$glyph) | Out-Null
  if ($glyph -and $glyph.CharacterToGlyphMap.TryGetValue($charId, [ref]0)) {
   $_.Source.Split("#")[1]
   break
  }
 }
}

To use it, you'll need to save it as a PowerShell script (.ps1). Before PowerShell will let you run scripts, the script policy must be set to Unrestricted by typing this at the prompt:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Then, the script can be invoked by typing .\ followed by its filename, then a space, then the character to search for. (Right-clicking anywhere in the PowerShell window pastes the contents of your clipboard onto the command line.)

.\fontcheck.ps1 ä½ 

Sunday, January 10, 2016

Command-line locking

While looking around for command-line Terminal Services management tools, I discovered tsdiscon. Running it causes the workstation to, essentially, "switch user." Strictly speaking, it disconnects the Terminal Services session, so it would disconnect a Remote Desktop session if run under one.

Interestingly enough, this utility seems to not follow Microsoft's tendency to have programs in system directories not do anything without command line parameters. (People liked to click around in their system folders and accidentally do bad things.)

Saturday, January 9, 2016

Robotics - Volunteering Again

Today I volunteered at an FTC league meet, my second FTC volunteer role. This time, I was assigned two roles, Field Inspector and Field Resetter. That was an upgrade from my previous role of Pit Runner.

Field inspection is the process of checking the teams' robots for use in the actual competition. So, the checklist primarily involved verifying communication between the two phones (driver station and robot controller) and testing movement control. We ran out of inspection checklists at one point, but I had a laptop with the PDF version of the rulebook, so I printed some more. The inspection phase was the first three hours of the meet.

The other three hours were the actual matches. One of the game elements is the spread of small plastic cubes and balls across the playing field. My job was to toss a box of these things onto the field before each match and pick them all up afterwards. That last part was made a little tricky by the necessity of splitting the debris pool into two equal collections and throwing one from each side of the field for best uniformity.

Along the way, I helped address some simple questions of team members so that referees didn't have to deal with them.

My legs are sore from all the standing, but I'm glad I helped with the event.

Friday, January 8, 2016

Changing Partition Types with DiskPart

DiskPart and the Disk Management snap-in note for each partition its type - "Recovery", "EFI System", "Primary", etc. For GPT (GUID Partition Table) disks, these partition types are identified by - you guessed it - GUIDs. DiskPart makes it possible to change the type, if you direly need to do so.

Run diskpart from an elevated command prompt and select the desired disk and partition. Then issue set id= followed immediately by the GUID (without braces). For example, this changes the selected partition's type to EFI:

set id=c12a7328-f81f-11d2-ba4b-00a0c93ec93b

Other types:

  • Normal: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
  • Recovery: de94bba4-06d1-4d40-a16a-bfd50179d6ac
  • Reserved: e3c9e316-0b5c-4db8-817d-f92df00215ae
(Note that it may not be possible to change an existing partition's type to Reserved, according to the "set id" technical reference. If you're really intent on making a partition have the Reserved type, see the dangerous part of my Super User answer on the subject.)

Each partition's attributes/flags can be changed with the gpt attributes= command. Its current attributes can be seen with as part of the detail partition output.

Thursday, January 7, 2016

Fleex's Lab: Best of 2015

It's been 2016 for a while now. As we head into the new year, let's review what I believe to be the most interesting articles published on this blog in 2015:

Wednesday, January 6, 2016

LoadImage: Not all bitmaps accepted

I discovered via the comments on my ContextIcons project that the LoadImage function apparently doesn't treat all BMP files equally. Specifically, the function doesn't seem to like unusual DPI, i.e. not 96 pixels per inch. A certain piece of software the comment author used produced bitmaps that were unacceptable in some way; I had success with the standard MS Paint.

It's also worth noting that some of the flags, like LR_LOADTRANSPARENT, only work for images that have less 8 bits per pixel (256 colors). In the compiled version of my DLL, I had set LR_DEFAULTSIZE, but that might not have been a good idea, since it seems to depend on some system configuration that isn't related to the bitmap's actual size.

Tuesday, January 5, 2016

ContextIcons: Set icons for standard Windows context menu entries

Yesterday, I answered a Super User question that asked how to add icons next to "Copy", "Paste", and other standard Windows Explorer context menu items. I solved it by creating a shell extension that looks through the existing items and injects icons into the appropriate ones.

I was asked to put it on GitHub, and since I was publishing the source anyway, I thought that was a pretty good idea. So I did: it's called ContextIcons. The interesting stuff is in IconInjector.cpp. Building it is pretty easy; just open the SLN file in Visual Studio 2015 after installing the C++ tools and do Build | Build Solution.

Monday, January 4, 2016

GetMenuItemInfo Surprise: Text Length Reported in Characters

I found myself wanting to retrieve the text of a menu item with the GetMenuItemInfo function. The first thing that I noticed was that getting the text required the classic Win32 dance of "call the function, see how long the text is, allocate a buffer, call the function again." (I'll have you know that such dances are exceptionally painful with PInvoke, but at least I was writing in normal C++.) Basically, this function's first call produces the length of the buffer via the ccb member of the menu item information structure.

The surprise came when I found that the heap was corrupted after the second call of GetMenuItemInfo! It turns out that the length is reported in characters, not bytes, which is super misleading and not noted anywhere, as far as I can tell. (All the examples on the Internet always allocated a buffer of 256 bytes, which is a bit wasteful.) So, rather than allocating a buffer of ccb + 1, you need a buffer of (ccb + 1) * 2 thanks to the wideness of the characters in LPWSTRs.

Sunday, January 3, 2016

ATL Surprise: GetCommandString Declaration Changes Based on Bitness

I am trying to learn how to write Windows shell extensions. I initially wrote something that compiled to a 32-bit DLL, but then I realized that since 64-bit programs (like Explorer) can't load 32-bit DLLs, my plan had no chance of working. So I switched Visual Studio to produce a 64-bit DLL, but then I got a build error:

'ATL::CComObject': cannot instantiate abstract class in atlcom.h, line 2000

I was very confused, since that error wasn't even in my code.

It turns out that the declaration of GetCommandString (one of the context menu handler functions) changed in the move from 32- to 64-bit. Its first parameter becomes a UINT_PTR instead of just a UINT. Somehow, that discrepancy confused ATL.

If, for some reason, you want to be able to easily compile for both 32- and 64-bit platforms, you'll need to use some #ifdef preprocessor statements to adjust the signature appropriately.

Saturday, January 2, 2016

Changing Windows API Functions from .NET with EasyHook

A while ago, I attempted to suppress a certain annoying behavior of a specific program by blocking the Windows API call that produced it. I was not successful, but I learned how to use an interesting tool called EasyHook. EasyHook is a .NET library that makes DLL injection and hooking very easy. Its only major shortcoming is the complete lack of examples (though it does have a nice API reference).

To use EasyHook, you need two parts: an EXE program to do the injection, and a DLL to contain the hook code. Both need a reference to EasyHook.dll, and both processes (your EXE and the target's) need access to the other assorted EasyHook resources.

If you don't need to pass any information to the injected DLL (e.g. you don't communicate between your EXE and the DLL because your EXE exits after doing the injection), then you can just do this in your program:

RemoteHooking.Inject(procId, InjectionOptions.DoNotRequireStrongName, hookDll, hookDll, {})

procId is the target process's ID; hookDll is the full path to the .NET DLL that contains the hooks. Your DLL should contain exactly one type that implements IEntryPoint, and it must have a constructor that takes a RemoteHooking.IContext. You don't need to do anything there unless you want to do some preliminary setup, like connecting to your controller program. The IEntryPoint implementation must also have a Run method, again with a RemoteHooking.IContext.

In Run you can set hooks. First, however, you'll need to declare the prototypes of the functions to be hooked, placing them in your DLL as delegates with the UnmanagedFunctionPointer annotation. Create replacement functions with the same signature as the respective delegates. Then create a hook with LocalHook.Create, like this:

Dim Hook = LocalHook.Create(LocalHook.GetProcAddress(targetLib, targetFunc), New YourDelegateType(AddressOf YourHookFunc), Me)

targetLib is the DLL name containing the replaced function, targetFunc is the name of the function; YourDelegateType and YourHookFunc are what the names say.

Note that this will not work for COM methods, which is why my attempts failed.

Friday, January 1, 2016

Always let "Open in new tab" work

Since it's New Year's Day, I've started looking for my best posts of 2015. To do that, I held down Control while clicking to open the list of posts in Blogger in a new tab so I could drag it onto my second monitor (yay for tearable tabs!). I noticed immediately that it did not open in a new tab.

Once I actually right-clicked the object, I saw that it was actually just a normal div, not a link, so only JavaScript was responsible for opening the page. Still, that's quite unfortunate, since it looks like it should be a link - it goes to a different page, after all. Whenever websites stop me from doing normal web things, I subconsciously feel appalled.