Getting a machine’s NetBIOS domain name in C#

I tried to find some mechanism to get the current machine’s NetBIOS domain name (the machine domain, not user domain), but couldn’t find anything in the usual places (e.g. System.Environment). If you want the fancy-schmancy Active Directory DNS domain then you can use Domain.GetComputerDomain().Name from System.DirectoryServices.ActiveDirectory, or another one that I stumbled across in Reflector was IPGlobalProperties.GetIPGlobalProperties().DomainName that lives in System.Net.NetworkInformation. But a simple way of getting the old-skool NetBIOS/LanManager-style machine domain name proved elusive.

Some googling suggested that WMI would provide the answer but I find WMI a little heavyweight, and not always reliable. The information is also probably in the registry somewhere, although I couldn’t find it after a cursory scan. The proper, supported way it would appear is to use the Network Management API. So my solution entailed P/Invoking to netapi32.dll.

If you’re after the same information I hope you find the code below useful. Once you’ve incorporated this in your project, just call the GetMachineNetBiosDomain method. It will return the machine’s Workgroup name if the machine is not domain-joined.

UPDATE: Now works on 64-bit thanks to update sent by Rp Brongers.

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

class NetUtil
{
    [DllImport("netapi32.dll", CharSet = CharSet.Auto)]
    static extern int NetWkstaGetInfo(string server,
        int level,
        out IntPtr info);

    [DllImport("netapi32.dll")]
    static extern int NetApiBufferFree(IntPtr pBuf);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    class WKSTA_INFO_100
    {
        public int wki100_platform_id;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string wki100_computername;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string wki100_langroup;
        public int wki100_ver_major;
        public int wki100_ver_minor;
    }

    public static string GetMachineNetBiosDomain()
    {
        IntPtr pBuffer = IntPtr.Zero;

        WKSTA_INFO_100 info;
        int retval = NetWkstaGetInfo(null, 100, out pBuffer);
        if (retval != 0)
            throw new Win32Exception(retval);

        info = (WKSTA_INFO_100)Marshal.PtrToStructure(pBuffer, typeof(WKSTA_INFO_100));
        string domainName = info.wki100_langroup;
        NetApiBufferFree(pBuffer);
        return domainName;
    }
}

Disabling direct PDF viewing/opening from the web

This worries me (more information). It would appear that you could craft PDFs that could hijack someone’s machine simply by their opening the PDF. This is especially pernicious because Adobe Reader is so intent on integrating PDF into Internet Explorer using various Browser Helper Objects and ActiveX Controls that a “drive-by” hijack would be simple to set up once you’ve crafted the malicious PDF file.

A quick fix (that Works On My Machine™) that prevents the automatic opening/viewing of PDF files from the web is to change the HKEY_CLASSES_ROOT.pdfContent Type registry key from application/pdf to something like application/octet-stream. This means that you have to save the files first before opening them.

Some possible scriptable ways of automating this:

Method 1: A .REG file

Save the following into a file with a “.reg” file extension and running using regedit.exe /s filename.reg.

REGEDIT4
[HKEY_CLASSES_ROOT.pdf]
"Content Type"="application/octet-stream"

Method 2: The REG command

Alternatively the following, using the reg.exe command will achieve the same result:

reg add HKCR.pdf /v "Content Type" /d "application/octet-stream" /f

You obviously still need to be careful about PDFs, you just have the ability now to actively decide whether you want to open them.

Cisco home page FAIL

UPDATE: it’s over 2 hours later now and they’ve finally fixed it 🙂

Cisco’s home page this morning: looks like they ran out of their allocation of lowercase letter ‘t’ (thanks to Chris Venus for pointing it out):

image

Or was it “Speak Like an Irishman” day and nobody told me?

Lowercase ‘t’s were being stripped from the source which explains why there were no styles, etc:

image

Chris reckons it’s a possibly a whitespace-trimming RegEx gone wrong, WDYT?

Setting Google Chrome as the default browser for Adobe AIR apps

UPDATE: Logan Buesching commented to say that Chrome apparently creates “ChromeHTML” shellopen keys except they’re in HKCR (which is why you get a UAC prompt, it’s the machine part of the registry), so you can actually just set HKCUSoftwareClasses.htm to ChromeHTML and you’re done. Logan also goes into more detail as to what’s going on so check out his post.

