Sunday, May 31, 2015

FMod - Psychedelic Find Tool Redesign

Yesterday, I made some changes to the File Emitter that make it a lot nicer to work with. Previously, the output folder had to be specified before it would do anything. That field is now auto-filled with the current directory, but it can be changed just like before. Some visual tweaks were made to the list view that make the user feel more in control of what's going on.

Today, I made some changes to the Essential Manipulator. Holding the Control key now hides the paste preview overlay so it's easier to see the level when about to start copying. (This change was actually made in PastePreviewRenderPlane, so it applies to the Paster as well.) Also, the EM now keeps a record of the tiles it has modified in the current drag-place operation and checks it before putting down the stamp; it's kind of like TOM's snap paste mode but lets you make more interesting patterns. (Abiathar intelligently checks for collisions with already-modified tiles, not grid alignment.)

I realized that the Tile Instance Locator was pretty lame. It was a tool that duplicated (poorly) the editing capabilities of the Tile Picker to allow editing while seeing where there are instances of the selected tiles. So, it was impossible to perform more advanced operations (rectangle fill, replace, essential-manipulate) and get the find highlights at the same time.

I decided to remove the Tile Instance Locator and add a "find" view option instead, like TOM has. This is implemented as an ephemeral rendering plane on all levels, which is notified by the Abiathar core when tiles are placed, the current level is switched, or a different tile is selected. (There are still some kinks to be worked out with situations in which the overlay is disabled, changes to the level are made, and then the overlay is re-enabled.) It seems to be working well; since all tools notify the core of changes to levels, getting the notifications collated was pretty easy. The count of instances now appears in the status bar rather than the tool information place in the lower-right.

