2012-10-23 16 views
5

Vorrei scrivere un plugin WinMerge per tradurre i database SQLite in testo, quindi posso usare WinMerge per confrontare i database.Come scrivere un plugin WinMerge in C# (o VB.NET)

Ho scritto codice in C# per fare la conversione, ma non riesco a farlo apparire come un plugin WinMerge. Ma non ho molta familiarità con la scrittura di oggetti .NET COM-visible.

Ho pensato di non aver inserito gli attributi COM corretti (ho appena inserito ComVisible (true) sulla classe). Tuttavia, penso che VB.Net dovrebbe fare tutto questo per te, quindi ho riscritto la classe in VB.Net, usando Project/Add New/COM class. Tuttavia, non appare ancora in WinMerge come plugin caricato.

In preda alla disperazione, ho provato a guardare la DLL VB utilizzando DLL Export Viewer, ma non mostrava alcuna funzione esportata. Sto ovviamente facendo qualcosa di sbagliato.

Ecco il codice per intero:

<ComClass(WinMergeScript.ClassId, WinMergeScript.InterfaceId, WinMergeScript.EventsId)> _ 
Public Class WinMergeScript 

#Region "COM GUIDs" 
    ' These GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class. 
    Public Const ClassId As String = "9b9bbe1c-7b20-4826-b12e-9062fc4549a0" 
    Public Const InterfaceId As String = "b0f2aa59-b9d0-454a-8148-9715c83dbb71" 
    Public Const EventsId As String = "8f4f9c82-6ba3-4c22-8814-995ca1050de6" 
