Category Archives: Programming

Solved: Keeping Windows Forms from Resizing when Dragging them to a Monitor with a Different Resolution

Standard disclaimer: This is one of those “how to overcome an incredibly geeky tech problem which has been bedeviling me forever” posts. It’s meant as a virtual breadcrumb for anyone who faces a similar issue. If you find it and it helps, please give it a “like”. If this isn’t the sort of thing that interests you, by all means skip on to the next comic, music, or pop culture-related post.

Anyone who’s ever done Windows Forms coding knows what a pain in the nether regions it’s been to get windows and type to properly handle monitors with different resolutions. (I wrote about it years ago here)

Things got substantially better with the introduction of .Net Framework 4.7.2, which started to make it possible to properly scale things when you had multiple monitors with different resolutions. Still, there were certain actions–such as dragging a screen from a hi-res 4K monitor set to 150% magnification to a regular monitor set at 100%, that would give results like this:

Dialog as it appears on the 4K monitor, set at 150% display scale

…becoming this

Same window, when dragged to a monitor set at 100% display scale

…when dragged to the adjacent 1080p monitor, whose display scaling was set to 100%. Note the sea of white space at the right and bottom. This occurs even when there is no program code to setup the window.

Worse, when dragging the window back to the original monitor, the white space remains–or even grows (in some cases, enough so that repeatedly dragging the window back and forth fills the entire screen).

Granted, it’s possible to manually compute your own window scaling factors, and resize and scale every element as necessary whenever the form was moved, but this is beyond tedious in practice–and it makes dragging forms around both slow and ugly to boot. You also need to test that you’ve handle any screen DPI switches that happen simply when the user switches up their display settings in the control panel–another can of worms.

Setting both monitors to the same scaling factor removes the problem, but that’s also not really a solution.

So what is the solution? It turns out it’s two things: one of which makes sense, the other which appears to be a bug in .Net’s rendering algorithm.

  1. The default setting of any Windows form’s “AutoSizeMode” property is “GrowOnly”. This needs to be overridden on every form to be “GrowAndShrink”.
  2. The culprit behind the growing white space, however, was the anchor property of the bottom buttons(!). One might reasonably assume that since the action buttons are meant to be placed dependent on the position of the lower-right of the window, that anchoring them to the bottom-right of the form makes sense. (This is exactly what you’d do if the window was capable of resizing: you’d always want the buttons to ride at the bottom-right of the form).

The bug apparently comes, however, in that setting the buttons to be anchored to the bottom right of the form messes up .Net’s calculation of how large the form should be when moved between windows of different dpi/scale. .Net seems to effectively scale up the form according to the old dpi setting, peg its boundaries at where the anchored items would be, then re-lay it out according to the new monitor’s dpi–leaving the white space you see there.

The solution? On any fixed size form, avoid anchoring any elements to the bottom or right of the form.

It took a long time to figure out what was going on and fix it. Now I just have to check over about a jillion dialogs and forms in ComicBase, and my next Livestream (which inevitably involves showing something on my secondary monitor which was dragged over from my 4K primary monitor) should go a little smoother…

Bickford’s Law for Large Project Development

If you haven’t tested a particular part of your project recently, just assume you did something to the rest of the project which broke it.

Crystal Reports 2016: Worst Installer. Ever.

It takes a lot to get worked up about a program’s installer for goodness sake, but Crystal Reports 2016 has one that’s so problem-ridden and buggy that it could drive a Zen monk to acts of random mayhem.

As ordered directly from the company, the program comes without apparent documentation, merely a big “click me to install” executable download of some 800 MB. After the giant download, you see a single a clickable installer .exe file. Double-clicking this in turn kicks off a giant-self-decompressing archive…which after several minutes, presents you with… an incomprehensible error message saying: “Fatal Error: At least one port in the range 4520-4539 must be open for the installation to proceed. Please ensure that no application or firewall is blocking this range.”

“Wow! I had no idea my firewall was blocking those ports, but let’s check…” and then an hour or more of checking security software, network settings, and firewalls commenced across both my own computer, my wireless router, and even my cable modem. All in vain. Because the error message had nothing to do with the actual problem.

What was the problem? Apparently something path-related, because it turns out that the (impossible-to-guess) solution was that the installer had to be located at the top level of the C: drive in order to work.

