Drydo's Blog

Teenager of the Internet

This blog hosted by:
http://blogs.vbcity.com
  Home :: Syndication  :: Login   Community Forums   :: vbCity.com   :: DevCity.NET  

Wednesday, April 23, 2008 #

So firing up Expression Blend and getting into the whole WPF thing is always a refreshing change, especially getting away from mundane coding and alike. However, the first thing to trip me up and my colleague up was using the "Edit Externally" command from the project view to edit an existing '.png' file and whipping into my favourite graphics editor. Imagine my surprise when I was greeted with MSPaint! How there are two things to consider here...

  1. I used to be a design guy prior to becoming a programmer, so MSPaint is the last thing I need to see.
  2. Two - MSPaint is in no way anything like a sophisticated design application. Just get used to it ;-)

Now the doomsayers and conspiracy freaks might consider that MS has done this on purpose, so I fired up Reflector to work out how the project items (such as image files) were actually being catagorised and executed. What Blend does is by using the old .NET standby of Process.Start but explicitly passing through the 'Edit' string as the 'Verb' when making the call. In short, they're letting explorer handle the file association. Note: this works differently from explorer where if you double-click an existing and recognised dot extension it fires up the application with the selected file because its using the 'Open' verb and not the 'Edit' verb.

Ideally, Blend should use the 'Open' verb rather than hardcoding the 'Edit' verb (well, selection that is then implemented in the EditExternalCommand object) into the 'DocumentType.PreferredExternalEditCommand' property. Or even better - allow the user to specify those application they want for editing resources. But hey, its version 1.

So to get around this, a quick registry tweak will get things working. Navigate to the key...

HKEY_CLASSES_ROOT\SystemFileAssociations\image\shell\edit\command

...and change the value of the '(Default)' value to your favourite package from...

"%systemroot%\system32\mspaint.exe" "%1"

...to , so in my case to Fireworks...

"C:\Program Files\Macromedia\Fireworks 8\Fireworks.exe" "%1"

...and job done + no need restart...

HTH - And remember this fix / hack comes without warranty and will effect other instances where applications use this key as well. In short, be careful and backup your registry before doing this.

posted @ 1:34 PM | Feedback (0)

Wednesday, March 26, 2008 #

A very quick one. Been playing with the above class for generating emails in .NET 2.0, embedding images within HTML views which is rather cool. However, I noticed an unusual problem. The emails I generated in my test project would not send until I had exited the application. It was almost like it would only 'flush' the generated email once the application had unloaded. Interestingly, if I attempted to send the email using the 'SendAsync' method, it would fire the SendCompleted event but still nothing would come through until the application had ended.

The resolution? Turning off Symantec Anti-Virus's 'Internet Email Auto-Protect' facility from the 'Configure' menu. Once deselected, everything started behaving properly.

I cannot answer for any other AntiVirus packages - but its a good starting point if you're experiencing the above.

M

posted @ 4:07 PM | Feedback (0)

Monday, March 03, 2008 #