#End Region 

    Dim _connection As SQLite.SQLiteConnection 
    Dim _output As IO.TextWriter 
    Dim _error As Long 
    Dim _errordesc As String 

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject. 
    Public Sub New() 
     MyBase.New() 
    End Sub 

    Public ReadOnly Property PluginEvent() As String 
     Get 
      PluginEvent = "FILE_PACK_UNPACK" 
     End Get 
    End Property 

    Public ReadOnly Property PluginDescription() As String 
     Get 
      PluginDescription = "Display Sqlite Databases in tab-delimited format" 
     End Get 
    End Property 

    Public ReadOnly Property PluginFileFilters() As String 
     Get 
      PluginFileFilters = "\.db$" 
     End Get 
    End Property 

    Public ReadOnly Property LastErrorNumber() As Long 
     Get 
      LastErrorNumber = _error 
     End Get 
    End Property 

    Public ReadOnly Property LastErrorString() As String 
     Get 
      LastErrorString = _errordesc 
     End Get 
    End Property 

    Public Function UnpackFile(ByVal fileSrc As String, ByVal fileDst As String, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean 
     On Error GoTo CleanUp 
     subcode = 1 
     _error = 0 
     _errordesc = "" 
     Using connection As New SQLite.SQLiteConnection("Data Source=" + fileSrc + ";Version=3;DateTimeFormat=ISO8601;") 
      _connection = connection 
      Using output As New IO.StreamWriter(fileDst) 
       _output = output 
       For Each table As DataRow In Query("Select name from sqlite_master where type = 'table' order by name") 
        Dump(table(0).ToString()) 
       Next 
      End Using 
     End Using 
     bChanged = True 
     UnpackFile = True 
     Exit Function 
CleanUp: 
     _error = Err().Number 
     _errordesc = Err().Description 
     bChanged = False 
     UnpackFile = False 
    End Function 

    Sub Dump(ByVal tablename As String) 
     Dim reader As IDataReader 
     Using cmd As New SQLite.SQLiteCommand(_connection) 
      cmd.CommandText = "Select * from """ + tablename + """" 
      cmd.CommandType = CommandType.Text 
      reader = cmd.ExecuteReader() 
      Using reader 
       _output.WriteLine("==== " + tablename + " ====") 
       Dim data(reader.FieldCount) As String 
       For i As Integer = 0 To reader.FieldCount - 1 
        data(i) = reader.GetName(i) 
       Next 
       Dump(data) 
       While reader.Read() 
        For i As Integer = 0 To reader.FieldCount - 1 
         data(i) = reader.GetValue(i).ToString() 
        Next 
        Dump(data) 
       End While 
      End Using 
     End Using 
    End Sub 

    Sub Dump(ByVal data() As String) 
     _output.WriteLine(String.Join(vbTab, data)) 
    End Sub 

    Function Query(ByVal sql As String) As DataRowCollection 
     Dim cmd As SQLite.SQLiteCommand 
     cmd = _connection.CreateCommand() 
     Using cmd 
      cmd.CommandText = sql 
      Using da As New SQLite.SQLiteDataAdapter(cmd) 
       Dim dt As New DataTable() 
       da.Fill(dt) 
       Query = dt.Rows 
      End Using 
     End Using 
    End Function 
End Class 

risposta

1

Ho appena rivisto il codice effettivo della WinMerge 2.14.0, e penso che funziona solo per le DLL vera COM (e OCX), soprattutto a causa funziona senza aspettarsi che gli oggetti COM vengano registrati. Dovrebbe essere espanso per fare riferimento almeno a .LB o adattato per non specificare alcun percorso, ma un ID più esplicito di "WinMergeScript".


in un oggetto COM VB.NET lavoro ho citato esplicitamente <ComVisible(True)> _ e il progetto è "Registrati COM" selezionata nella finestra delle proprietà di compilazione.

Ho appena creato una funzione HelloWorld utilizzando il codice, compilato con vbc /t:library e registrato con regasm /codebase. Questo è stato chiamato con successo utilizzando questo semplice VBScript (utilizzando wscript):

Option Explicit 
Dim so 
Set so = CreateObject("SO13035027.WinMergeScript") 
MsgBox so.HelloWorld 

E l'intero codice (non ho riconfigurare il mio sistema di utilizzare un secondo vbc quindi questo è stato effettivamente compilato a .NET 1.1):

Option Explicit On 
Option Strict On 
'Option Infer On 

Imports Microsoft.VisualBasic 

Namespace SO13035027 
<ComClass(WinMergeScript.ClassId, WinMergeScript.InterfaceId, WinMergeScript.EventsId)> _ 
Public Class WinMergeScript 

#Region "COM GUIDs" 
' These GUIDs provide the COM identity for this class 
' and its COM interfaces. If you change them, existing 
' clients will no longer be able to access the class. 
Public Const ClassId As String =  "9b9bbe1c-7b20-4826-b12e-9062fc4549a2" 
Public Const InterfaceId As String = "b0f2aa59-b9d0-454a-8148-9715c83dbb72" 
Public Const EventsId As String = "8f4f9c82-6ba3-4c22-8814-995ca1050de2" 
#End Region 

' A creatable COM class must have a Public Sub New() 
' with no parameters, otherwise, the class will not be 
' registered in the COM registry and cannot be created 
' via CreateObject. 
Public Sub New() 
    MyBase.New() 
End Sub 

Public Function HelloWorld() As String 
Return "Hello, world!" 
End Function 

End Class 
End Namespace 
+0

Grazie - Ho aggiunto " _" davanti alla classe WinMergeScript e davanti a ciascuna funzione pubblica. Avevo già spuntato "Rendi COM visibile nell'assemblaggio" nella finestra di dialogo AssemblyInfo, raggiungibile dalle proprietà del progetto, Applicazione, pulsante Info assieme. Non riesco a trovare "Register for COM" ovunque (Visual Studio 2008). Ancora non funziona e il visualizzatore DLL non mostra oggetti o metodi COM nella dll compilata. –

+0

[Più avanti] Ho trovato "Registra per interoperabilità COM" nelle opzioni di compilazione del progetto, ed era già spuntato. –

+0

hai mai funzionato? Se sì: puoi condividerlo? – fabsenet