將 AIM & XNAT 的原始碼和 ClearCanvas 整合在一起

在網路上有個能做醫學影像標記的開源專案 [AIM on ClearCanvas][AIMbin] 他目前出到第 4.5 版,我想要修改其中有發現的一些 bugs. 因為過程中遇到了很多問題,花了很多時間才解決(快整整三天),於是我把我的經驗整理一下,以供日後參考。

嘗試直接修改原始碼

第一直覺就是直接去到他的 [GitHub repo][AIM] 並 clone 下來修改完重新編譯. 然而還未修改就先出現 reference not found 的錯誤訊息。

我在 annotation-and-image-markup\AimPlugin4.5\XnatWebBrowser\XnatWebBrowser.csproj 這個檔案裡發現這行:

<ProjectReference Include="..\..\source_cc\Common\ClearCanvas.Common.csproj">

annotation-and-image-markup\source_cc 這個資料夾卻不存在,這才發現是 repo 內的檔案不完整。

於是我便直接從他提供的執行檔安裝好的資料夾內,把所有會用到的 DLLs 複製到專案資料夾裡,直接 link to dll, 編譯完再替代安裝好的檔案。

找齊所有原始碼

之後又要改其他東西,而不能直接 debug 實在是很致命的耗時,之後便找到了 [ClearCanvas][CCbin] 的 [GitHub repo][CC] 並從 [Readme][CCReadme] 中得知他需要的 [ReferencedAssemblies][CCRef].

如此一來便集齊了所有原始碼:

  1. [NCIP/annotation-and-image-markup][AIM]
  2. [ClearCanvas/ClearCanvas][CC]
  3. [ClearCanvas/ReferencedAssemblies][CCRef]

多個 repository 的整合

我們的主要目的是把 [AIMPlugin4.5][AIMv4.5] 跟 [ClearCanvas][CC] 合併在一起編譯.

首先當然是去看清楚他們 Readme 裡面寫的注意事項。 [ClearCanvas Readme][CCReadme] 裡面有提到資料夾相對位置,和要建立 symbolic link, 再加上應該存在的 annotation-and-image-markup\source_cc 便找出所有 repo 的相對關係。

Root dir
│ [annotation-and-image-markup.git]
│
├─ReferencedAssemblies
│   [ReferencedAssemblies.git]
│
└─source_cc
    [ClearCanvas.git]
    ReferencedAssemblies (Symbolic Link) <<===>> ..\ReferencedAssemblies

Symbolic link 用下面的指令建立

path\to\source_cc>mklink /D ReferencedAssemblies ..\ReferencedAssemblies

之後再根據 [AIMPlugin Readme][AIMv4.5Readme] 裡面寫的做:

  1. Add AIM plugins and their WinForms projects to your ImageViewer solution file.
  2. Make Desktop.Executable project dependent on the newly added plugins.
  3. Either change post-build routines to copy new plugin executables to the “plugins” folder or copy the plugin executables there manually when the build completes.
  4. Build Desktop.Executable. During an initial build, there may be errors related to visibility of some of the ClearCanvas classes. Make the classes in question public and build again.

這邊其實有點誤導人,因為他是說把 dlls 複製到 plugins 資料夾內就好,然而,如果有 dll 跟 ClearCanvas.Desktop.Executable.exe 在同一個目錄下,就會出錯。

原本以為是 Compact SQL Server 的 Native DLLs 問題,方向搞錯,試了很久都沒成功。當初的 Error message 如下:

