Monthly Archives: April 2009

Using TLBIMP.exe to create Strong Named Interop Assemblies

2
Filed under .NET, Utilities

Working on a VSTO 8 Word addin recently, I discovered to in order to deploy it, you must “strong name” the assembly.

I’d already obtained a Verisign certificate for digital code signing, and had a password protected PFX file containing both my public and private keys, so I figured I had what I needed.

So, I loaded the project, set the signing options to use my PFX file and compiled.

Full stop.

“Interop.Word.dll” is not strong named

Doh.

A little research later and it turns out that if you strong name one assembly, every single assembly that it references must also be strong named!

Yikes. In my case, I have almost a dozen, plus piles of interop assemblies for accessing legacy COM libraries.

First, the .NET assemblies. Setting them to be strong named using the same PFX file is easy, just use VS, under the project properties.

image

But, if your .net code refers to any COM components, it’s very likely you also have references to “interop” assemblies. These are DLLs that VS creates for you “behind the scenes” to act as convenient .net wrappers around the COM library objects.

The problem is that VS won’t automatically strong name those interop assemblies, and if you strong name your .net assembly, those interop assemblies also must be strong named.

First, I tried just creating an interop assembly.

I chose the Word 2000 object library to initially play with, but just about any COM dll or TLB or OLB file will do.

tlbimp "{path}\msword9.olb" /verbose /out:Interop.Word2000.dll /sysarray

(note, {path} is the path to your copy of this file, and the /sysarray option appears to be required if your working with just about any COM based interface). Worked like a champ.

So, I add in the keyfilename argument:

tlbimp "{path}\msword9.olb" /verbose /keyfilename:mycert.pfx /out:Interop.Word2000.dll /sysarray

and TLBIMP responds with an “Incorrect strong name arguments specified” error.

I then tried the PUBLICKEY option, like so:

tlbimp "{path}\msword9.olb" /verbose /keyfilename:mycert.pfx /out:Interop.Word2000.dll /sysarray

This appeared to work, until I actually tried to run my application. It failed, indicating that the “Strong Named Assembly was corrupt or was not signed with a private key”. Apparently, PUBLICKEY means just that, that the public key is used for one part of the signing process, and that you have to use a private key for the other.

I really didn’t want this to be a two step process so I kept looking.

Eventually, I discovered that signing an assembly is a completely separate process from “Strong Naming” an assembly.

Strong Naming an assembly doesn’t guarantee that you wrote it, but it does provide a way for one assembly to guarantee that it is loading the exact same assembly that it was compiled to work with, a subtle but significant difference.

Signing an assembly, on the other hand, requires a certificate from a signing authority, like Verisign. Signing does guarantee that an assembly was written by who the certificate says it was written by.

From what I can tell with VS2008, signing an assembly automatically strong names it, but the reverse is not true.

And certain assemblies need to be signed, (such as the primary assembly for an Office Addin), but others don’t.