To be quite frank, after 3 months of ASP.NET development, the opportunity to do some down and dirty API programming really appealled to me today. So, the question (as indicated by the title) involved a member wanting to disable the right-click context menu from the Flash ActiveX component when being used in a WinForms application. (See previous blog entries for examples of Flash in VB.NET and communication between the two such as http://blogs.vbcity.com/drydo/archive/2005/10/18/5586.aspx).

The simple answer is to capture the right-click of the Flash Window itself and prevent it from being processed. A little play with Spy++ quickly came up with the answers and the rest was all about good old fashioned subclassing. I must admit it pinched the API declarations from Pinvoke.net and smartened them up a tad and that is pretty much it.

For the record, this is something I've been meaning to do for a while + I can leave work not feeling like some CSS floozy :)

Note: to recreate, create one form, one button and add one Flash Active X control. Copy and Paste as necessary. Tested in VS2005. If you get the dreaded 'Failed to import the ActiveX control' message, check out this workaround

Imports System.Runtime.InteropServices

Public Class Form1

#Region "API Routines"

    <DllImport("User32.dll")> _
   Private Shared Function EnumChildWindows _
       (ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowProcess, _
       ByVal lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, _
   ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer)
    End Sub

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As Integer) As Integer End Function <DllImport("user32.dll", CharSet:=CharSet.Auto)> _ Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As FlashCaptureRoutine) As Integer End Function <DllImport("user32.dll", CharSet:=CharSet.Auto)> _ Private Shared Function CallWindowProc(ByVal lpPrevWndFunc As Integer, ByVal
hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer End Function #End Region #Region "Delegates" ' Used for processing Flash Window messages Public Delegate Function FlashCaptureRoutine(ByVal hwnd As Integer, ByVal
Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer ' Used for enumerating child windows Public Delegate Function EnumWindowProcess(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean #End Region ' Constants Public Const GWL_WNDPROC As Integer = (-4) Public Const WM_ENTERMENULOOP As Integer = &H211 Public Const WM_RBUTTONDOWN As Integer = &H204 Public Const WM_INITMENU = &H116 ' Private vars Private mFlashWindowHandle As IntPtr Private mPreviousHandle As Integer Private isCapturing As Boolean Private Sub Form1_FormClosing(ByVal sender As Object, ByVal
e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing ' Cleanup if appropriate If isCapturing Then CleanupCapture() End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles MyBase.Load ' Load the test movie... Me.AxShockwaveFlash1.Movie = "MyTestMovie.swf" Me.AxShockwaveFlash1.Menu = True End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles Button1.Click ' Capture / Reset Flash Window Processing as appropriate ' React as approrpiate If isCapturing Then ' Resume CleanupCapture() Else ' Capture events CaptureRightClick() End If ' Switch over the flag isCapturing = Not isCapturing End Sub Private Sub CaptureRightClick() ' Attempt to obtain the Flash Window EnumChildWindows(Me.Handle,
AddressOf EnumWindow, IntPtr.Zero) ' Subclass using new routine storing the old result mPreviousHandle = SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, AddressOf FlashWindowCapture) End Sub Private Sub CleanupCapture() ' Reset back to the original handle... SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, mPreviousHandle) End Sub Private Function FlashWindowCapture(ByVal hwnd As Integer, ByVal Msg As Integer,
ByVal wParam As Integer, ByVal lParam As Integer) As Integer ' Capture the appropriate message and prevent it from being processed Select Case Msg Case WM_RBUTTONDOWN ' Exit Exit Function End Select ' Carry on... Return CallWindowProc(mPreviousHandle, hwnd, Msg, wParam, lParam) End Function Private Function EnumWindow(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean ' Obtain the class name of the child window Dim ClassName As New System.Text.StringBuilder("", 255) GetClassName(Handle, ClassName, ClassName.MaxCapacity) ' Is this the Flash Window? If ClassName.ToString = "MacromediaFlashPlayerActiveX" Then mFlashWindowHandle = Handle End If Return True End Function End Class

posted @ 4:42 PM | Feedback (0)

Monday, January 28, 2008 #

I guess as developers we're used to solving the difficult problems, this task isn't working because of dependancy X, Y and Z - so we code around that, handshake with this and validate the other. But as a developer its always the simple things that catch you out.

For instance, I've spent the last 4 hours messing around with loading a comma delimited textfile into a typed dataset using one dataadapter, do some funky things to it and then upload those records into an SQL Server using an SQLDataAdapter. Sounds easy, and it is - check out this previous post for an example.

So, I coded it up and interestingly it loaded the datarows correctly - but all the fields were NULL! Now things shouldn't be more easier than this - you SELECT the data, it flys into the strongly typed dataset and job done. I then spent my time working backwards through the code, exploring the various problems that might be occuring (tablemapping and that kinda thing). However, the problem was much easier to diagnose - basically, a similar issue came up in the forums with someone using the same code as linked and the answer was...

Change the file extension of the textfile being imported! It turns out that the JET driver has certain restrictions placed upon it, by using a '.txt' extension it was expecting a tab delimited file - by changing the extension to '.csv' everything started working. Check out this MS Support Page on the very subject, where only certain file extensions are supported and are subtlly dealt with in different ways.

HTHs somebody - M

posted @ 11:22 AM | Feedback (0)

Thursday, January 24, 2008 #

This course was created for the VBCity Academy where you can take online courses for free. Unfortunately, the material I wrote is something I constantly want to keep linking to - so I've decided to place the course up as a flat article.

I fully recommend that the take the course through the Academy where the structure and flow of the course should make a little more sense - however, if big long documents are your thing - check out the article at http://blogs.vbcity.com/drydo/articles/8959.aspx.

posted @ 9:55 AM | Feedback (0)