It seems odd that they end up creating a global HKCR key which ulitimately points to an app that’s installed in a user’s private profile. I’m sure this will cause issues if you have multiple people using your machine. Anyway, I guess this is all a bit moot: this is beta software kids, and I’m sure Google will fix this in due course by release and you may have to undo some of these registry shenanigans for it to work as expected.

Google Chrome was a big hit in the office today. To the extent that many of my colleagues were setting it as their default browser already, even though it’s a beta product. Cwazy.

Unfortunately even if you do click the “Make Google Chrome my default browser” button on the Options page, not all applications that launch hyperlinks comply. One of those is the Twitter client Twhirl, which is an Adobe AIR application (I’m assuming this is an issue with AIR itself rather than Twhirl doing something silly). I deduced what AIR was doing when trying to locate the default browser by using Sysinternals’ Process Monitor (ProcMon). It was using the current user’s “.htm” file association preference: which on my machine was pointing to FirefoxHTML. So I created a new registry key for GoogleChromeHTML that specified the location of chrome.exe as the file opener and pointed the “.htm” setting there, which did the trick.

To make this easier to replicate, and to save having to write tedious explanatory steps detailing exactly what to do – I’ve created a short JScript Windows Script file.

Save the following with a “*.js” file extension (e.g. ChromeDefaultForAIR.js) and run it:

var wshell = new ActiveXObject('WScript.Shell');
var chromePath = wshell.ExpandEnvironmentStrings('%USERPROFILE%\Local Settings\Application Data\Google\Chrome\Application\chrome.exe');
wshell.RegWrite('HKCU\Software\Classes\.htm\',
   'GoogleChromeHTML');
wshell.RegWrite('HKCU\Software\Classes\GoogleChromeHTML\shell\open\command\',
    '"' + chromePath + '" "%1"');

Normal caveats for editing your registry and downloading and running random scripts from some idiot’s blog apply. To revert, set HKCUSoftwareClasses.htm back to FirefoxHTML.

If it helps leave a note in the comments!

Identifying the unidentified problem with Windows Firewall

Recently Windows Vista has been refusing to show the Windows Firewall Settings dialog box and instead showing the ever so informative message: “Windows Firewall: Due to an unidentified problem, Windows cannot display Windows Firewall settings”.

image

No clues. Nothing in the Event Log. Nothing. Brilliant.

Well I had a brain wave this morning about what might be causing it. Thankfully it turned out to be right. I remembered that on our Windows Domain we have a few Group Policy settings that apply to Windows Firewall.

image

In this case the culprit was the “Define program exceptions” that had a few old entries for AVG 7.5 Network Edition. As we’d upgraded to AVG 8.0 recently the program paths were no longer valid, nor really necessary. So I removed them entirely and set the policy back to Not configured. To verify it worked I ran gpupdate /target:computer /force at a command prompt on my workstation and voila: the Windows Firewall Settings dialog box would now appear once more.

 image

Group Policy for Windows Firewall is stored on client machines in the the Registry at:

HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindowsFirewall

So if you’re not on a domain and there are registry entries in this location that have been set for some reason, then adjusting them will have the same effect as changing the Group Policy. If you are on a domain then getting the Group Policy fixed is obviously the right approach.

Hope that helps you – leave a comment if it does.

Solved: “Cannot read from the source file or disk”

I’ve finally solved a problem that’s been bugging me for years. One of our file shares ended up with several undelete-able files. Attempting to delete them results in “Error Deleting File or Folder – Cannot delete file: Cannot read from the source file or disk“.

Note: Windows 7’s version of this message is something like:

Could not find this item: This is no longer located in C:Blah. Verify the item’s location and try again.

Even going to the file’s properties to check permissions presented a very blank properties dialog. And a CHKDSK didn’t sort thing out either.

It turns out the problem was: the filename ended with a dot, e.g. it was something like “C:TempStuffSales Agreement.“. As far as Windows is concerned this is an invalid file name: so although it gets reported in a directory listing, the standard Windows APIs for manipulating files subsequently deny its existence.

So how did this file get created in the first place? The answer: a Mac. The file was on a file share which had been accessed by a Mac user. Macs tend to write all sorts of metadata to extra “._DSStore” files and suchlike and had left this file behind.