And even this is problematic: remember how launching the installer kicks off a self-decompressing archive? It turns out that there’s no user control over where those files decompress to (presumably someplace in the %TEMP% directory). It’s not even sufficient to copy the installer.exe file to your C: directory–you need to hunt down the decompressed files and copy them there. The easiest way I’ve found to accomplish this is to use 7-Zip, right-click on the installer.exe file, and tell it Extract the contents of the .exe file to your C: drive. After that, the program will actually install.

“Oh my goodness” you might be saying. “That sounds like some hacky installer implementation that must have caused all manner of tech support calls, and surely was the first thing SAP (the maker of Crystal Reports) fixed after release!”. If so, you’d be wrong. Indeed the exact same force-compress and moving of the installer files is necessary for the Crystal Reports 2016 Service Packs (Currently on Service Pack #4!).

Unbelievable. Did SAP actually intend to sell any copies of this $495 program? Or were they trying to kill off its user base in the most passive-aggressive way possible by making it nigh-impossible to install?

Getting Started in Xamarin Forms with Visual Studio 2017: Why Your First App Won’t Compile or Deploy

Visual Studio 2017 was just released with much fanfare, and if you work in the Windows world, your set of tools just got a major upgrade. One of the biggest toys in your new toolbox is the built-in support for Xamarin–a recent acquisition of Microsoft’s, and whose technology allows developers to write an app in C# that will deploy and run natively on iOS, Windows, and Android mobile devices. This is Really Big Stuff, and a technology which we’ll be spending a lot of time with in the coming years.

One of the more surprising aspects of the new Xamarin Forms support in Visual Studio 2017, however, is that the built-in templates for Forms-based projects don’t actually compile(!). These are the “Hello World” apps which are there to get novices (such as ourselves) started, so not being able to get them to… you know… work… is sort of unnerving.

After a couple of weeks dealing with Xamarin, here’s a few tips on how to get that first app running under Windows, using the Community edition of Visual Studio 2017. Hopefully Microsoft will fix much of this soon, but in the meantime, this article is for anyone who’s also getting their feet wet with Xamarin is might be getting flustered by the constant stream of errors standing between themselves and “Hello World”:

  1. You’ll likely need to install a new Windows SDK, or you’ll get errors when targeting different versions of Windows UWP. As soon as you choose to create a new “Cross Platform” project (iOS/Android/Windows), Visual Studio will go through the work of creating separate sub-projects for each one of these platforms. When it hits the UWP (Universal Windows Platform) one, you’ll be presented with a dialog asking you which version of Windows you want to target, and which level is the minimum you’ll support. Whatever you choose, there’s about an 80% change you don’t have the exact right version of the relevant Windows SDKs installed on your machine, and you’ll get a message with a “https://go.microsoft..” url as part of the error message. Copy that link into your browser’s address bar (the error message is not a hyperlink, unfortunately), and it’ll take you to the Windows  SDK download page. Install the relevant version, restart Visual Studio, and try again.

  2. Visual Studio Itself may need to be updated or you’ll get “(limited)” Mac Client connectivity and the iOS app won’t compile. After a day last week  spent wondering why my Mac Client was connecting with a “(limited)” next to the icon in the toolbar–and having the builds which worked the night before suddenly fail (and in desperation, spinning up a second Mac as a build computer only to have it also fail)–I discovered that Microsoft had just released a patch some 2 hours earlier to Visual Studio which solved the issue (itself likely caused by one of the Windows 10 updates that downloaded overnight). The solution: watch your “Notifications” in Visual Studio like a hawk, and download any updates you see there. You can also use Tools > Extensions and Updates to verify that you’ve got the very latest–and we do mean the very latest–updates.

  3. Your Android SDKs are out of date. If you want to work with the latest Android OSs (and you do), you’ll need to install more recent versions of the Android SDKs than are included with the Visual Studio 2017 install. The current versions of Xamarin (more on this later) also expect the Android SDKs to be updated. To do this, use Visual Studio’s Tools > Android > Android SDK Manager. Warning: the installs take a long time to complete, so throw on an episode or two of Breaking Bad before you kick them off.

  4. The default installed version of Xamarin is out of date, and will cause errors around InitializeComponent() in App.xaml.cs; when you try to compileThe solution: Before you do anything with a new project, right-click on the solution, go to Nuget Package Manager, click the Updates tab, and install all available updates. Then Do it Again as the Build component for Xamarin won’t update until the rest of it has updated. It’ll want to restart Visual Studio afterward, so do that too.

  5. Your Mac’s XCode and Xamarin also likely need updating. This is tedious. You’ll need the latest version of XCode… which in turn likely requires the latest version of the OS… along with the latest version of the Xamarin components (which you can get by downloading Xamarin Studio). It’s all pretty easily managed, but the installs take hours.

  6. The default project settings will nest the path too deeply and you’ll likely get deployment errors. By default, projects are created in the [My Documents]\Visual Studio 2017\Projects folder, creating a sub-folder for the project itself. Due to the depth of the folder nesting within the various sub-project folders, it’s far too easy to have some of the paths exceed Windows’ limit of 255 characters in the total path name. The solution: Don’t use the default location, and create the project’s directory as close to your drive’s root as possible.

  7. Your Android Devices need to be set up in developer mode to let you debug on the device. And trust me, after waiting several minutes for the emulators to boot up, you will want to debug on an actual device.The trick to turning on developer mode varies depending on the version of Android you’ve got. For mine (the “Marshmallow” version of Android), it involved tapping the Android OS version number a jillion times in a row under Settings. See http://www.androidcentral.com/android-50-lollipop-basics-how-turn-developer-settings or https://www.youtube.com/watch?v=TKIRXVhBvBY for more.

  8. Your iOS Devices need to be provisioned… and have their certificates set up… and a bunch of other stuff. The easiest way to handle all of this is through XCode. Start by paying the $99 to Apple to join their iOS developer program (you’ll need to bite the bullet and do it anyway if you distribute through their store), then connect your iOS device to your Mac, launch XCode, and follow the guide here: https://developer.xamarin.com/guides/ios/getting_started/installation/device_provisioning/Oh, and that part about needing to create a dummy app to get the proper provisioning profile installed? That’s actually real.

Hope these tips give you a smoother ride getting started. I’ll undoubtedly be blogging more on Xamarin in the future…

 

Importing thing to remember: This tech stuff is secretly fun

There’s a lie we tech folks tell ourselves–and anybody else who will listen–that what we’re doing is tough, arduous, and demanding work. It involves impossible demands, long hours, and nothing we do is ever completely perfect, or completely finished. In short, programming is hard work.

We start out telling folks this because it is difficult, demanding stuff, and we do put in crazy amounts of work at the keyboard, and stress ourselves out thinking about it all the time. We would like your admiration for all we go through, but since what we go through is largely incomprehensible and makes terrible stories at dinnertime, we’ll settle for your pity.

We tech types work marathon shifts, drink coffee by the gallon, and run ourselves ragged, all the while telling ourselves how bad we’ve got it. But here’s the truth–a truth we rarely admit to even ourselves: we’re secretly enjoying the whole thing, because it’s just about the most interesting game we’ve ever played.

Solving technical problems on computers is fascinating stuff, involving incredibly complex mental models, and elaborate systems built out of nothing but thoughts organized into code. It’s an amazingly creative pursuit, where you can think of an idea for a feature, and merely by thinking through all the angles of it in enough detail, can convert that idea into code, and thus into existence.

Even debugging is a challenge better than most mystery books, where your job is to solve the mystery of some strange occurrence, see it for what it really is, and slowly trace it back to the malformed code which perpetrated it. From there, you have to either tear up the bad code outright (risking the creation of new bugs in the process), or craft a suitable fix to restore the proper working of the system.

This stuff is downright fascinating. And on many days, we’d do it even if we didn’t get paid.

But we do get paid–and most of us fairly well at that–because it’s indeed difficult stuff, which requires ridiculous amounts of patience and knowledge, as well as a constantly replenished skill set to keep up with a technical landscape which is ever changing.

As deadlines loom and project problems pile up, it can also have an element of terror built in, as problems which would be fun to solve if there was more time to muck about with them suddenly become the narrowing jaws of a vice that threatens to crush you if they aren’t worked out by the time the ship date arrives.

At times like this, I often think back to a notable economics lecture in college where the professor demonstrated the law of diminishing returns by proposing “the Beer Game”. The  game goes as follows: He agrees to buy a string of beers for you, but whenever he buys you a beer,  you have to drink it.

“Wow!” we all thought, and on the hot autumn day he told the story, I was thinking that the first beer would taste awfully good indeed. The second would also be good–if not quite as refreshing as the first. But as the game goes on, each beer brings you less and less pleasure, and you’d eventually reach the point where you’d be willing to pay the instructor to be let out of the game.

Getting a software release out reminds me a lot of that game. As you dream up features and do the initial exploration, it’s a dream job, full of hope and creativity. As things ramp up and you have to work the technical details out, it’s still engaging, but seems more work and less fun. And then there’s always the terrible crush of deadlines at the end, where the non-stop work and pressure make you feel like the college kid trying to get out of the old econ professor’s beer-buying game. Only in this case, the only way out is through.

But then, if you don’t crumble under the pressure, you ship the product, the pressure evaporates, and in a while, a part of you starts looking forward to doing it all over again.

As I write this, I’m still catching my breath a bit and doing a little tidying up after a very major software release indeed. And yes, I’m happy to tell anyone who will listen about all the pain we went through to bring our new creation to life. We’re all incredibly proud of the new release, but there’s definitely a part of us that knows that there are far easier ways to make a living, and wonders why we keep putting ourselves through all this.

And here’s the truth: it isn’t just a way to earn a living, and it isn’t entirely about the pride we have in bringing something cool to life (although there’s a lot of that too). It’s because despite it all, it’s the most fun we’ve ever had while”working.” And despite our grousing–even to ourselves–we secretly know we’re having a blast.

One for the Programmers: Daily WTF

If you’re not a VB.Net or C# geek, probably best to move on to the next post. But if you are, perhaps someone can explain to me the what the !@#%! is going on here.

While hacking away on a new code project which involved porting a routine from VB6 to VB.Net (4.5 framework), I discovered that my performance had gone completely to hell on a function which assembles a big text file from database values. In it, I tracked the trouble to a function checks to see if certain values from the database were null, and returns “safe” values in case they are. It also looks for telltale “null” date fields, with values like 12/31/1899 which–although not technically null, are acting as blank for these purposes.

Here’s code sample #1:

  Public Shared Function ConvertNulls( _ 
     ByVal theString As Object) As String
    ...
      If IsDBNull(theString) Then
        ConvertNulls = ""
      ElseIf theString = "12:00:00 AM"  OrElse theString = _
           "12/31/1899" OrElse theString= "12/30/1899" Then
        ConvertNulls = "" ' This is a null date string
      Else
        ConvertNulls = theString
      End If
     ...
  End Function

And code sample #2:

  Public Shared Function ConvertNulls( _ 
     ByVal theString As Object) As String
     ...
      If IsDBNull(theString) Then
        ConvertNulls = ""
      ElseIf theString.Equals("12:00:00 AM") _
         OrElse theString.Equals("12/31/1899") _
         OrElse theString.Equals("12/30/1899") Then
        ConvertNulls = "" ' This is a null date string
      Else
        ConvertNulls = theString
      End If
    ...
  End Function

Here’s the thing:

Code sample #1 was on track to take a hour or so to run through 100,000 iterations; code sample #2 did the same 100,000 iterations in about 20 seconds. And the only difference? Whether I used theString = “x” or theString.equals “x”

Luckily, I thought to try .equals pretty early on, or else I’d be pulling my hair out trying to figure out why there should be even a tiny difference between the two approaches. Can anyone out there give me a coherent explanation as to why using the “=” operator vs. the .equals method should yield such wildly different performance results?

Tip: Solving “Restart Required” problem installing SQL Server Express x64 on Windows 7

There’s a bug in the current build of SQL Server Express which prevents it from being installed on a Windows 7 machine (the pre-installation checks will fail on a “restart required” link. Restarting, obviously, doesn’t fix this.

The solution:
Go to Start > Cmd > RegEdit and navigate to the following key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

In the right-side pane, double-click on the key “PendingFileRenameOperations” and clear any values in there. Exit RegEdit.

Then, just re-run the SQL Express intaller and all should be fine.

Internet Explorer 8 Ships, Fixes Dropdown List Problem

Microsoft finally made Internet Explorer 8 a “recommended download” with the latest set of patches on Microsoft Update. At first glance, there’s not a ton new with IE 8, but it does fix one incredibly annoying problem with all previous versions, including IE 7: Dropdowns containing many items no longer take a huge amount of time to be built, freezing the page (and computer!) during the process. Firefox and other browsers haven’t had this problem, but it’s nice to see IE finally getting this one fixed.

Why is this one important? My big point of pain was the “List of Titles” under the seller inventories on Atomic Avenue. After complaints from users, we tracked down what appeared for all the world to be a hard crash in IE 6 and 7 to the user’s going to my personal titles on Atomic Avenue, where my list of over 10,000 titles in stock resulted in a drop-down list which could take several minutes to fill on a fast computer.

Cutting down the number of titles resulted in an exponential decline in the time required, leading me to guess it was a case of the programmer equivalent of the blonde joke about painting lines on the highway–basically, the programmer was adding onto the end of the list in a way which involved constantly going back to the start, counting to the end, then tacking on the item there, rather than setting an index point at the end and tacking new data on from there directly.

On modern machines, the lazy, brute force way of adding to lists by counting from the beginning is normally not a problem, but when thousands of items are involved, you can quickly set up conditions so that the computer must walk up a number of items in the list equivalent to  [the number of items in the list] raised to second or third  power—each and every time they want to add a new item. Repeat that ten thousand times, and you can see how little programming inefficiencies, repeated with very large numbers, can become killers.

Once we discovered the original problem in Internet Explorer, we’d been forced to cap IE clients to seeing the first 2000 titles worth of content from a given seller when viewing individual inventories. This only affected a couple of sellers on the system, and was largely a temporary measure until we could address the matter in a more satisfactory way.

Unfortunately, one of those sellers with wide-ranging titles for sale was me! (By nature, we tend to grab one copy of everything in order to throw it in ComicBase).  Happily with IE 8 now available, we’re safely able to remove that limit (and warn users of older versions that they could do better if they upgrade to the latest version, or use another browser like Firefox which never had that particular problem). We’ll track browse usage in the months ahead and see whether we still need to engineer a workaround for older IE user.

(I’m hoping not, frankly, since any fix would not only be reasonably complicated, but would also involve a fair amount of overhead to load up the list, realize that there’s too many to be safely be shown by old versions of IE, then display smaller batches in a safer way. Having Microsoft simply fix IE seems much preferable, although if nobody ever updates their browser, we may have to rig up the workaround anyway, I guess…). In any case, kudos (and thanks!) to whichever person on the IE 8 team fixed this one!

Stopping “Invalid Callback or Postback” errors when using Ajax with dynamically filled dropdowns

This is one of those posts I’m just putting out there in the hopes it saves some other poor programmer the hours and hours worth of headaches that we just went through.

When we were developing the new search control panel for Atomic Avenue, we set it up so that several of the dropdownlists fill up with data based on other selections. For instance, if you choose to search by artist, a list of artist names will appear to choose from. As it turns out, such data-driven fields—particularly if they’re not always made visible until a later action (such as indicating you want to search by Artist) unhides them—is a great way to generate “invalid postback” errors under Ajax. This is especially true if you combine them with the AddHistoryPoint method in Asp.Net Futures’ July release to enable Back Button support.

The problem is that the new security controls in ASP.NET 2.0 can’t validate that the postbacks on the page were generated by those controls in the first place since (a) the contents can change as a result of the postback, and (b) the event validation may not have been set up in the first place if the control in question was hidden to start.

For the best rundown on the issue, here’s  the critical blog post by K.Scott Allen (check out part 1 as well)

Three options for getting around the situation presented themselves:

1. We could just disable the event validation checking, but that would open us up to new and fun injection attacks from folks faking postback data and using it to trick our web page into doing various inconvenient things.  In particular, we didn’t want to do that with our search since it was meant as a system-wide facility, meaning it would be used on virtually every page in the system.

2. We could avoid Ajax altogether and use traditional, full-page HTML rendering. This wasn’t a good option for us, since the Ajax-enabled version is *much* faster (and better looking) than the traditional HTML architecture which would require full page redraws after every control selection.

3. We could try calling Clientscript.RegisterForEventValidation and supply all the possible values of each dropdown prior to validation, but since there were often thousands of possibilities, this was impractical in the extreme.

So what was there to do? The answer was to roll our own version of the Dropdownlist control, leaving out the (non-inheritable) SupportsEventValidation attribute. By replacing the three problematic dropdownlists with the new control (“DynamicDropdownList”), we were able to get things working (including back button support) without tripping all over this rather thorny problem.

-Pete

Code Sample

Instructions