And still others need to be strong named, but don’t necessarily need to be signed (such as any assembly or interop assembly referenced by an Office Addin.

But when you do this, you might notice that you end up with another unexplained dll in your output folder, called Office.dll.

After some digging, it turns out that TLBIMP will also create interop files for those COM libraries referenced by the COM library that you’re creating an interop file from. And you’ll need to include those additional interop files with your app for everything to load properly.

This is where the /reference option comes in. First, generate a strong named interop file for the referenced COM library, and then for the COM library you actually care about, like so:

tlbimp "{path}mso9.dll" /out:Interop.Office2000.dll /sysarray /verbose /keyfilename:mycert.snk 
tlbimp "{path}msword9.olb" /out:Interop.Word2000.dll /sysarray /verbose /keyfilename:mycert.snk /reference:Interop.Office2000.dll

The first line will create the Interop file for the Office.dll, which is referenced by Word.

The second line will create the interop file for Word itself, but note that it uses the /reference option to indicate that this interop file should reference the just created interop file for the Office library.

Finally, a note about namespaces. You’ll notice that I specified an OUT filename of Interop.Word2000.dll.

TLBIMP appears to automatically assume that when you do that, you want the classes defined within that interop file to exist within the “Interop.Word2000” namespace (ie the file name minus the “.dll”).

image

This may be appropriate, but it may not be, depending on your needs. Why might you want to change it? The only reason I can think of offhand is that you are referencing multiple versions of a single COM interface. A common example would be the need to reference both the Office 2007 Primary Interop files (available directly from Microsoft), and the Office 2000 interop files you created yourself (because MS doesn’t provide them).

It is possible that the two Interop files would have the same namespace and would collide.

Changing the namespace of one of them will allow your assembly to reference both interop files with no collisions. This is one element of .net that is, at the same time, unfortunately complicated, but incredibly useful.

Cisco VPN Client and Vista 32

0
Filed under Troubleshooting

image I’ve been running the Cisco VPN Client (version 5.0.0.360) for quite some time now and have consistently had another one of those “annoying but not enough to bother doing something about it” issues the entire time.

Basically, it can often be difficult to establish a connection. Once a connection is made, it stays up quite nicely (as long as there’s a little bit of activity over it). But establishing the connection in the first place can really be an exercise in patience sometimes, often taking 10 minutes or more of repeated connection attempts before succeeding. It seemed to me to have something to do with a timeout, but I had no idea what to tune or even where to look.

I finally decided to go poking around for a possible solution this morning.

First stop was Google, looking to see if there was a new version out. There is, but only with relatively minor changes, it would appear.

But the “changes and release notes” page did have some possibly pertinent material on it.

In particular, this caught my eye:

Vista Window Auto-Tuning Feature Might Cause Network Timeout Problems

Vista introduces a new feature called “Receive Window Auto-Tuning” that continually adjusts the receive windows size, based upon the changing network conditions.

Some people reported that auto-tuning causes network timeout problems with some applications and routers.

To turn off this Auto-Tuning, just open an administrative access command prompt and enter:

netsh interface tcp set global autotuninglevel=disabled

Try it out. If it doesn’t help, you can turn auto-tuning back on by entering enabled in the above command.

At least so far for me, with it off, I’ve been able to connect immediately, every time now. A far cry from before.

*UPDATE*

There’s a little more to it than just the autotuning level, it turns out. Apparently, VMWare’s networking support can really mess with the Cisco VPN service. From what I can gather so far, Cisco’s service does not like network interfaces disappearing and reappearing. It doesn’t track them internally properly. So, even if you exit VMWare to start your Cisco VPN session, the Cisco service might still be confused.

The easiest solution is to simply restart the Cisco VPN Service (called CVPND). You can do it manually through the Services control panel, or use a batch file to restart it even more easily (check here for a nice clean little batch file that handles all the nuances of restarting a service).

Finally, it’s not just VMWare that can mess with the Cisco VPN service. Apparently, ANY application which causes network interfaces to be created or removed could cause similar problems.

Fixing Fonts that Won’t Install

0
Filed under Fonts, Utilities

image Previously, I wrote a bit about fonts that won’t install under Vista (and possibly Windows XP SP2, but I haven’t tested that).

Apparently, Vista expects certain fields within the TTF file to be filled, whereas older versions of Windows don’t. The result is that while you might have been able to install a particular TTF file perfectly fine under an older version of Windows, the same font won’t install under Vista, with Vista claiming the font is corrupted.

Enter Font Creator Pro 5.6, a utility to actually allow you to edit fonts. One of its ancillary features, however, is the ability to correct this problem in TTF files quite easily.

Unfortunately, it’s a very manual process, requiring a lot of mousing or keyboarding.

Until now!

I cobbled up a short little VBScript that will accept either dragging and dropping onto it, either:

  • a single TTF file
  • Several TTF files
  • or a single folder containing a bunch of TTF files

The script essentially automates the process of loading the font into Font Creator, applying the rename fix and saving the font out.

Note that it saves the font in place (for simplicity’s sake more than anything else), which means that you should make a backup of any font you process with this.

'FONT FIX SCRIPT
'Darin Higgins May 2009
'---------------------------------------------
'Requirements
'------------
'Eval or licensed copy of Font Creator 5.6
'
'Purpose
'-------
'Many Fonts will not install properly under Windows XP SP2 or Vista, because they are 
'missing a few values for several internal fields.
'While the field values themselves are immaterial, Windows will consider the font "corrupt"
'
'What this script does
'------------
'You can drag either a single TTF font file or a folder that contains a number of TTF files
'onto this script.
'The script will run and will use Font Creator to
'1) Open the font
'2) Perform a Font Creator "AutoName" on the font
'3) Close and save the font, overwriting the original file.
'
'I've never had problems but if you are concerned, be sure to make a backup copy of
'all your font files first.
'
'Usage
'-----
'1) Make sure that you've opened Font Creator, clicked past the eval screen
'   and have an empty window open before running this script
'2) Drag iether a single TTF file or a folder containing TTF files onto this script
'3) The script should run, with lots of window flashing.
'4) Don't touch anything, even if you hear beeps.
'5) Eventually the script will finish. It is possible that some files didn't get saved properly
'   so check each file with a good font viewer app.
'
'--------------------------------------------------

dim Name
Dim fso, fldr, s, file
dim shell
Dim Count, x
dim excel

Set shell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
set Excel = nothing

for x = 0 to wscript.arguments.count-1
    Name = wscript.arguments(x)
    on error resume next
    '---- first, try to retrieve argument as a file
    if fso.FileExists(name) then
        '---- it worked, convert the single file
        Count = Count + 1
        CheckForQuit
        FixTheFont name
        CheckForQuit

    elseif fso.FolderExists(name) then
        '---- try to get a folder
        on error resume next
        Set fldr = fso.GetFolder(Name)    
        For each file in fldr.files
            if instr(1,ucase(File.Name),".TTF") <> 0 then
                Count = Count + 1
                CheckForQuit
                FixTheFont File.Path
                CheckForQuit
            end if
        next
    end if
next

'---- don't show a message if Only one file was processed
if Count > 1 then Msgbox "All Done"

'---- Alert if nothing was processed
if Count = 0 then Msgbox "No fonts were processed"

CleanUp

'====================================================
'End of main script
'====================================================

Sub CleanUp()
    if not Excel is nothing then excel.quit
    wscript.quit(1)
End Sub



'---- this subroutine uses sendkeys to 
'1) load the font in FontCreator 
'2) tell FC to perform the AUTONAME function on the loaded font
'3) close and save the font
Sub FixTheFont(File)
    shell.appactivate "FontCreator 5.6 (UNREGISTERED)"

    wscript.sleep 1000
    shell.sendkeys "%F{DOWN}{RIGHT}{DOWN}{ENTER}" 
    wscript.sleep 500

    '---- fix up possible bad elements in the Filename (could conflict with SendKeys)
    File = Replace(File, "{", chr(1) & "1")
    File = Replace(File, "}", chr(1) & "2")
    File = Replace(File, "(", chr(1) & "3")
    File = Replace(File, ")", chr(1) & "4")
    File = Replace(File, "[", chr(1) & "5")
    File = Replace(File, "]", chr(1) & "6")
    File = Replace(File, "+", chr(1) & "7")
    File = Replace(File, "~", chr(1) & "8")
    File = Replace(File, "%", chr(1) & "9")
    File = Replace(File, "^", chr(1) & "A")

    File = Replace(File, chr(1) & "1", "{{}")
    File = Replace(File, chr(1) & "2", "{}}")
    File = Replace(File, chr(1) & "3", "{(}")
    File = Replace(File, chr(1) & "4", "{)}")
    File = Replace(File, chr(1) & "5", "{[}")
    File = Replace(File, chr(1) & "6", "{]}")
    File = Replace(File, chr(1) & "7", "{+}")
    File = Replace(File, chr(1) & "8", "{~}")
    File = Replace(File, chr(1) & "9", "{%}")
    File = Replace(File, chr(1) & "A", "{^}")

    shell.sendkeys file & "{ENTER}"
    wscript.sleep 500

    Shell.SendKeys "%LN"
    wscript.sleep 500
    shell.sendkeys "{ENTER}{ENTER}"
    wscript.sleep 500
    shell.sendkeys "%FC{ENTER}"
    wscript.sleep 1500
end sub


'------------------------------------
'Check to see if user pressed esc
'Do this using a hadny little hack through excel
'There's likely better ways, but this works
'------------------------------------
dim Skip
Sub CheckForQuit
    if Skip = true then exit sub

    On Error Resume Next
    '---- make sure Excel exists and we can create an object
        '     if not, no big deal, just skip all this code
    if excel is nothing then
         set excel = CreateObject("Excel.Application")
                if err then Skip = true
        end if

    if Skip = true then exit sub

    dim keys(0)
    'ESCAPE
    keys(0) = 27

    dim Passed
    Passed = 1
    For i = 0 To UBound(keys)
        keystate = excel.ExecuteExcel4Macro("CALL(""user32"",""GetAsyncKeyState"",""JJ""," & keys(i) & ")")
        If (keystate and 1) = 0 Then
            Passed = 0
        End If
    Next

    If Passed = 1 Then
        CleanUp
    End If
End Sub

To use it, just copy the text above and save it to a FixFont.VBS file on your desktop.

Then, back up a font TTF file you want to process, and simply drag it from Explorer onto the VBS script.

Then sit back and let it drive for a few seconds.

Each font takes about 2-3 second to fix.

It doesn’t work 100% (sometimes the SENDKEYS just don’t get synchronized properly), but I didn’t have any problems as a result, and I processed some 10,000 fonts through it. It just took several passes (and a few days<g>)

One final note. I used a trick from Excel to check if the ESCAPE key has been pressed and terminate the script. If you have Excel, that should work fine. If not, it should just skip all that, but that means you won’t be able to stop the script should you need to. To be safe, just do a few fonts at a time.

And as with everything else here, IWOMM (It Works On My Machine) but your mileage may vary.

System process in Vista running at 100%

0
Filed under Uncategorized

I’ve had a very strange problem for months now that was intermittent enough to not be overly concerned about, but happening enough to be bothersome.

Basically, every other time I rebooted my system, the “System” process (as listed in TaskMan) would get pegged at max utilization (in my case, on a dual core system, it would hover around 45-50%, but on a single core system, it’d run at near 100%).

This would drag things to almost a standstill. The cursor would move haltingly, apps would take forever to load, and shutting down was interminable.

It happened again this morning, so when I got some time, I started researching it.

Turns out the solution is relatively straightforward, at least in my case.

Vista has a feature called Offline Files. It allows files stored on network drives to be automatically synchronized down to your local system, for access when you are, yes, offline.

However, this feature appears to have some really nasty timeout handling issues, so when network devices actually are offline, it can end up bringing your entire system to it’s knees.

For virtually everyone out there, I’m guessing this feature isn’t actually something you even care about. I certainly don’t. And fortunately, turning it off is easy.

Open the Control Panel, and click Offline Files.

image

Then, if the first button listed says “Disable Offline Files”, click it. That will disable the offline files features, and, at least so far, through several reboots, has resulted in my system not getting dragged down in the slightest.

And just when I was starting to like Vista<g>