最近 team 遇到了這鬼問題,全都是源自於萬惡的 vc6.0 移到 vs2010 上面所帶來的效應。言歸正傳,長話短說。

專案裡有一份 exe 和數份 dll (上百份) ,dll 是購買機制,exe 部份功能是看 dll 有沒有開啟。早期 exe 和 dll 都是用 vc6.0 完成的。

exe 從 6.0 升級到 2010 ,dll 也從 6.0 升級到 2010 ,這四種搭配必須無誤,問題點在於有一個功能竟然是直接傳 pointer to class,而這個 class 還是繼承自 MFC 來的,可以想做是 class CMyButton。這個 class 不論 dll 還是 exe 專案,都有同樣的 source code 塞進去。問題點出在,class MyButton 在 vc6.0 和 vs2010 下編譯,大小並不相同 ( 廢話,光是繼承 CButton,再繼承 CWnd ,再繼承 CCmdTarget,這個只要 MFC 中間有改過一個就不一樣了 ) ,接下來的麻煩就不用我講了吧。

問題應源自於,部份 dll 要畫 UI 時,是 exe 和 dll 各負責一半 ( = = 沒錯,是各負責一半,所以在各自專案裡, CMyButton 兩邊都有一份相同的 source code) 。說實在的目前我沒想到好的解決方法。

 

(1) 可以的話是想在 CMyButton 裡做 padding size,簡單的說就是再手刻一份 CMyButton 能同時相容 6.0 和 2010 ,一方面不確定這辦得到,一方面後續要改很麻煩。

(2) CMyButton 直接包出一個靜態 dll 出來供中介呼叫。但這個感覺也很麻煩,到時還要動到 exe 和 dll 原始碼。還好目前 dll 自己有在 exe 畫 UI 的,只有一個 class ,其他都是由 exe 畫。

(3) 最後這部大概是一勞永逸的方式了,直接把 UI 部份切回給 exe,換句話說 dll 也要再改過,但想想後續可能還會再爆未爆彈的機率相對就少很多。

 

判斷大概是 (2) , (3) 兩個其中挑一個吧,不過既然原本專案沒有為 UI 特別再開個 dll 出來做中介呼叫使用,延續以前機制大概是走 (3),把 UI 部份從 dll 切乾淨了。在想要達成目標、較短路徑情況下,不知道有沒有其他方案可行就是了。

路過的網友若有其他的想法,麻煩提供些意見吧...

edisonx 發表在 痞客邦 PIXNET 留言(2) 人氣()


留言列表 (2)

發表留言
  • novus
  • 不同編譯器編譯同一個 C++ class 本來就不會相容,而且介面有 class 的 dll 本來就不應該跨編譯器使用。

    最簡單的方法大概是重新劃分模組。如果考慮到重用的問題,應該包裝成 COM 物件或提供純 C 介面。

    Windows API 有一些元件其實內部是用 C++ 寫的(例如近幾版的 RichEdit),第三方元件如 Scintilla 也是以 C++ 實作,但是介面一定是純 C,這是為了二進碼相容性必然的結果。

  • >> 最簡單的方法大概是重新劃分模組。如果考慮到重用的問題,應該包裝成 COM 物件或提供純 C 介面。

    這就是麻煩的地方了,不論是不是考慮重用問題,只要一重劃模組,exe 和上百份 dll 都要改過 source code ,再想到改完之後要交予他人做測試、正式發行…工程浩大啊!但目前我能想到的,也只有這方式最穩健 (考慮重用應就是原文所提出的第二個方案,懶人做法不包成 com/dll 就變第三個方案)。

    不過第一次看到原本的做法,有些蠻傻眼就是了...

    >> 不同編譯器編譯同一個 C++ class 本來就不會相容,而且介面有 class 的 dll 本來就不應該跨編譯器使用。

    這點我想再確認一下,若這支 C++ class 是自己純手動刻的,裡面所有的 functions 只用到 C library functions ,沒再繼承其他 class,未來包進 dll 跨編譯器是否也不會相容? 目前我想到的問題只有 padding 上的問題。

    edisonx 於 2014/02/20 13:34 回覆

  • novus
  • 理論上: 編譯器有可能對一個 class 做任意修飾、偷偷安插隱藏成員(如 vptr),因此 memory layout 會隨編譯器而異。只有 POD class 的 layout 比較有規則可循

    即使是 POD,普通成員函數的 calling convention 會隨編譯器而改變,virtual 的查詢法也可能不同。

    編譯器的 exception 系統不同,因此當 exception 跨越 dll 邊界的時候很可能會出現大問題。

    理論上 C++ 對以上連一絲一毫的保證都沒有,因此介面含有 class 的 dll 都不應該跨編譯器使用。

    -----

    實際上: 編譯器會用的招數是有限的,如果只有非常具體的 2 編譯器 + 1 class,想蠻幹賭運氣也不是全無可能。

    如果將來可能繼續遇到類似問題,還想比照辦理,我只能說: This is not sparta, this is madness.
  • 要考慮的事真的還頗多,真的硬砍下去也是沒完沒了..
    謝謝回覆。

    edisonx 於 2014/02/21 22:29 回覆

您尚未登入,將以訪客身份留言。亦可以上方服務帳號登入留言

請輸入暱稱 ( 最多顯示 6 個中文字元 )

請輸入標題 ( 最多顯示 9 個中文字元 )

請輸入內容 ( 最多 140 個中文字元 )

請輸入左方認證碼:

看不懂,換張圖

請輸入驗證碼