C#.NET的COM DLL破坏了与VB6应用程序的引用关系

5

我有一个用C#.NET编写的DLL库,它暴露出COM接口,这样vb6应用程序就可以调用我的DLL库。这个接口看起来像这样:

   [System.Runtime.InteropServices.Guid("3D2C106C-097F-4ED7-9E4F-CDBC6A43BDC4")]
    public interface IZDPharmaManager {
        [System.Runtime.InteropServices.DispId(2)]
        SearchPatientEventArgs FoundPatient { get; set; }
        [System.Runtime.InteropServices.DispId(3)]
        IntPtr Start(string server, string database, string user, string password, bool integrated, int praktijkID, string userGUID, int userID, string userName, bool hasRightToSearchPatient);
        [System.Runtime.InteropServices.DispId(4)]
        void Stop();
        [System.Runtime.InteropServices.DispId(5)]
        void InitializeSkinner(System.Object skinnerFramework);
    }

[System.Runtime.InteropServices.Guid("4438852E-CF2D-4DB0-8E6E-428F65A6B16C")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IZDPharmaManagerEvents {
    [DispId(1)]
    void SearchPatient(ZDPharmaManager sender, SearchPatientEventArgs e);
}

   [System.Runtime.InteropServices.Guid("9297D43F-C581-3F0F-AA60-9506C6B77B5F")]
    [ClassInterface(ClassInterfaceType.None)]
    public class SearchPatientEventArgs : WebHIS.ZDPharmaceutisch.ISearchPatientEventArgs {

        public SearchPatientEventArgs() {
            //Nodig voor COM.
        }

        public int ID { get; set; }
        public string FullName { get; set; }
        public string OwnName { get; set; }
        public string PartnerName { get; set; }
        public string DateOfBirth { get; set; }
        public string ZipCode { get; set; }
        public string HouseNumber { get; set; }
        public string BSN { get; set; }
    }

    public delegate void SearchPatientEventHandler(ZDPharmaManager sender, SearchPatientEventArgs e);

    [System.Runtime.InteropServices.Guid("465AC7EC-27EF-3D95-AAA6-29D01FCF15A1")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IZDPharmaManagerEvents))]
    public class ZDPharmaManager : WebHIS.ZDPharmaceutisch.IZDPharmaManager {

        public event SearchPatientEventHandler SearchPatient = null;

        public SearchPatientEventArgs FoundPatient { get; set; }

        //private MainForm GraphicalInterface { get; set; }
        private ChoosePatient GraphicalInterface { get; set; }

        public ZDPharmaManager() {
            //Nodig voor COM.
        }

        #region IZDPharmaManager Members

        public IntPtr Start(string server,
            string database,
            string user,
            string password,
            bool integrated,
            int praktijkID,
            string userGUID,
            int userID,
            string userName,
            bool hasRightToSearchPatient) {

            //Zet connectiestring.
            DAL.DAC.CnnInfo = new System.Data.SqlClient.SqlConnectionStringBuilder() {
                DataSource = server,
                InitialCatalog = database,
                UserID = user,
                Password = password,
                IntegratedSecurity = integrated
            };

            DAL.DAC.PracticeID = praktijkID;
            DAL.DAC.UserGUID = userGUID;
            DAL.DAC.UserID = userID;
            DAL.DAC.UserName = userName;
            DAL.DAC.HasRightToSearchPatient = hasRightToSearchPatient;

            //Apotheek IDs ophalen en bewaren.
            DAL.DAC.PharmacyIDs = DAL.PracticeDAO.GetPharmacyByPracticeID(praktijkID);

            //Initialiseer grafische interface.
            //this.GraphicalInterface = new MainForm();
            this.GraphicalInterface = new ChoosePatient();

            //Haal ongekoppelde afhaalberichten op.
            this.GraphicalInterface.Patients = new VML.PatientsVM(this);

            //Toon grafische interface.
            this.GraphicalInterface.Show();

            return this.GraphicalInterface.Handle;

        }

        public void Stop() {
            foreach (var item in this.SearchPatient.GetInvocationList()) {
                this.SearchPatient -= (SearchPatientEventHandler)item;

            }
            this.GraphicalInterface.Close();
            this.GraphicalInterface = null;
            this.FoundPatient = null;
        }

        public void InitializeSkinner(System.Object skinnerFramework) {

            WebHIS.ZDPharmaceutisch.SkinnerModule.SkinFramework = (XtremeSkinFramework.SkinFramework)skinnerFramework;

        }
        #endregion

        internal virtual void OnSearchPatient(SearchPatientEventArgs e) {
            if (this.SearchPatient != null) {
                this.SearchPatient(this, e);
            }
        }


    }

这很正常。但是,每次在不更改接口的情况下构建此DLL(因为我必须在逻辑上修复某些内容),与vb6应用程序的引用就会中断,我们需要重新编译vb6应用程序。
有人知道我做错了什么吗?因为我们有vb.net DLL,由于固定的GUID,在重新编译后不会破坏引用。任何帮助都将不胜感激。
更新: vb6应用程序和DLL均已操作。但是,当我重新编译DLL并通过vb6应用程序在我们的测试服务器上进行测试时,我会收到自动化错误(这通常意味着引用已损坏,并且您需要重新编译vb6应用程序)。

我不太确定你的意思,但如果你已经附加了引用并且现在正在更改你的dll,那么你需要在每次编译dll后至少关闭VB6或释放对dll的引用。 - user2140173
这确实不是我的意思。vb6应用程序和DLL都可以运行。但是,当我重新编译DLL并通过vb6应用程序在我们的测试服务器上进行测试时,我会收到自动化错误(通常意味着引用已损坏,您也需要重新编译vb6应用程序)。 - Danny van der Kraan
你的 DLL 中的其他公共类可能会获得自动 UUID / GUID,当你重新编译时会发生变化。最近我看到一个例子似乎就是这样。 - StayOnTarget
1个回答

11

我看不到任何能解释这个问题的强烈线索。程序集的[Guid]属性很重要,它设置了类型库ID, 而[AssemblyVersion]也很重要,它设置了类型库版本号。这些属性在项目的AssemblyInfo.cs文件中声明。确保您的构建系统不会修改这些属性。

最好的方法是找出确切变化的地方。从Visual Studio命令提示符中运行OleView.exe实用程序。文件+查看类型库,然后选择.tlb文件。将右侧面板的内容复制/粘贴到文本文件中。

重新构建项目并重复上述步骤。现在,您可以使用差异工具轻松查看确切的更改内容。如果需要更多帮助,请更新您的问题并描述您发现的情况。


非常感谢您向我解释OleView.exe。通过这个工具,我能够发现程序集暴露了更多的内容,而且正在生成GUID(这当然会破坏引用)。 - Danny van der Kraan
@DannyvanderKraan你能提供一些关于意外暴露的细节吗?谢谢。 - StayOnTarget
@DaveInCaz 抱歉,我几乎3年前就问过这个问题了,我记不清了。问题的要点是,尽管我认为构建过程没有改变我的程序集的API,但实际上确实改变了。我是通过Hans上面描述的方法发现的。 - Danny van der Kraan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接