Full error message ``` Failed to create database connection for 'dicom_store.sdf'; waiting 50ms before trying again. System.Data.SqlServerCe.SqlCeException (0x80004005): Unable to load the native components of SQL Server Compact corresponding to the ADO.NET provider of version 8482. Install the correct version of SQL Server Compact. Refer to KB article 974247 for more details. at System.Data.SqlServerCe.NativeMethods.LoadNativeBinaries() at System.Data.SqlServerCe.SqlCeConnection..ctor() at System.Data.SqlServerCe.SqlCeConnection..ctor(String connectionString) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnectionInternal(String fileName) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnection(String fileName, Int32 timeoutMilliseconds) 2018-04-05 22:31:18,267 [1] WARN - Exception thrown Failed to create database connection for 'configuration.sdf'; waiting 50ms before trying again. System.Data.SqlServerCe.SqlCeException (0x80004005): Unable to load the native components of SQL Server Compact corresponding to the ADO.NET provider of version 8482. Install the correct version of SQL Server Compact. Refer to KB article 974247 for more details. at System.Data.SqlServerCe.NativeMethods.LoadNativeBinaries() at System.Data.SqlServerCe.SqlCeConnection..ctor() at System.Data.SqlServerCe.SqlCeConnection..ctor(String connectionString) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnectionInternal(String fileName) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnection(String fileName, Int32 timeoutMilliseconds) 2018-04-05 22:31:23,322 [1] WARN - Exception thrown System.Data.SqlServerCe.SqlCeException (0x80004005): Unable to load the native components of SQL Server Compact corresponding to the ADO.NET provider of version 8482. Install the correct version of SQL Server Compact. Refer to KB article 974247 for more details. at System.Data.SqlServerCe.NativeMethods.LoadNativeBinaries() at System.Data.SqlServerCe.SqlCeConnection..ctor() at System.Data.SqlServerCe.SqlCeConnection..ctor(String connectionString) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnectionInternal(String fileName) at ClearCanvas.ImageViewer.StudyManagement.Core.Storage.SqlCeDatabaseHelper`1.CreateConnection(String fileName, Int32 timeoutMilliseconds) at ClearCanvas.ImageViewer.StudyManagement.Core.Configuration.DataAccessContext..ctor(String databaseFilename) at ClearCanvas.ImageViewer.StudyManagement.Core.Configuration.SystemConfigurationSettingsStore.GetSettingsValues(SettingsGroupDescriptor group, String user, String instanceKey) at ClearCanvas.ImageViewer.Common.Configuration.SystemConfigurationSettingsProvider.GetPropertyValues(SettingsContext context, SettingsPropertyCollection properties, Boolean returnPrevious) at ClearCanvas.ImageViewer.Common.Configuration.SystemConfigurationSettingsProvider.GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) at System.Configuration.SettingsBase.GetPropertiesFromProvider(SettingsProvider provider) at System.Configuration.SettingsBase.GetPropertyValueByName(String propertyName) at System.Configuration.SettingsBase.get_Item(String propertyName) at System.Configuration.ApplicationSettingsBase.GetPropertyValue(String propertyName) at System.Configuration.ApplicationSettingsBase.get_Item(String propertyName) at ClearCanvas.ImageViewer.Common.StudyManagement.StorageSettings.get_FileStoreDirectory() at ClearCanvas.ImageViewer.Common.StudyManagement.StorageConfigurationProxy.GetConfiguration(GetStorageConfigurationRequest request) at ClearCanvas.ImageViewer.Common.StudyManagement.StudyStore.<>c__DisplayClass16_0.b__0(IStorageConfiguration s) at ClearCanvas.Common.Platform.GetService[TService](WithServiceDelegate`1 proc) at ClearCanvas.ImageViewer.Common.StudyManagement.StudyStore.GetConfiguration(Boolean forceReload) at ClearCanvas.ImageViewer.StudyManagement.LocalServerWatcher.get_StorageConfiguration() at ClearCanvas.ImageViewer.StudyManagement.ActivityMonitorTool.CheckDiskspaceUsageExceeded() at ClearCanvas.ImageViewer.StudyManagement.ActivityMonitorTool.Initialize() at ClearCanvas.Desktop.Tools.ToolSet..ctor(IEnumerable tools, IToolContext context) ``` </details> 目前測試如果是如下兩種可能都可以跑。 ``` bin │ ClearCanvas.Desktop.Executable.exe │ [no dlls] │ ├─common │ [dlls] │ └─plugins [dlls] ``` ``` bin ClearCanvas.Desktop.Executable.exe [common dlls] [plugins dlls] ``` 所以最好就是把所有 references 的 `Copy Local` 設為 False. ## 和安裝版本做比較 目前似乎就可以成功執行了!但是在 [DicomViewer-13.2.19401.1661-x64][CCbin] 和 [AIM on ClearCanvas® Workstation][AIMbin] 的 plugin folder 裡面,有一些現在我們編譯出來沒有的 dll 檔,於是我便把他們一一試著加入 [PostBuild_dist.proj](source_cc\Desktop\Executable\PostBuild_dist.proj) 裡面。 - In ClearCanvas but not in compiled: ``` ClearCanvas.ImageViewer.Shreds.dll ``` - In AIM on ClearCanvas but not in compiled: ``` AIMLib.dll AIMLib.NET.dll AIMLibModel.NET.dll AimTmplUtil1923.dll AimTmplUtilV1Rv23V2Rv13.dll TCGA.dll TCGA.View.WinForms.dll xerces-c_3_1.dll ``` ## Release mode 現在在 Debug 模式似乎就可以跑得很順了。最後便用 Release 模式執行看看,因為 Release mode 會有優化等等,所以一些在 Debug mode 中不容易出現的問題就會發生。 結果果然出現問題了,仔細尋找才發現是 [AimDataService.View.WinForms.csproj ]() 的 Release Target Platform 被改成 `x86` 了,改回來就沒事了! ```xml AnyCPU ``` 這真的是非常難找,但是幸虧有 Error message 的幫忙,才能 target 到那個 dll 檔。我採取的方法是先把 dll 檔直接用 debug mode compile 的替換,便發現可以正常執行。之後再試著 disable Release mode 的 optimization, 發現沒有用,之後便意外地看到異常的 x86 target platform.
Full error message ``` System.NotSupportedException: No extensions found for extension point AimDataService.AimDataServiceSearchCriteriaComponentViewExtensionPoint, or the extensions could not be instantiated. Please see the log for more information. at ClearCanvas.Common.ExtensionPoint.AtLeastOne(Object[] objs, Type extensionPointType) at ClearCanvas.Desktop.ViewFactory.CreateView(IExtensionPoint extensionPoint, String toolkitId) at ClearCanvas.Desktop.ApplicationComponentHost.get_ComponentView() at ClearCanvas.Desktop.View.WinForms.SplitComponentContainerControl..ctor(SplitComponentContainer component) at ClearCanvas.Desktop.View.WinForms.SplitComponentContainerView.get_GuiElement() at ClearCanvas.Desktop.View.WinForms.TabComponentContainerControl.ShowPage(TabPage page) at ClearCanvas.Common.Utilities.EventsHelper.Fire(EventHandler del, Object sender, EventArgs e) 2018-04-05 21:46:42,318 [10] FATAL - Exception thrown ```
## Git 整合 因為有 submodule 中的 symbolic link 所以不能用一般的 clone 來下載。必須使用一連串的指令。 Launch a elevated command prompt (with administrator rights) and type the following commands: ```shell git clone https://github.com/j3soon/annotation-and-image-markup.git aim-xnat-cc cd aim-xnat-cc git submodule update --init --recursive cd source_cc git config --local core.symlinks true git reset HEAD --hard cd .. ``` 如果 symbolic link 不是在 submodule 裡,就可以直接用下面的指令: ```shell git clone -c core.symlinks=true ``` ## 完成並送出 pull request 這邊就不特別紀錄了,不過他的 pull request 要求蠻多的,有點麻煩。 不過終於大功告成啦~ 整合好的原始碼放在[這裡][AIMXNATCC]。 [AIM]: https://github.com/NCIP/annotation-and-image-markup [CC]: https://github.com/ClearCanvas/ClearCanvas [CCRef]: https://github.com/ClearCanvas/ReferencedAssemblies [AIMv4.5]: https://github.com/NCIP/annotation-and-image-markup/tree/master/AimPlugin4.5 [AIMv4.5Readme]: https://github.com/NCIP/annotation-and-image-markup/blob/master/AimPlugin4.5/readme.txt [AIMproj]: https://github.com/NCIP/annotation-and-image-markup/blob/e3f3340aae3f59c3676cf0c1077c890ef47dda6d/AimPlugin4.5/XnatWebBrowser/XnatWebBrowser.csproj#L135 [CCReadme]: https://github.com/ClearCanvas/ClearCanvas/blob/master/README.md#how-to-build-using-github-for-windows [CCbin]: https://github.com/ClearCanvas/ClearCanvas/releases [AIMbin]: https://wiki.nci.nih.gov/display/AIM/Annotation+and+Image+Markup+-+AIM [AIMXNATCC]: https://github.com/j3soon/annotation-and-image-markup

Posted:

Comments