是否可以在 C# 中的后台工作程序中调用以 this.Handle 作为参数的方法

Is it possable to call a method that takes this.Handle as an argument inside a background worker in C#

我正在使用 C# 编写一个独立的 WinForm 程序,该程序使用 Solidworks EPDM api。该程序采用顶级程序集并在程序集中查找所有引用和引用文件。例如所有子组件、零件文件和工程图。然后程序从 EPDM 中检出所有文件,更新数据卡,并将所有文件检入回 EPDM。

我已经成功地实现了使用后台工作者找到所有引用和引用文件并更新数据卡信息的代码部分。这部分代码不需要访问 UI 线程。我希望能够添加代码来检出文件并在后台工作人员中将它们检回。问题是用于执行结帐和签入的方法将 this.Handle 作为参数。我知道从后台 worker 中访问 UI 线程会抛出跨线程异常。该代码不访问任何 UI 控件。它只需要访问 this.Handle。是否可以以线程安全的方式将 this.Handle 传递给后台工作程序,不会引发跨线程异常?

这是我第一次使用后台工作者,所以我的知识有限。下面是我想在后台工作人员中 运行 的代码。

    private void BatchCheckout(Dictionary<string, string> SelectedFiles)
    {
        try
        {
            IEdmBatchGet batchGetter = (IEdmBatchGet)vault.CreateUtility(EdmUtility.EdmUtil_BatchGet);           
            EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];            
            IEdmFile5 aFile;
            IEdmFolder5 aFolder;
            IEdmFolder5 ppoRetParentFolder;
            IEdmPos5 aPos;
            int i = 0;

            foreach (KeyValuePair<string, string> kvp in SelectedFiles)
            {
                aFile = vault1.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
                aPos = aFile.GetFirstFolderPosition();
                aFolder = aFile.GetNextFolder(aPos);
                ppoSelection[i] = new EdmSelItem();
                ppoSelection[i].mlDocID = aFile.ID;
                ppoSelection[i].mlProjID = aFolder.ID;
                i = i + 1;
            }
            batchGetter.AddSelection((EdmVault5)vault1, ref ppoSelection);
            batchGetter.CreateTree(this.Handle.ToInt32(), (int)EdmGetCmdFlags.Egcf_Lock);
            batchGetter.GetFiles(this.Handle.ToInt32(), null);
        }

        catch (System.Runtime.InteropServices.COMException ex)
        {
            MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
        }
    }

多年来,我一直是 Whosebug 的 reader,几乎所有我遇到的问题都找到了答案。这是我在 Whosebug 上的第一个问题。我真的希望有人能回答这个问题。

编辑:

我已经成功测试了 AndrewK 的建议,很高兴地报告它确实适用于我的批量结帐方法。当我 运行 我在后台工作程序中的批量签入方法时,我收到以下 COM 异常:

无法将类型 'System.__ComObject' 的 COM 对象转换为接口类型 'EPDM.Interop.epdm.IEdmBatchUnlock2'。此操作失败,因为 IID 为“{F0970446-4CBB-4F0F-BAF5-F9CD2E09A5B3}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:不支持此类接口(HRESULT 异常:0x80004002(E_NOINTERFACE)).

如果我 运行 来自后台工作人员的代码,我只会得到这个异常。

这是我的 BatchCheckin 方法的代码:

    private void BatchCheckin(Dictionary<string, string> SelectedFiles)
    {
        try
        {
            int i = 0;
            IEdmFolder5 ppoRetParentFolder;
            IEdmFile5 aFile;
            IEdmFolder5 aFolder;
            IEdmPos5 aPos;
            EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];
            IEdmBatchUnlock2 batchUnlock;

            foreach (KeyValuePair<string, string> kvp in SelectedFiles)
            {
                aFile = vault5.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
                aPos = aFile.GetFirstFolderPosition();
                aFolder = aFile.GetNextFolder(aPos);
                ppoSelection[i] = new EdmSelItem();
                ppoSelection[i].mlDocID = aFile.ID;
                ppoSelection[i].mlProjID = aFolder.ID;
                i = i + 1;
            }

            batchUnlock = (IEdmBatchUnlock2)vault7.CreateUtility(EdmUtility.EdmUtil_BatchUnlock);
            batchUnlock.AddSelection((EdmVault5)vault5, ref ppoSelection);
            batchUnlock.CreateTree(0, (int)EdmUnlockBuildTreeFlags.Eubtf_ShowCloseAfterCheckinOption + (int)EdmUnlockBuildTreeFlags.Eubtf_MayUnlock);
            batchUnlock.Comment = "Updates";
            batchUnlock.UnlockFiles(0, null);
        }

        catch (System.Runtime.InteropServices.COMException ex)
        {
            MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
        }
    }

我在调用 vault7.CreateUtility 时遇到异常。 BatchCheckin 代码几乎与 BatchCheckout 相同。我在两种方法中都对 vault7.CreateUtility 进行了相同的调用。唯一的区别是 EdmUtility 标志在 BatchCheckin 方法中设置为 EdmUtil_BatchUnlock。关于这个 AndrewK 有什么线索吗?

更新:

我能够通过将 batchUpdate 从 IEdmBatchUnlock2 接口更改为 IEdmBatchUnlock 接口来解决 COM 异常。这是代码更改:

    private void BatchCheckin(Dictionary<string, string> SelectedFiles)
    {
        int i = 0;
        IEdmFolder5 ppoRetParentFolder;
        IEdmFile5 aFile;
        IEdmFolder5 aFolder;
        IEdmPos5 aPos;
        EdmSelItem[] ppoSelection = new EdmSelItem[SelectedFiles.Count];
        IEdmBatchUnlock batchUnlock = (IEdmBatchUnlock)vault7.CreateUtility(EdmUtility.EdmUtil_BatchUnlock);

        try
        {
            foreach (KeyValuePair<string, string> kvp in SelectedFiles)
            {
                aFile = vault5.GetFileFromPath(kvp.Key, out ppoRetParentFolder);
                aPos = aFile.GetFirstFolderPosition();
                aFolder = aFile.GetNextFolder(aPos);
                ppoSelection[i] = new EdmSelItem();
                ppoSelection[i].mlDocID = aFile.ID;
                ppoSelection[i].mlProjID = aFolder.ID;
                i = i + 1;
            }               
            batchUnlock.AddSelection((EdmVault5)vault5, ref ppoSelection);
            batchUnlock.CreateTree(0, (int)EdmUnlockBuildTreeFlags.Eubtf_ShowCloseAfterCheckinOption + (int)EdmUnlockBuildTreeFlags.Eubtf_MayUnlock);
            batchUnlock.Comment = "Release to Production ECO";
            batchUnlock.UnlockFiles(0, null);
        }

        catch (System.Runtime.InteropServices.COMException ex)
        {
            MessageBox.Show("HRESULT = 0x" + ex.ErrorCode.ToString("X") + " " + ex.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message + "\n" + GetStackTrace(ex));
        }
    }

我猜测这是 IEdmBatchUnlock2 接口中的错误。如果从后台工作程序调用 IEdmBatchUnlock2 将导致 COM 异常,但如果从 UI 线程调用则不会导致 COM 异常。 IEdmBatchUnlock 接口在从后台工作程序调用时不会导致 COM 异常。

只需在句柄中输入 0。只要您的代码不需要用户输入,它就可以工作。我经常这样做。

        batchGetter.AddSelection((EdmVault5)vault1, ref ppoSelection);
        batchGetter.CreateTree(0, (int)EdmGetCmdFlags.Egcf_Lock);
        batchGetter.GetFiles(0, null);