Category Archives: VB Feng Shui

Using Word’s Find Object in Field Result Ranges

0
Filed under Office, VB Feng Shui

image If you’ve ever had to use the Word Object Model’s Find object, you probably know it can be a bit… well… finicky. It has guids that conflict with Excel 95 typelibs which causes problems, it uses a veritable forest of optional parameters, most of which are declared as OBJECT so intellisense doesn’t work well with it, it’s a real pain to use with C# because of C#’s lack of optional parameter handling, etc, etc.

And I have a new one to add to the list.

I was recently working on a kind of super advanced mail merge facility for Word documents. Word’s MailMerge capabilities are certainly good, but they couldn’t cut the mustard for this particular batch of requirements.

However, since the MAILMERGE field (and all the various other fields in Word) have a lot of capability, I wanted to leverage that as much as possible.

Essentially, the templates to be used would embed normal mail merge fields, but Word’s Merge ability would never get used. Instead, I’d have a VB.NET assembly that would navigate through each field in the document, analyze its code, and replace it with the appropriate result. The code looks something like this:

Dim Code = Field.Code.Text
'....parse the code for the field here
'     determine the final field contents, put it in Content

Field.Result.Text = Content
Field.Unlink

Pretty simply stuff, really.

But, the content of the field might have embedded style information. Sort of like a stripped down HTML code system. For instance, <b> might be “Turn bold on”, and </b> would turn bold off.

First thought

Initially, I thought I could just detect the existence of the opening tag, remove all the tags, and just format the entire field consistently. It’s simple and fast. But unfortunately, some field values had tags embedded within the field, meaning that only a portion of the field’s data should be formatted.

Strike 1.

RTF??? In 2010?

Then, I figured I could just swap out the formatting code with the equivalent RTF codes, and use PasteSpecial to paste the RTF formatted data directly in the field.

While this did work, it presented a bad side effect. Since the RTF text coming off the clipboard represented specific and complete formatting information, it overrode all default formatting already applied to the field. So, say the entire document was formatted in Calibri Font. When I pasted the RTF text “{\b My Text Here}”, the end result was a field formatted in bold Times New Roman, not Calibri. So even though I hadn’t specifically set the font for the text, the paste special was assuming a default of Times.

Strike 2

That ol’ Word FIND Object

I finally realized that I was going to HAVE to use the FIND object in Word to locate those formatting marks, and then apply the applicable styles to the found text.

Performing the Find is pretty straightforward, although there’s a few things to watch for.

The first is the aforementioned Excel 95 Guid clash. What it means is that you need to access the FIND object via late binding. So obtain a FIND object from the (Field.Result range) and store it in an OBJECT variable. That will force VB.net to make latebound calls to it.

The next problem is how to actually find the marks. You’ll need to use the Find object’s wildcard support for that. The code looks something like this:

Dim Find as Object = Field.Result.Find
With Find
   .ClearFormatting
   If .Execute(FindText:="\<b\>*\</b\>", MatchCase:= false, MatchWildcards:= True, Forward:= True) then
      'the text was found
   Else
      'The text was not found
   End If
End With

Again, pretty simple stuff.

But there was two problems.

The first was, the above would find the text alright, but I still needed to remove those embedded formatting marks. After a false starts, I realized that the REPLACE functionality was could do this very easily. Just mark the * (i.e. the found text that you want to keep) by enclosing it in “()”, then Replace with “\1” (the first marked substring).

Dim Find as Object = Field.Result.Find
With Find
   .ClearFormatting
   If .Execute(FindText:="\<b\>(*)\</b\>", MatchCase:= false, MatchWildcards:= True, Forward:= True, Replace:=wdReplace.wdReplaceAll, ReplaceWith:="\1") then
      'the text was found
   Else
      'The text was not found
   End If
End With

The second problem was much more insidious.

It worked perfectly on fields embedded in the body of the document, but completely failed to find anything in field embedded in cells in a table. Needless to say, I was scratching my head over that one for a while.

It turns out that Find just doesn’t work right if you attempt to use it in the Result range of a Field  object when that object has been embedded within a table.

