5

我想编写一个 WinMerge 插件来将 SQLite 数据库转换为文本,这样我就可以使用 WinMerge 来比较数据库。

我已经用 C# 编写了代码来进行转换,但我似乎无法让它显示为 WinMerge 插件。但我对编写 COM 可见的 .NET 对象不是很熟悉。

我想我一定没有放入正确的 COM 属性(我只是将 ComVisible(true) 放在类上)。但是,我认为 VB.Net 应该为您完成所有这些工作,因此我使用 Project/Add New/COM 类重写了 VB.Net 中的类。但是,它仍然没有作为加载插件出现在 WinMerge 中。

无奈之下,我尝试使用 DLL Export Viewer 查看 VB DLL,但没有显示任何导出的函数。我显然做错了什么。

这是完整的代码:

<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
4

1 回答 1

1

我刚刚查看了 WinMerge 2.14.0 的实际代码,我认为它只适用于真正的 COM DLL(和 OCX),主要是因为它不需要注册 COM 对象即可工作。需要将其扩展为至少引用 .TLB 或进行调整以允许不指定路径,但允许指定比“WinMergeScript”更明确的 ID。


在我明确提到的工作 VB.NET COM 对象<ComVisible(True)> _中,项目在编译属性中检查了“注册 COM”。

我刚刚HelloWorld使用您的代码创建了一个函数,将其编译vbc /t:library并使用regasm /codebase. 这是使用这个简单的 vbscript 成功调用的(使用wscript):

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

以及整个代码(我没有重新配置我的系统以供以后使用,vbc因此实际上已编译为 .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
于 2012-11-01T15:25:33.550 回答