It was slightly harder to pick a color for the overlay that isn't confusable with the selection overlay but is also easy to see on all 16 EGA colors. I tried lots of colors, but none of them stood out on top of every possible game color. So, I added a fun feature: clicking the instance count label in the status bar causes the overlay to enter pulse mode. The overlay changes color between a red and a green two times per second in this mode, making it easy to see where there are instances of the selected tile. It's pretty psychedelic and exciting. (I'll record a video soon so you can see it in action, once I work out all the bugs.)

A crash bug involving graphics reload was fixed by forcing all extensions to re-register new instances of their tools when the graphics cache is destroyed.

Saturday, May 30, 2015

Gash - Font Success

Today I finished up the export part of the NextGenGraphics class that will form the core of Gash. This required parsing the font chunks, which fortunately are documented on ModdingWiki. The EGA version of the exporter was very easy; the format in that article is correct. (I did run into a surprise with VB.NET while coding that: non-explicitly-initialized variables inside a loop retain their values across iterations.)

The CGA version was a little trickier. CGA font chunks apparently use what that article calls the version-1 format of fonts, so there are two bits for every pixel. That is, the font chunks are really just a bunch of standard CGA pictures jammed together, whereas EGA fonts are a single plane of EGA data.

I also wrote simple exporters for text chunks (becomes a String) and miscellaneous data chunks (becomes a Byte array). Next, I'll see about importing.

Friday, May 29, 2015

FMod - v2.5.5

Yesterday while helping a new modder with Abiathar I discovered two bugs: the ADEPS file would stop being recognized if there were blank lines in a list, and that bitmap files were held open as long as Abiathar ran. Today I fixed these issues, plus three more:

  • The New Project Wizard no longer erases the value of BackTileCount and ForeTileCount when EGA loading is disabled (wasn't a super horrible problem, but inconvenient)
  • The auto-generated, compiled patch files are now formatted nicer. Before, they looked a little strange due to the random-looking placement of blank lines.
  • The tool information text for the Paster and Essential Manipulator is now updated properly when the Palette Copier is used. This problem was only caught after I had released the previous fixes as v2.5.4, so I had to put up a v2.5.5 to address this. (Thorough testing is important!)

Thursday, May 28, 2015

Gash - CGA Success

I did lots of work on Gash today, meeting with much success. I finally got the GetPixelData and GetLowColorBitmap functions working with CGA graphics. The trick was that CGA places the full mask of the image before the image itself, with 2 instances of the mask bit per pixel. I had also completely forgotten to add unmasked support in GetLowColorBitmap, so that also caused issues when loading background tiles.

NextGenGraphics can now extract sprites, tiles (background and foreground), pictures (masked and unmasked), and the 8x8 tiles. The small 8x8 tiles were a challenge because all of them are stored in one chunk. I wasn't sure how to get the individual tiles out because there's no information on that in the ModdingWiki and the GalaxyGraphics code is super horrible. It turns out that the small tiles are just 8x8 pictures in the usual format all pushed up next to each other. That is, extracting a single one doesn't require any shuffling of chunk-wide planes, just grabbing a section of the chunk and treating it as a picture.


Another interesting fact is that the CGA version of Keen 4 has one fewer font and one more picture to fill that chunk. The extra picture seems to be a placeholder; it's just a pink square with a blue edge on the top and left. (Probably to make sure all the other chunk offsets don't get messed up from the font removal.)

All the extraction routines work for EGA graphics also. No bit twiddling is actually done until the image is called for, so the initial load is very quick.

All that's left to do in the core is extract fonts and miscellaneous resources, then figure out a way to put back modified graphics. I'm still looking into VGA support; it seems pretty tricky thanks to an extra (non-VGAGRAPH) file that holds the sprites.

Wednesday, May 27, 2015

Gash - Sprite Extraction

Today I wrote two important routines for the NextGenGraphics class in FleexCore: one to transform raw decompressed chunk data into a 2D array of pixels representing color, and another to transform that array into an instance of LowColorBitmap.

The EGA (planes shuffled) version of these functions is working perfectly. After writing the getter for the Sprite property on NextGenGraphics and throwing together a quick test program, I am able to dump out all the sprites of Keen 4 into a collection of transparent PNGs:


The CGA and VGA (normal bit arrangement) version of these functions is not working so well. Even when I finally figured out exactly where the offset table (header) and Huffman dictionary is in the CGA version of Keen 4, I'm just getting garbled versions of the sprites:


It looks like the mask is actually after all the color data, not interleaved with it like I assumed. There's also some sort of horizontal duplication and overall squishing going on, but I'm not sure what's causing that.

Tuesday, May 26, 2015

Beeping from Windows Batch

It may, from time to time, be useful to create a beep or notification sound from a Windows batch file. You could launch some lightweight media player pointed at a simple sound file, but that's way overkill. Just insert ASCII character 7, the control character called BEL (bell). The command processor, when printing text, produces a beep upon encountering that character, printing no visible representation of it.

While typing in a copy con prompt or when echoing to a file, use Control+G to create the character (it will appear as ^G on the command line).

In Notepad and most text editors, hold down the right-hand Alt key while pressing 7 on your numeric keypad (with NumLock on). This will create a character that looks like a big dot.

Your batch file will end up with something like echo •. When the command processor executes this line, a beep will be made. On Windows 8 (and possibly other versions after Windows XP, which I know does the standard DOS-like beep), this actually produces the OS-standard message box sound. Either way, you'll hear something.

Monday, May 25, 2015

Windows 10 Family Safety: Missing in Action

Today I was tinkering with the latest stable build of Windows 10 (number 10074). I tried to create a child account to explore the Family Safety options, but I found that the "Child" option was missing from the account type drop-down. The "Create a child's account" link in the Accounts control panel just created a standard user account.

Some poking around on the Microsoft support forum-y thing confirms that Family Safety is temporarily disabled in current builds of Windows 10. They're improving it and/or building something better.

(I tried upgrading to the latest fast-ring build, number 11something, but now the computer constantly blue-screens a few minutes after booting up. Hm.)

Sunday, May 24, 2015

Windows 10: "Who owns this computer?"

Today I upgraded all my Windows 10 stuff - the server and the normal client/PC OS - to the latest build, number 10041, called Windows Server Technical Preview 2 for the server. (It has also become known that said server OS will be called Windows Server 2016.) The server update is very nice, and I look forward to playing with it more.

When upgrading to build 10041 (Pro edition) on the client via WDS, I ran into an interesting screen while going through the OOBE. It asked me "who owns this computer?", me or my organization. I did some Googling, and apparently it will try to do a bunch of Microsoft account and OneDrive stuff if you say you own the device. I didn't test that; it blue-screened (KMODE_EXCEPTION_NOT_HANDLED) while I was deciding.

When I logged in after it came back up, I chose "my organization" because I wanted it to be domain-joined. (WDS should have already done that, so I'm not sure what was going on.) However, it then showed me a screen of text explaining when and under what circumstances I should join it to a domain. Again, I thought that was weird, because it already was domain joined.

I guess they didn't test this build's interaction with WDS all that much. I still don't know what those screens were talking about.

Saturday, May 23, 2015

Gash - Masking Understood

A while ago, I had a conversation on IRC with a programmer in the Keen community who has some experience working with the CGAGRAPH format used in the CGA distros of some iD games, which I would like to support in Gash.

While starting out on the rewrite of FMod/FleexCore2's GalaxyGraphics class, I quickly ran into a problem: non-EGA formats use a sane human's intuitive expectation of bit layout for each pixel. Rather than the EGA business of having all the red bits, then all the green bits, etc., the others have all the bits necessary to represent one pixel right next to each other. (Makes sense.) The problem is that such a scheme seems to require a non-factor-of-two number of bits per pixel in masked graphics, e.g. 3 for CGA (color, intensity, mask). That would be a problem because handling constantly-shifting non-byte aligned bit sequences is a huge pain and, as far as I know, not done in the actual game.

This community member and I, after some poking around, discovered that non-EGA layouts have a fairly obvious but also clever fix for the byte alignment problem. Rather than CGA doing this:

cimcimcimcimcimcimcim...

(Color, intensity, mask; respectively. The underline shows byte boundaries.) It does this:

cimmcimmcimmcimmcimmcimm

The mask bit is duplicated, rounding out the pixel representation to 4bpp. VGA does something similar, guzzling 16 bits per pixel! (Eight for the actual color, and eight instances of the mask bit.) Also, I learned that VGA games tend to keep only the UI/menu bitmaps in VGAGRAPH; the game pictures and sprites are in another file.

Armed with this knowledge, and lots of summer free time, I'll be able to create the most versatile xGAGRAPH manager the Keen community has seen.

Wednesday, May 20, 2015

A weird UI thing in Windows 8's Explorer

I'm currently in the process of generating a huge file and blasting it across the network to a Windows share. On the machine at which the file is appearing, I sometimes press F5 on the Explorer window to see how much has transferred so far. I noticed while madly mashing that key that if I press it a few times really fast and then hold it for a few seconds, the items under "Select" in the Home tab of the ribbon will become disabled until I release the F5 key. The file size doesn't update continuously, though.

Tuesday, May 19, 2015

WCF Surprise: ServiceBehavior Does Nothing on Callback Classes

Today I was debugging an issue where a service calls a client (duplex situation) which calls a different method on the server. It was always failing with an InvalidOperationException on the client despite my having placed ConcurrencyMode:=ConcurrencyMode.Reentrant on the client class... or so I thought.

I had placed that attribute in a ServiceBehavior attribute on the client class that implemented the callback interface. However, when I read the error message more thoroughly, I saw that it mentioned CallbackContract rather than ServiceContract. Changing the class's attribute to CallbackBehavior made everything work fine. (CallbackContract goes on the interface.)

Interestingly enough, it partially worked before - the channel opened fine and the server could call methods on the client. I guess WCF just ignores the settings in ServiceContract on callbacks. So, don't use the "service" attributes on callback/client types; use the attributes specifically designed for callbacks.

Monday, May 18, 2015

Careful of Windows Vista Ultimate's Optional Updates

Windows Update is a really nice thing, and I usually make sure to get all the updates, including optional ones. However, I was using a Windows Vista Ultimate computer the other day, and I noticed something weird when I went to update it. The list of optional updates is full of completely unnecessary stuff like language packs for every language I've ever heard of, plus some game-ish things that somehow add value to Vista.

I had to carefully go through and pick out the updates that actually update Windows. I'm not sure how to banish the language packs, but I know you probably don't want them - so don't hit the select-all checkbox in the optional updates list.

Sunday, May 17, 2015

The Programmatic Version of NTRights.exe

I was curious today as to the implementation of NTRights.exe, which comes in the Windows Server 2003 Resource Kit and is essentially the command-line version of User Rights Assignment. I did some research, and discovered these Lsa-prefixed Windows API functions:

  • LsaEnumerateAccountsWithUserRight gets the list of principals with a given right (like viewing the properties of a privilege in User Rights Assignment)
  • LsaAddAccountRights adds a principal to the list of things with a given right (like adding it to the list in URA). It will also create an account with the provided SID if it does not exist.
  • LsaRemoveAccountRights strips a principal of a given right (like removing it from the URA list). It can also be used to delete an account if you pass a special flag.
They all look really gnarly to use in .NET with P/Invoke, but CodeProject does have an article on using LsaAddAccountRights from C#. (Careful: some comments on the article say it has some bugs.)

Saturday, May 16, 2015

Abiathar: From Fresh Install to Playing Modded Levels In-Game in 10 Minutes

It's been a while since I've updated the Abiathar help file (I really should get on that), and the video tutorials are aging rapidly as well. So today, I recorded the pilot episode of a new Abiathar video tutorial series. I start fresh with a clean install of Abiathar and a ZIP of the original Keen 5 files and in 10 minutes - all captured live - I have created an Abiathar project, toured its most basic functionality, tweaked a level, and have it running in DOSBox, patches and all.

My last attempt at an Abiathar tutorial series tried to jam a bunch of unrelated concepts into one video to fit my standard 15-20 minute time frame. This series will be much more focused, task-oriented, and "bite sized" so people can see only what they need.

Thursday, May 14, 2015

Fixing the High DPI Alignment Issue

Yesterday, I gave up on aligning Windows Forms controls at high DPI. Today I found a (fairly simple) solution. My problem was that I had been too insistent on a design-time solution rather than the addition of some code to fix it up at runtime.

All I wanted was to make the right edges of the Label and LinkLabel line up. That is, I wanted to assign Rlabel to Rlink. However, the Right property of controls is read-only; I can only modify Left and Top. A little bit of algebra got me the simple formula:

Llink = Llabel + Wlabel - Wlink

Or simply:

Llink = Rlabel - Wlink

And in code:

LinkLabel.Left = Label.Right - LinkLabel.Width

The link is now aligned properly at all DPI levels accessible in Windows 7, with only one line of code added to the form's Load handler.

Wednesday, May 13, 2015

DPI Frustration

Yesterday I tested my Windows Forms application at a high DPI setting and discovered that it got completely messed up at that scale. I did some Googling, and learned that I had to remove the form-wide font setting because it caused a reset of all child controls' sizes. Once I set my preferred font face (Segoe UI) on all the individual controls, the form looked a lot better.

However, there was a misalignment involving a Label and LinkLabel, anchored to the bottom-right of the form. The Label was on top, with AutoSize set to False because its text had to be changed at runtime. (Right-anchored auto-sized Label controls get messed up when their text is changed.) Under it was the LinkLabel, which was horizontally aligned with another LinkLabel on the other side, at the bottom-left. Both LinkLabels are auto-sized. The problem was that the LinkLabel - only the one on the right side - got pushed to the left at high DPI.

I tried making the LinkLabel non-auto-sized, but that caused its underline to be clipped off at high DPI. Making the control extra-tall would create undesirable extra spacing between it and the Label immediately above. (They go together.)

I then tried a TableLayoutPanel. I gave the top row - the one containing the fixed-size Label - a fixed height, and let the bottom row with the LinkLabel auto-size. That fixed the horizontal alignment, but the TableLayoutPanel shifted up at high DPI, removing the horizontal alignment between the two LinkLabel controls. No amount of Anchor adjustment helped.

My current resolution is to accept the non-alignment of the Label and LinkLabel and go with the simple initial arrangement. It doesn't look terrible, and it only happens at high DPI. I might have to consider WPF if I run into worse issues.

Monday, May 11, 2015

What's the deal with that Enterprise Admins group?

If you've poked around in Active Directory, you may have noticed two super-powerful groups that seem pretty similar: Domain Admins and Enterprise Admins. The default Administrator account is a member of both. They seem fairly similar, but there are some important differences that I will illuminate here.

First, Enterprise Admins is only created in the root domain of the forest. (In my opinion, it should be called Forest Admins.) Users that are Enterprise Admins are Enterprise Admins no matter where they go in the forest. Domain Admins are only Domain Admins in their own domain (and possibly child domains? I'm not sure). The Domain Admins group is created in each domain. However, none of this is at all noticeable unless you have one or more sub-domains.

If you look at the list of local administrators (in the "Local Users and Groups" MMC snap-in) on a domain-joined workstation, you'll see the Domain Admins group listed, but not Enterprise Admins. That means Domain Admins can administer all domain machines, but Enterprise Admins can only deal with the Active Directory. (Every securable Active Directory object allows the system and Enterprise Admins (and to some degree the appropriate Domains Admins instance) full control.) Careful though, Enterprise Admins can easily add themselves to the Domain Admins list of any domain in the forest.

There is one more administrative/powerful group, simply named Administrators. It is created in each domain in a forest. Enterprise Admins, Domain Admins, and the default Administrator account are the default members. This group is actually used as the local administrator list on all domain controllers in the domain. That is, membership in this group allows users to log into domain controllers and UAC-elevate. (Unlike Server Operators, who can only log on to domain controllers. Also very much unlike normal users, who can only log on to Domain Computers, not ENTERPRISE DOMAIN CONTROLLERS, which are clearly really important because the group's security principal name is in all-caps.)

So, in summary, Enterprise Admins are powerful forest-wide but aren't by default counted as local admins on domain workstations.

Sunday, May 10, 2015

Visual Studio Git Integration

I noticed while working on Abiathar Online that Visual Studio 2013 (the Professional version at least) automatically integrates with the Git version control system. I created a solution file inside a folder managed by GitHub for Windows and noticed that all the files had little marks next to them indicating their status in Git. The Team Explorer actually does something - I can create commits and perform synchronization without having to actually open the GitHub program. Git-related actions such as Commit have been added to the context menu of items in the Solution Explorer.

This is all really convenient, and I have one more reason to love Visual Studio.

Saturday, May 9, 2015

Windows Automatic Update Settings Also Control Windows Defender

A few weeks ago, I finally got tired of automatic restarts wrecking my workspace while I was AFK, so I changed my Automatic Updates settings to download updates, but not install them until I told it to. This has been working well.

The funny thing is that Windows Defender also seems to be controlled by that setting. Rather than updating itself automatically (which doesn't require a restart), it throws up a notification balloon saying that virus/spyware protection is out of date. It doesn't update until I click that balloon, which opens Windows Defender, which causes it to start the definition update installation.

I really wish there was a separate setting for Windows Defender, or even a setting to allow auto-installation only of updates that don't require restarts. Currently, I have to click a little balloon once or twice a day to keep my malware definitions up to date.

Maybe I'll mess with the local Group Policy to prevent the automatic restart when I'm logged on.

Friday, May 8, 2015

Transferring Large Amounts of Data with WCF

I found myself wanting to send the contents of a fairly large file (specifically a ~100MB MSI installer) via WCF. However, the call to the method of which the byte array was a parameter always failed with a TimeoutException, but thrown almost immediately, much quicker than the one minute it allegedly waited.

The problem was not a timeout but WCF's on-by-default DoS protection. I'm very concerned about security for this application, but the large data transfer was from the server to client, never the other way around. So, it's alright for the server to be able to flood the client with data, because clients are voluntarily connecting to the server.

The fix is to increase the ListenBacklog and/or MaxBufferSize on the NetTcpBinding. (They may also apply to some of the other bindings.) That allows larger amounts of data to be received in one shot.

Thursday, May 7, 2015

Forcing Spaces to be Preserved

Some web-based text editors (especially e-mail clients and forums) have an unfortunate tendency to destroy extra spaces when text is pasted in. So something like this:

\  /-----\
 > |  !  |
/  \-----/

Would become smushed like this:

\ /-----\
> | ! |
/ \-----/

This is obviously a serious problem for hand-aligned tables and other monospace text, which as a programmer, I deal with on a semi-regular basis.

Fortunately, there is a (fairly ugly) workaround that forces extra spaces to be preserved... in a way. The 255th ASCII character typically renders as a blank space, but is of course not the same as character 32, the real space.

To convert spaces in some text to these fake spaces, open a Notepad window, paste your text (danger: may destroy carriage returns if the source uses only LF rather than CR-LF; use Word or Notepad++ if appropriate), open the Replace window, type a single space in the "find" field, insert character 255 in the "replace with field" by holding the right-hand Alt key while typing 255 on the numeric keypad with NumLock on, and choose to replace all. Paste the text into the space-eating text field, and you'll find it remains intact.

Careful: this will wreak havoc if pasted into a code file or if the file is textually transcoded.

Wednesday, May 6, 2015

Why a Remote sc.exe Invocation is Slow

A few weeks ago, I was using sc.exe to manage services on a remote machine in the same domain. The problem was that it was super slow - every call took about 30 seconds. I would have loved to use Remote Desktop, PowerShell, WMI, or really anything else, but the firewall was blocking all those things and I didn't want to open any ports unless absolutely necessary. (The RPC Endpoint Mapper was already open, which is why SC worked at all.)

After placing a 50-rep bounty on a Server Fault question, I learned that it was indeed the firewall causing this issue. The answer said that I should do some registry tweaking to change the RPC dynamic ports to something that can go through my firewall. I wasn't all that jazzed about tweaking the registry, but that answer did inspire me to my own solution, which I posted as an answer in that same thread.

Windows Firewall can open just the dynamic RPC ports, which shouldn't be bound to any application and so not much additional attack surface will be exposed. Since SC apparently uses a dynamic port that it negotiates with the RPC Endpoint Mapper, I'm not sure how it worked at all (maybe it timed out at each port and counted up until it found an open one?), but opening the dynamic ports made SC super fast even across the network.

Tuesday, May 5, 2015

Windows 10 Server Makes a Comeback

I previously wrote that Windows 10 Server was missing in action. A day or so after the expiration date, my installation stopped showing any signs of being expired. I haven't rebooted it or noticed a restart since then, though, so I'm guessing they somehow removed that expiration enforcement. (Maybe there was a Windows update?) Anyway, that's been working just fine for me the past few weeks.

More interestingly, they seem to have come out with a Windows Server Technical Preview 2. I received an e-mail today (four, actually, and they were all the same) with a link to the TechNet Evaluation Center where the new version can be downloaded. There's also a collection of semi-serious issues in the release notes, but nothing that looks show-stopping.

I'll only install this new version if the original one threatens to expire again. My current set-up works just fine, and was challenging enough to set up once.

Sunday, May 3, 2015

When Visual Studio is Missing Target Frameworks

A week or so ago, I noticed that I had a bunch of old versions of Visual Studio installed. Since I certainly don't need VS from 2008 or 2010 (I have 2013 Pro), I removed out the extra installations in the normal Control Panel way. However, I found that removing VS2010 seems to have removed my ability to target version 4.0 of the .NET Framework. That's a serious problem, because Abiathar must be built for .NET 4.0 (woo, Windows XP compatibility). When I open a solution involving those projects, Visual Studio asks me to either change the project target version or cancel the project load. The ".NET Framework 4.0" option has of course vanished from the target framework drop-down.

I'm currently in the middle of a repair on the Visual Studio 2013 installation. That can be accessed by starting the VS2013 uninstaller in Programs and Features, then choosing Repair on the start screen. Hopefully this will work, otherwise I may need to do a full reinstall.

Friday, May 1, 2015

DPI Awareness in WinForms

You may have heard of a thing called DPI. In a literal sense, it means "dots per inch", but in the UI world, it affects the scale of your form elements. If you design a form at a certain scaling level but it's used at a different level, there's a chance you'll get ugly overlapping UI elements.

In .NET, DPI awareness is governed by the AutoScaleMode property on container controls (things like Form or Panel). If you set that property to Font, scaling will happen relative to the font size, which is usually what you want. I'm not exactly sure what the Dpi option does (MSDN says it scales relative to the system DPI setting, which sounds nice), but I haven't tried it.

I've also heard that layout panels like TableLayoutPanel or FlowLayoutPanel help with DPI scaling issues, but I haven't made serious use of them either.