|
version: 1.0.0.0 last updated: 4 January 2003 You would expect regular VB.NET events to work when using SQL-DMO events. The code that does not workSo you would expect the following VB.NET code to work as expected: Imports System.Runtime.InteropServicesImports SQLDMO Module BackupWithEvents<MTAThread()> _ Sub Main() Dim app As App app = New App() app.Run() End Sub End Module Public Class AppDim server As SQLDMO.SQLServer2Class Dim database As SQLDMO.Database2 Dim backup As SQLDMO.Backup2 Dim WithEvents backupEvents As SQLDMO.Backup2 Public Sub Run() server.LoginSecure = True database = server.Databases.Item("pubs") backup.Database = database.Name server.DisConnect() Catch ex As System.Runtime.InteropServices.COMException Private Overloads Sub backupEvents_Complete(ByVal Message As String) Handles backupEvents.Complete Private Overloads Sub backupEvents_NextMedia(ByVal Message As String) Handles backupEvents.NextMedia Private Overloads Sub backupEvents_PercentComplete(ByVal Message As String, ByVal Percent As Integer) _ Download BackupWithEvents.zip The wrong resultsHowever when you look at the results is shows like: As you can see there is something wrong, the CompleteEventHandler fires 3 times, the other ones never fires at all. If you would change the order of linking the delegates you will see that the first event handler that you register is the one and only one that fires. The problemThis behavior is caused by the fact that TLBIMP.EXE, which generates the Runtime Callable Wrappers (RCW) for the SQL-DMO COM library, creates a separate event interface implementation for each delegate rather than having a single interface with multiple functions. It appears that for every event that you want to be advised on, a new “sinkhelper” object, is being created and advised. As a result if one of the events is *dependent* on return value of another event you get unexpected results. The solutionTechnically there are two solutions, the first is to create your own RCW which implements the events handlers correctly using a single interface with multiple functions. This however requires a lot of coding for just handling events. The second solution provides a workaround for the problem using the UCOM interfaces to Advise our own implementation of the sink interface. To properly handle the events, the Visual C# .NET application must implement the IConnectionPointContainer and IConnectionPoint interfaces. The .NET Framework provides managed definitions of these interfaces through the UCOMIConnectionPointContainer and UCOMIConnectionPoint interfaces. These interfaces are part of the System.Runtime.InteropServices namespace. Using the workaroundWhen using the UCOM interfaces the code will look like this: Imports System.Runtime.InteropServicesImports SQLDMO Module App <MTAThread()> _ Sub Main() Dim server As SQLDMO.SQLServer2Class Dim database As SQLDMO.Database2 Dim backup As SQLDMO.Backup2 Try server.LoginSecure = True backup.Database = database.Name 'Begin - set up events sink backup.Database = database.Name cpPoint.Unadvise(intCookie) server.DisConnect() Catch ex As System.Runtime.InteropServices.COMException Public Class BackupSinkImplements SQLDMO.BackupSink Public Sub Complete(ByVal Message As String) Implements SQLDMO.BackupSink.Complete Public Sub NextMedia(ByVal Message As String) Implements SQLDMO.BackupSink.NextMedia Public Sub PercentComplete(ByVal Message As String, ByVal Percent As Integer) Implements SQLDMO.BackupSink.PercentComplete Download BackupWithEventsFix.zip The correct resultsserver (local) Other SQL-DMO event sink interfacesIf you want to apply the same technique for other SQL-DMO objects that emit events you need to know the GUID of the interface for the event sink, this is the list of objects and the interface UUID for the various event sink interfaces in SQL-DMO
In case you are wondering how to find this information yourself, use OLEVIEW to find the sink interfaces in the type library. *** |
Questions or problems regarding this web site should be directed to Web Master. |