The trick, then is to Unlink the field object before you attempt a find inside of it.

Dim Rng = Field.Result
Field.Unlink
Dim Find = Rng.Find
With Find
   '.... continue as before

With the range no longer within the field, the Find works just like it should, regardless of whether the field is in the body of the document or embedded within a table.

So there’s my terrifically arcane Office object model trivia for the day!

Old School Binary File Manipulation, Or Code Page Encoding Gotchas

0
Filed under Troubleshooting, VB Feng Shui

So, I was working on parsing a WordPerfect Merge DAT file today…

Yep, you read that right, WordPerfect! Seriously old school stuff.

Anyway, this file format is a peculiar binary format with a bunch of binary headers surrounding all the nice juicy ASCII merge text fields. Dealing with such files in VB6 was easy, but it seems that the few times I’ve had to work with this type of thing in .NET, I always end up stubbing my toe on encoding.

You see, all strings in .NET are UNICODE, and reading binary data like this into a string involves an encoding or decoding process. In order for things to work the way you’d (or at least, I’d) expect them to, you have to be SURE that the strings will round trip properly. And boy, they weren’t for me.

I wrestled with it all day, finally knocking off to go home and unwind.

But it was still bugging me.

So I whipped up this little sample (why didn’t I think of this at noon today<sigh>).

    Private Sub TestEncode()
        Dim b(255) As Byte
        For x = 0 To 255 : b(x) = x : Next

        Dim buf As String = System.Text.Encoding.Unicode.GetString(b)

        Dim c(255) As Byte

        c = System.Text.Encoding.Unicode.GetBytes(buf)
        For x = 0 To 255
            If c(x) <> x Then Stop
        Next
        Stop
    End Sub

If the code stops at that stop in the last FOR loop, something didn’t round trip properly and you’re pretty much guaranteed a headache.

And sure enough, the UNICODE encoding object failed to round trip. But so does the ASCIIENCODING, UTF8, etc etc.

On a whim, I tried the “default” object, SYSTEM.TEXT.ENCODING.DEFAULT.

And it worked!

A quick check revealed that on my system, DEFAULT is actually the encoding object for the codepage 1252, which is the Windows ANSI ASCII encoding. Read more about it here. But 1252 is the codepage you want to use if you want EVERY SINGLE binary value from 0-255 to map to the exact same unicode character when you read the file into a string.

Long story short, if you’re used to looking at binary files via a hex editor, and you want to manipulate those files in VB, you have two choices.

  1. Read the file into a BYTE() array as raw data, then operate on the bytes directly.
  2. Read the data into a string, but be SURE to use the proper encoder, like so:
Dim Buf as String= My.Computer.FileSystem.ReadAllText(MyFileName, System.Text.Encoding.GetEncoding(1252))

Option 1 is great if you need to work on the data as, more or less, strictly byte type info. But it’s a real pain if much of the data is string type stuff.

Option 2 is MUCH easier to work with for mostly string data (you can use INSTR, MID, LEFT, RIGHT, cutting and chopping much more easily than with byte arrays), BUT you have to have read the data in via the right encoder or it will be “altered” during the loading process and won’t contain the same bytes that were actually in the source file.

Doing this won’t work:

Dim Buf as String= My.Computer.FileSystem.ReadAllText(MyFileName)

Because the ReadAllText routine uses, as its default, the UTF8 encoder.

Hopefully, putting all this down in writing now will keep me from forgetting about it the next time I’m mucking with funky file formats!

Calling C Object Methods from VB.Net

0
Filed under .NET, amBX, Games, Hardware, VB Feng Shui

image I’ve been playing recently with the amBX ambient effects library and devices.

Essentially, it’s an effects platform that allows you to easily create light, wind and rumble effects to coordinate with what’s going on on-screen, in a game, in media players, or what-have-you. The lighting effects are nothing short of fantastic. The rumble and fan effects…. meh. They’re interesting, but I’m not sure where that’ll go.