So if Windows doesn’t appear to allow these file names, how did they get to be created? Well, it turns out that NTFS allows all sort of file name/path weirdness that Windows, or specifically the Win32 API, doesn’t allow. For example, NTFS actually allows file paths up to 32K but Windows restricts file paths to no more than 260 characters (MAX_PATH). I suppose this is all for DOS/Windows 9x backwards compatibility. As these files were being accessed over a file share I guess the usual Win32 checks are bypassed.

But thankfully you can get Win32 to ignore these checks by prefixing your file paths with \?, (ie. C:TempSomeFile.txt becomes \?C:TempSomeFile.txt) which I discovered after reading this blog post about long paths in .NET.

So at a command prompt (Start > All Programs > Accessories > Command Prompt) I was able to delete the file using:

del "\?C:TempStuffSales Agreement."

Note: On Windows 7 it seems you can just use wildcards without the \? trick to delete the offending files: e.g.
del c:tempsomefil*

If it’s a folder/directory you’re trying to delete use the rd or rmdir command, e.g.:

rd /s "\?C:Documents and SettingsUserDesktopAnnoying Folder."

Tip: as you’re typing the file/directory name use the TAB key to auto-complete the name (press TAB repeatedly to cycle through possible names).

 


Of course the corollary of all of this is that you could really annoy somebody by doing this:

 

echo Hi > "\?%USERPROFILE%DesktopAnnoying file you can't delete."

But you wouldn’t do that would you?

If this post helped you and you feel so inclined, feel free to buy me a beer 🙂PayPal - The safer, easier way to pay online.

Converting Visual Studio 2003 WinForms to Visual Studio 2005/2008 partial classes

.NET 2.0 introduced partial classes which enables “.designer” files in Visual Studio 2005 and later. That is, all of the visual designer-generated code (control declarations, the InitializeComponent method, etc) can be kept in a file separate from your regular code. When you open up a .NET 1.x Visual Studio 2003 WinForms project up in Visual Studio 2005/2008 it will upgrade your project to .NET 2.0 just fine, but unfortunately it doesn’t migrate your WinForms classes over to the new “.designer” project structure.

Initially I thought this would be a job for a DXCore plug-in (the free framework upon which CodeRush is built) as it provides plug-ins with an object model of the code which could be used to grab all the right members and move them over into a designer file. Before I looked into this though I checked what the options were for simply implementing it as a Visual Studio Macro. I was fully expecting to have to use a regular expression to grep the code file to perform the task, but was pleasantly surprised to find that the Visual Studio extensibility API in available to macros provides a code model (based on the .NET CodeDom I presume) which you can traverse to inspect and manipulate the underlying code.

So, here’s what the resulting “ExtractWinFormsDesignerFile” macro does:

  • Locates the first class in the selected project item (DTE.SelectedItems.Item(1).ProjectItem) by traversing the ProjectItem.FileCodeModel.CodeElements
  • Extracts the InitializeComponent and Dispose methods from the class by traversing CodeClass.Members
  • Extracts all control fields: that is, all fields whose type derives from System.Windows.Forms.Control or System.ComponentModel.Container or whose type name starts with System.Windows.Forms
  • Puts all the extracted code into  a new “FormName.Designer.cs” file.

This is currently C# only – it could easily be converted to generated VB.NET code or adapted use the FileCodeModel properly and perhaps create the code in an language-agnostic way when generating the designer file. I took a shortcut in just generating the designer file as a string and writing it directly to a file.

To “install”: download the macro text and copy the methods into a Visual Studio Macro Module (use ALT+F11 to show the Macro editor).

To use:

  • Select a Windows Form in the Solution Explorer
  • Run the macro by showing the Macro Explorer (ALT+F8) and double-clicking the ‘ExtractWinFormsDesignerFile’ macro. (Obviously you can hook the macro up to a toolbar button if you like.)
  • You will then be prompted to manually make the Form class partial (another bit I was too lazy to work out how to get the macro to do): i.e. change
    public class MyForm : Form
    to
    public partial class MyForm : Form

Please leave a comment if this helps you.

Fight Spam with jQuery!