Regardless, the API for amBX is all C style objects, which means essentially an array of function pointers to the methods of the object; not really an API that VB.net likes to consume. Be sure to grab the amBX developer kit here. You’ll also need to core amBX software available from the main website. Finally, play around with the “Virtual amBX Test Tool”. It’ll allow you to experiment with all the amBX features and functions without having to buy anything at all. Of course, eventually you’ll want to get at least the starter kit, with the lights. But it’s not necessary to begin experimenting.

Hats off to Philips for making this possible!

image

Here’s an example of the structure definition from the amBX.h header file that comes with the API (I’ve clipped out comments and other bits):

struct IamBX {
    amBX_RESULT (*release) (struct IamBX * pThis);
    amBX_RESULT (*createLight) (struct IamBX * pThis,
                                amBX_u32 loc,
                                amBX_u32 height,
                                struct IamBX_Light** ppLight);
....

As you can see, each element in the structure is made up of a pointer to a function. The various functions all take, as their first argument, a pointer back to this structure. Under the covers, this is how virtually all object oriented languages function, it’s just the the compiler usually hides all this nasty plumbing so you don’t have to deal with it regularly.

But this presents a problem. VB.net is “managed” code, and as such, it likes things to be wrapped up in nice “managed” bits. There are plenty of good reasons for this, but these function pointers are decidedly not nice and tidy managed bits! So, what to do?

One solution is the approach Robert Grazz took here. It’s a solid solution, no doubt, and I learned a lot from looking at his approach, but, this being VBFengShui, I wanted that same functionality in native VB.net with no additional dll files hanging around!

Delegates to the Rescue!

A delegate in .net is essentially a managed function pointer. In VB.net, they’re most commonly used to handle events, but you wouldn’t really know it, because VB’s compiler does a good job of hiding all that plumbing from you. However, unlike VB6 and earlier, in VB.net, all the plumbing can, if you’re willing, be “brought into the daylight” and used however you want.

There are many, many discussions about delegates for VB.net out on the web. A really good Introduction to the concepts by Malli_S is on codeproject, so I won’t rehash the basics here.

The problem is, delegates in VB.net tend to be generated by using the AddressOf operator, and I already had the function addresses (they’re in that C structure). I just needed to get a delegate that would allow me to call it.

Some Googling turned up several good posts that provided pointers, including this one on StackOverflow. But it wasn’t exactly all the steps necessary.

Getting the C Structure

The first step toward getting something working with amBX is to retrieve the main amBX object. You do this through a standard Windows DLL call.

<DllImport("ambxrt.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function amBXCreateInterface(ByRef IamBXPtr As IntPtr, ByVal Major As UInt32, ByVal Minor As UInt32, ByVal AppName As String, ByVal AppVer As String, ByVal Memptr As Integer, ByVal UsingThreads As Boolean) As Integer
        End Function

Assuming you have the ambxrt.dll file somewhere on your path or in the current dir, the call will succeed, but what exactly does that mean?

Here’s an example of a call to it in C:

    if (amBXCreateInterface(
            &pEngineHandle, 
            majorVersion, minorVersion, 
            (amBX_char*)cAppName.ToPointer(), (amBX_char*)cAppName.ToPointer(),
            nullptr, false)
        != amBX_OK)

Essentially, you pass in the Major and minor version numbers of the Version of amBX you need, and two strings indicating the name of your app and the version of your app. No problems with any of that. But that &EngineHandle is the trick.

It means that this call will return a 4 byte pointer to a block of memory that contains the amBX object structure, which is, itself, an array of 4 byte function pointers to the various methods of the amBX object. Therefore, in VB.net, that argument is declared ByRef IamBXPtr as IntPtr.

Now, we need a place to store that “structure of pointers.” Going through the ambx.h file, I ended up with a structure that looks like this:

        <StructLayout(LayoutKind.Sequential)> _
        Private Structure IamBX
            Public ReleasePtr As IntPtr
            Public CreateLightPtr As IntPtr
            Public CreateFanPtr As IntPtr
            Public CreateRumblePtr As IntPtr
            Public CreateMoviePtr As IntPtr
            Public CreateEventPtr As IntPtr
            Public SetAllEnabledPtr As IntPtr
            Public UpdatePtr As IntPtr
            Public GetVersionInfoPtr As IntPtr
            Public RunThreadPtr As IntPtr
            Public StopThreadPtr As IntPtr
        End Structure

That StructLayout attribute is particularly important. It tells the compiler that the structure should be layed out in memory JUST AS it’s declared in source code. Otherwise, the compiler could possibly rearrange elements on us. With Managed Code, that’d be no problem, but when working with unmanaged C functions, that would not be a good thing!

And finally, we need a way to retrieve that function pointer array and move it into the structure above, so that it’s easier to work with from VB.net. That’s where the System.Runtime.InteropServices.Marshal.PtrToStructure function comes in. This routine will copy a block of unmanaged memory directly into a managed structure.

Private _IamBX As IamBX
Private _IamBXPtr As IntPtr
...

amBXCreateInterface(_IamBXPtr, 1, 0, “MyAppName”, “1.0”, 0, False)

_IamBX = Marshal.PtrToStructure(_IamBXPtr, GetType(IamBX))

And presto, you should now have the _IamBX structure filled in with the function pointers of all the methods of this C “Object”.

Calling the C Function Pointer

At this point, we’ve got everything necessary to call the function pointer. Take the CreateLight function. The C prototype for this function is shown at the top of this page. As arguments, it takes a pointer back to the amBX structure, 2 32bit integers describing the location and height of the light source, and it returns are pointer to another structure, in this case, an amBX_Light structure, which contains another set of function pointers, just like the amBX structure described above.

First, we need to declare a delegate that matches the calling signature of the CreateLight C function we’ll be calling:

<UnmanagedFunctionPointer(CallingConvention.Cdecl)> _
Private Delegate Function CreateLightDelegate(
         ByVal IamBXPtr As IntPtr, _
         ByVal Location As Locations, _
         ByVal Height As Heights, _
         ByRef IamBXLightPtr As IntPtr) As amBX_RESULT

The key points here are:

  1. Make sure you have the CallingConvention attribute set right. Most C libraries will be CDECL, but some libraries are STDCALL.
  2. Make sure your parameter types match, especially in their sizes. Not doing this will lead to corrupted called or system crashes.

Now, create a variable for the delegate and use the Marshal.GetDelegateFromFunctionPointer function to create a new instance of the delegate, based on the applicable function pointer. Since the function pointer for the CreateLight function is stored in the CreateLightPtr field of the _IamBX structure, we pass that in as the pointer argument.

IMPORTANT NOTE: There are 2 overloads for the Marshal.GetDelegateFromFunctionPointer  function. Be sure to use the one what requires a second argument of the TYPE of the delegate to create. Using the other one will fail at runtime because it won’t be able to dynamically determine the type of delegate to create.

Next, call the function via the delegate, just as if it was a function itself.

Finally, use Marshal.PtrToStructure again to copy the array of function pointers returned into another structure, this one formatted to contain the function pointers of the Light object that just got created.

Dim d As CreateLightDelegate = Marshal.GetDelegateForFunctionPointer(_IamBX.CreateLightPtr, GetType(CreateLightDelegate))
Dim r = d(_IamBXPtr, Location, Height, _IamBXLightPtr)
_IamBXLight = Marshal.PtrToStructure(_IamBXLightPtr, GetType(IamBX_Light))

The amBX library is much, much larger than just this little bit I’ve shown here. Once I get the entire thing coded up, I’ll be presenting it here as well.

But in the meantime, if you have a need to interface with C style function pointer objects, don’t let anyone tell you it can’t be done in VB.net

Final Note

As you may or may not have guessed, amBX is a 32bit library and its interfaces, functions and arguments all live in 32bit land. If you’re working with VS2008, BE SURE to set your project to the x86 platform, and NOT “Any CPU” or “x64”! The default, for whatever reason is “Any CPU”, which means things will work properly when run under 32bit windows, but things won’t work well at all if run under a 64bit OS.

Nasty, Nasty x64 and the AnyCPU Option

0
Filed under .NET, VB Feng Shui

At one point a while back (while I was still working for my previous company), we had “support for x64” handled down as a request for an interim version.

I thought, “No sweat”. Grab a few alternative prerequisite MSIs, determine the bitness of the processor you’re on in the install (InstallShield has the functionality built in), and just fire off the appropriate preqs. Our actual application is 32bit, and we had no intention or need to compile as 64bit.

Well. A few clicks later and the install was built and deployed to a test machine.

Crash.

Initial sample database didn’t get deployed properly.

Ok, why not. Well. Long story short, the application couldn’t find a registry key setting. But I hadn’t changed anything about the registry.

Lots of digging through verbose install logs later, and I discovered that the installer was, on a 64bit OS creating registry keys under the key  HKEY_CURRENT_USER\Software\Wow6432Node whereas when my application when to get the registry key, it was looking in the normal HKEY_CURRENT_USER\Software\ key.

Huh?!

First, what the hell was this Wow6332Node? Obviously it’s some kind of “compatibility” bit for running 32bit apps under a 64bit OS. And that’s exactly what it is.

Ok, my Installer is InstallShield, and it’s a 32bit app (even if it can install 64bit packages), so that explains why it was writing the key to that Wow6432Node, but why wasn’t my application reading it from there?

A little digging later, and I found this option buried in the “Advanced Compiler Settings” panel of the “Compile Options” tab of the Project’s properties.

image

See that AnyCPU setting? When set to AnyCPU, the JIT compiler will dynamically compile your .net dll as either a 32bit or 64bit dll, depending on the process that loaded it.

Obviously, on a 32bit OS, all the processes will be 32bit, so everything’s 32bit.

BUT, on a 64bit OS, things get nastier.

If the DLL runs under a native code 32bit process, it’ll get compiled as 32bit x86 code and run under the Wow32 (Windows On Windows) layer. This explains why the DLL that acts as an AddIn to Word worked just fine. Word is a native 32bit process, so the DLL was ending up executing as 32bit too.

However, the little utility app that creates our initial database was a .net application, and it was set to AnyCPU.

That meant that when IT loaded our DLL, the DLL ended up JITed to 64bit code (because the utility app was set to AnyCPU, so it was JITed to 64bit code because it was a base process and was running under a 64bit OS.

Case closed.

Short version of the story. Since tracing all this down, I’ve learned that for VS2008, the .net team decided to change the default of that option from x86 to AnyCPU, and then, in general, that has been regarded as a bad thing to have done.

The default will be changed BACK to x86 in 2010 apparently, but until then, unless you REALLY need to compile code for AnyCPU, be sure to switch this option back to x86!

Merging Assemblies, the Easy Way (part 1)

0
Filed under Code Garage, Utilities, VB Feng Shui

image Recently, I ran into a need to make use of the Mono.Cecil.dll library from a .net application I was working on. Cecil is a fantastic little project under the Mono project that allows you to interrogate an existing .net assembly (EXE or DLL file) and retrieve all kinds of information about the assembly, from the resources embedded within it to the classes and methods defined, and much more. You can even alter the contents of the assembly and write the new version back out to disk!

The thing is, Cecil comes prebuilt as a C# assembly (a DLL file), and I really did not want to have a second file required for this particular application (it’s just a little command line utility).

My first take was to use Oren Eini’s excellent concept of an assembly locator. My idea here was to embed an assembly as a binary resource, then, when requested, read that resource into a stream, load the assembly from the stream, and resolve references to it via the assembly locator.

I’m still working on that concept, because I think it’s a clever and convenient solution to the problem, but, in researching that, I happened to remember the even easier (as in, no code required at all!) solution of using ILMerge.

ILMerge

If you haven’t already discovered it, ILMerge is a Microsoft research project in the form of a single command line EXE utility, that can “merge” any number of .net assemblies with a “target” assembly, and produce either a .net DLL or EXE output file.

There’s a really good article on CodeProject describing the general use of the program. There’s even a GUI (Gilma) for it.

Automating ILMerge

What the article doesn’t go into is automating the ILMerge process. After all, you won’t want to manually run that command line utility every time you build your application!

The good thing is, it’s trivially easy to automate as long as you take care of one critical step.

  • First, download and install ILMerge from the link above.
  • Once it’s installed be sure to copy the ILMerge.exe utility to somewhere on your path (or add the folder it’s in to your path).
  • Then, grab the Mono.Cecil.dll file (or whatever DLL it is you want to merge into your main project EXE). Put it in the root folder of your project.
  • Go ahead and set a reference to that file, so you still get all the .net intellisense goodness, but be sure to set the Copy Local property for the reference to FALSE (after all, you don’t want to copy this DLL to the output folder along with the application if you don’t actually need it, right?)

    image

  • With that done, you MAY want to mark the DLL you’re embedding as “included in project” from the Solution Explorer.

image If you do this, however, make sure you also set the Copy to Output Folder to “Do not copy” (that’s the default though so it should already be set).

The Tricky Part

One limitation of ILMerge is it that it can’t alter the target assembly “in place”. This means that, for instance, if you want the final resulting executable file name to be called GenerateLineMap (my utility), you can’t have VS compile the assembly to that name. You’ll need to use some other name for the initially compiled assembly.

On the Application tab of the project properties you can change that name, like so:

image

I just added “-Interim” to the Assembly Name.

Now, go to the compile tab of the project properties and click Build Events

image

Insert this as the POST BUILD EVENT

ilmerge /target:winexe /out:”$(TargetDir)$(ProjectName)$(TargetExt)” “$(TargetPath)” “$(ProjectDir)Mono.Cecil.dll”

Notice that the OUT parameter specifies the output file name via the $(ProjectName) variable (which is still “GenerateLineMap”) while the first assembly to merge is specified using the $(TargetPath) variable (which is the full filename of the output assembly, including the “-Interim”).

image

EDIT: Important note: Notice the /target:winexe option. You’ll need to change that as appropriate depending on the type of exe you’re building. In my case, I had a console app where this needed to be set to just /target:exe. Setting it to /target:winexe caused all of the console output functions to just do nothing, which threw me for a bit!

Now, just rebuild the solution and you should see two resulting EXE files in your output folder, one with the “–Interim” (which is the version WITHOUT the embedded Mono.Cecil.DLL file or whatever DLL you’ve chosen) and one WITH the embedded file. As a final cleanup, you may want to add an additional Post build step to remove the “*-Interim” files.

To test, just make sure you DO NOT have the embedded DLL anywhere on the path or in the same folder as the exe and run the exe. If everything went right, your app should work exactly the same as if the embedded DLL was included externally with the app!

Now, your application is back to being a single EXE to distribute, and it was built completely automatically by Visual Studio.

Caveats

You knew there had to be some, right?

The first is that if the dll to embed contains licensing information, it might not work properly after being embedded. I don’t have any DLLs like that to test with, but I’ve read reports about the problem at various sites on the internet. Just something to be aware of.

Second, trying to replace the originally named exe with the newly built one results in VS not being able to debug the exe in the IDE (it throws a message about the assembly manifest being different from what was expected). I haven’t worked that issue out yet. What this means is that you might need to leave any references set to “Copy to Output Folder” while debugging, and not replace the original compiled assembly, just ILMerge it into a new assembly name.

Flipping Video with DirectShow

11
Filed under .NET, Media, Troubleshooting, VB Feng Shui

If you haven’t checked it out already, DirectShowLib.net is pretty much THE way to get at direct show functionallity in VB.net (that is unless you want to spend $$$). Thing is, it’s only a paper thin wrapper over the DirectShow COM api stuff, so there ain’t no hand holding here.

I’d mucked with it for a while and with the help of some of the sample code, got video playing in a form in VB.net fairly easily, but, I needed to flip and/or rotate that video under some circumstances.

After many googles, I finally came across the IVMRMixingControl9 interface that the VideoMixingRenderer9 exposes, but, no matter what I did, I could not cast from a VMR9 to the MixingControl, like so:

Dim Mixer = DirectCast(VMR9, IVMRMixerControl9)

I kept getting an “Interface not implemented”. Then I happened across a post about a wholly different problem, but buried within it was a comment about needing to set the VMR into “mixing mode” in order for it to implement that IVMRMixingControl9 interface. Ugh! DirectShow is nothing if not interfaces. And odd dynamically implemented interfaces at that. Oh well.

A little more digging, and it turns out to be quite easy. Just obtain the IVMRFilterConfig9 interface from your VMR9 object, and call SetNumberOfStreams on it (with and argument 1 or more).

The end result is code that looks like this (remember, this is with a reference to DirectShowLib.net):

DIM FGM = New FilterGraph
Dim VMR9 As IBaseFilter = New VideoMixingRenderer9

FGM.AddFilter(VMR9, "Video Mixing Renderer 9")
Dim FC As IVMRFilterConfig9 = VMR9
FC.SetRenderingMode(VMR9Mode.Windowed)
FC.SetNumberOfStreams(1)

Dim Mixer = DirectCast(VMR9, IVMRMixerControl9)
Mixer.SetOutputRect(0, New NormalizedRect(1, 1, 0, 0))
Mixer.SetAlpha(0, 0.2)

Note that in this case, the SetOutputRect is reversing the output rectangle, so the video is going to end up flipped and upsidedown, exactly what I was needing. I’ve also set the alphachannel to .2, meaning the video is somewhat transparent.

Unfortunately, there doesn’t appear to be any way to rotate the video using the MixingControl, so that is my next topic of research.

VBScript in VB.Net

2
Filed under .NET, ActiveX, Languages, VB Feng Shui

A long (long) time ago, if you wanted your users to be able to enhance your product by add coding logic, you pretty much had two choices:

  • Dig into Lex and Yacc or….
  • Roll your own parser and scripting execution engine.

Then, around the time VB 6 was released, Microsoft introduced VBA. It worked, but it was expensive and a god awful complicated mess to integrate with your app, so outside of Microsoft Office (which even as of Office 2010, still supports it!), very few applications actually made use of it.

Around the same time, the Microsoft Scripting Control was released. This was an ActiveX control you could use from any COM compatible language to embed VBScript. Now, of course, this is VBScript, not a “real” language like C or even VB. But, it was free, easy to obtain, and very easy to use.

As the years have rolled by, .NET has steadily grown in capability and while the Windows Scripting Host exe is still shipped with Windows, the old VBScript and JScript scripting has largely been supplanted by either:

  • ASP and more recently ASP.NET
  • Powershell
  • Dynamically compiled .NET code
  • and likely lots more options I’m not familiar with

Now, all these options are good, and each definitely has it’s place, but, for many purposes, good ol’ VBscript still fits the bit quite nicely.

But can you use it from .NET? And if so, how?

The Tempest in the Teapot

Before I continue, I should point out that any time you start talking about allowing users to add their own code into your application, you’re opening up a huge can of worms that you’ll need to deal with. Things like properly catching exceptions from badly written user code (yeah, that never happens), adding watchdog timers to deal with hung and infinitely looping user code, security concerns, and the like all will have to factor into the decision. You have been warned <g>.

So Simple It Hurts

I had a plugin project recently where I wanted to give the user the ability to write some very simple logic to expand the functionality of the application.

Of course, I wanted to build a full plugin API, but I also wanted to provide a lighter-weight option for those users that didn’t want to dive head-first into a full on .NET project. VBScript seemed like the obvious choice.

A few Google searches later and most everything I found was talking about how to dynamically compile .NET code, which is cool indeed, but not what I was really after. Other articles and posts insisted that users should convert their VBScript code to .NET (ok, yeah, but that’s not really the point now is it?).

Then I did a Google Desktop search of my own system and turned up some VB6 code I’d written ages ago to experiment with the Microsoft Scripting Control.

Now, I know that .NET languages support accessing ActiveX Controls and COM objects in general, but this was pretty old stuff. Would it actually still work?

I cobbled up a dirt simple VB.net project:

Public Sub Main()
    Dim Script = New MSScriptControl.ScriptControl
    Script.Language = "VBScript"
    Script.AddCode("sub Main" & vbCrLf & "MsgBox ""This is a Test"" " & vbCrLf & "End Sub")
    Script.Run("Main")
End Sub

Be sure to add a reference in the VB.net project to the COM object “Microsoft Scripting Control”.

Run it, and lo and behold, I get the “This is a Test” message box, straight from VBScript!

Obviously, there’s lots more to making use of the Scripting Control than just this, but, clearly, VBScript is still very much a choice for adding limited programmable logic to your application.

An Interesting Use of Generics

0
Filed under .NET, VB Feng Shui

I was working on some validation logic today, and was getting heavily into generics in several classes, when I stumbled across an application of generics that I hadn’t see before.

Take the following sample code (granted, it’s trivial, but it should get the idea :

Public Class Form1
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim s As String = "Testing"
        GenericTest(s)

        Dim i As Integer = 5
        GenericTest(i)

        Dim f As Single = 10.7
        GenericTest(f)
    End Sub
End Class


Public Module Generics
    Public Sub GenericTest(Of t)(ByVal Variable As t)
        Debug.Print(Variable.ToString)
    End Sub
End Module

Notice that the GenericTest function is early bound directly to 3 different variable types due to the use of generics. Just like using object type variables but without some of the stigma <g>.

Also note that GenericTest is defined in a module. I’d only seen generics as a way of defining classes before, never just a single function, and certainly not a function in a module.

Anyway, this may be old hat for many VB.net people, but I found it interesting, at the least. Not exactly sure how I might leverage it at this point, but it’s always good to have things like this in your toolbox.

DataContractSerializer is Not Necessarily Wonderful

0
Filed under .NET, VB Feng Shui, XML

Serializing objects in .NET is surprisingly easy, and there are a number of different ways to go about the process.

One method that was recently brought to my attention is the DataContractSerializer.

To use it, you’ll need to:

Imports System.Runtime.Serialization

Then create an new instance of a DataContractSerializer and a stream and finally, use the Serializer object to write a serialized version of some other object to the stream. I won’t delve into that code here, there’s plenty of examples on the web; even the Microsoft Help page for that object has a decent example.

But what you won’t find mentioned is how incredibly brittle the serializer can be.

First off, it doesn’t round trip the serialized XML, at least not completely. Say you serialize an object to an XML file, then EDIT that file and add comments. If you then deserialize and reserialize the object, you loose all your comments.

While this is somewhat understandable, it is rather unfortunate. Too bad that’s only the lesser of the problems you’ll face.

Another issue is one that plagues XML in general. It’s CASE SENSITIVE. This makes hand editing the files tricky at best. Now, I know a lot of you might say “Jeez, stop hand editing your XML!” but, let’s be realistic. Sometimes, that’s just flat the fastest way to deal with certain issues.

But the real stumper for me was when I recently discovered that the DataContractSerializer is highly dependent on the ORDER of the XML elements in the serialized XML! That’s right, get elements out of the order that the serializer expects them in (and yet still have perfectly legal and reasonable XML) and the serializer fails. But what’s worse is that it fails silently. It just simply fails to deserialize certain property values if their xml elements aren’t in the “proper” order (which happens to be alphabetic, but still, XML should not be order dependent).

There’s a short write up on it here, but even the author, Aarron Skonnard, doesn’t comment on the fact that if elements are out of order, they won’t deserialize properly.

From what I’ve read, that order dependency is partly why the DataContractSerializer is up to 10% faster than some other serialization techniques. And, if you know that your serialized objects will ONLY ever be touched by code that is intended to work with them, that’s probably ok.

But it’s something to be very aware of if you intend on the serialized XML being visible to (or editable by) actual people.

Finding the True File Location of an Executing .NET DLL

0
Filed under .NET, VB Feng Shui

image Say you’ve written a .NET DLL and you need to know from what folder that DLL was loaded (so you can find resources, config files, whatever).

There are any number of ways to skin that cat, but unfortunately, most won’t work in the general case, but only under certain special circumstances.

Matthew Rowan does a really good job of explaining the differences here, so I’m not going to repeat his post, but the short version of the story is, it takes code that looks like this:

Dim assemblyUri As Uri = New Uri(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase))
Return assemblyUri.LocalPath

Note that this is the VB version of Matthew’s clip. There a a number of other methods, but they all seem to return bogus results under various conditions.