OK, maybe title should actually be “Prevent email address harvesting with jQuery”. But anyway – I came up with a technique for our company web site today which will hopefully prevent some of the email addresses that we publish being picked up by email address-harvesting bots. The idea is that an email address is put on the website using the following obfuscation:

<span class='email'>joebloggs [at] example [dot] com</span>

And then transformed by JavaScript into:

<a href='mailto:joebloggs@example.com'>joebloggs@example.com</a>

It’s a progressive enhancement in that the content is still quite legible by people with JavaScript turned off. Here’s the jQuery script that does it:

$(function() {
   $('.email').each(function() {
      var $email = $(this);
      var address = $email.text()
         .replace(/s*[at]s*/, '@')
         .replace(/s*[dot]s*/g, '.');
      $email.html('<a href="mailto:' + address + '">' 
         + address +'</a>');
   });
});

I’m perhaps being naïve about how email addresses are collected these days, and maybe embedding email addresses in images is a better approach – but this was quick and simple and worth a try.

Lines between methods in the C# editor (CodeRush/DxCore plugin)

Like most .NET developers,  I used to do VB/VBA coding before C# came along. But, one thing I always missed in in the C# code editor was the lines that the VB editor puts between methods. An an avid user of CodeRush and Refactor! Pro, which itself does code structure painting in Visual Studio, I’ve created a DxCore Plugin that draws lines between methods which (IMHO) improves on the ones in the VB code editor.

Here’s a screen shot of it in action:

Draw Lines Between Methods - in action

And here’s the exciting options page:

Draw Lines Between Methods - settings

Even if you’re a VB.NET person you might like to try it to see if it works any better for you than VB’s built-in lines (although I guess you’d need to turn off the built-in method-separating lines somewhere in Tools Options).

The project is hosted on Rory Becker’s DX Core Community Plugins Google Code project, where you can download the source and binaries.

Let me know how you get on with it in the comments 🙂

IE 6 bug causes jQuery globalEval error

UPDATE: this is fixed in jQuery 1.2.6 and later, see ticket #2709.

After upgrading our code base to use the latest jQuery 1.2.3 (previously we were using 1.2.1) our testers discovered a quite ridiculous bug in IE 6 that caused jQuery to fail (IE 7 is fine, which is why we didn’t experience it development). The issue manifested itself as the script error message “Problems with this web page might prevent it from being displayed properly…

Line: 24
Char: 76
Error: Invalid Argument
Code: 0
...

…and various document.onready handlers not running.

Of course line 24, char 26 doesn’t really help much because IE always seems to get this a few lines out of whack and with the minified version of jQuery it would be way out. So I replaced the minified version jQuery.js with the uncompressed version, cleared the browser cache and re-visited the web app in IE 6. This then gave line 659, char 4 as the offending location:

image

After whacking in a several alert()s in the lines in the vicinity of 659, it turns out the issue is with head.removeChild(script) in the globalEval function, 4 lines up. Obviously.

So, why was head.removeChild failing? I put the following debug code in:

alert(head.tagName) // displays "HEAD" as expected
alert(script.parentNode.tagName) // displays "BASE" !!!

So, it transpires that our pages having a <base> tag within the <head> contributes to the issue. IE 6 seems to get totally confused as to the structure of the document HEAD when there’s a self-closing or unclosed BASE tag. BASE tags I suppose are quite rare and this is probably why this issue doesn’t appear to be commonplace. (The BASE tag is in there for legacy reasons in our code, but they’re also quite useful when you save the source of HTML pages they still pick up images and script from the originating server which is handy for debugging automatically-generated HTML.)

So, before, the offending base tag looked something like this:

<base href='http://example.com/blah' />

After some experimentation it appears IE6 doesn’t exhibit its odd behaviour if you do this instead:

<base href='http://example.com/blah'></base>

Job done.

Update: Chris Venus comments about the reason for the weird behaviour in IE6 and earlier. Previously <base> was interpreted as a container, which could appear multiple times in a document: different sections within the page could have different bases, so would logically end up wrapped within each <base> (now there’s a feature everybody wanted, right?). Because of this, <head> got treated as a “section” of the document and elements added to it ended up as children of any <base> it contained rather than siblings. See IEBlog: All your <base> are belong to us.