方法:
64位windows支持64位和32位進程(包括本機或跨機)間進程間通信(RPC)。在64位windows中,一個進程外32位COM服務器能夠與64位客戶端進行通信,同樣一個進程外64位COM服務器也能與32位客戶端進行通信。因此,如果你有一個32位COM無法識別的DLL,你可以將它封裝到一個進程外COM服務器中並在一個64位進程中用COM配置調用DLL。
原文鏈接:https://blog.csdn.net/nie2314550441/java/article/details/49867735
使用工具:
VS2017
步驟:
1.Devin已經驗證64位exe能調用32位dll,從他手中拿來Demo分析。
一共三個項目:
ATLProject12->COM exe 32位 (64位程序通過COM exe 調用32位dll)
ConsoleApplication-> 64位程序
MFCLibrary3->32位dll
問題:項目copy后vs打開,把依賴項路徑什么的改了,發現代碼中的類或函數都不能直接F12。
原因:.vs這個文件夾沒有刪除,導致VS打開項目時,是根據之前同事電腦上的配置進行的加載。
.vs文件夾:用來存儲當前用戶在解決方案中的工作配置,具體包括VS關閉前最后的窗口布局、最后打開的選項卡/操作記錄/文件文檔、某些自定義配置/開發環境、調試斷點等這類設置信息和狀態
參考鏈接:https://shiyousan.com/post/636441130259624698
2.
MFCLibrary:32位dll,會導出一個接口供ATLProject項目調用。
ATLProject12:
ATL(類型庫):類型庫是idl文件、COM類文件,.h文件,.cpp文件,.def文件的綜合體。類型庫里面包含了我們所要用的COM組件(COM類)。我們經常使用的word、excel的COM組件,都是通過他們的類型庫導入客戶程序的,然后我們才能通過CoCreateInstance()來構建組件對象。類型庫就是COM類的容器,里面包含了若干COM類,是一個獨立的能被客戶程序導入的dll文件,是對COM組件的打包。
ATL作用:
ATL專門用來生成COM組件的,編譯后生成dll文件或者exe文件。
com組件和普通的dll文件有什么區別呢?
com組件優點:1.語言無關性;2.便於升級擴展;3.有很好的繼承封裝多態特性,即面向對象能力強;4.完成進程間,分布式功能;5.接口調用,便於組織。
VS創建一個ATL項目(必須要用管理員權限打開,不然最后編譯時會報錯 error MSB8011: 未能注冊輸出。PS:報這個錯也有可能是依賴項沒有全部配好)
選擇服務(.exe) 。
生成項目后新建項
ATL簡單對象
ProgID:
是在定義COM類時為類起的別名,方便程序員記住。命名規則為:ProjectName.ClassName.VersionNumber,即:工程名(類型庫名稱).類名(COM類名稱).(版本號)
在這里填一個自己能記住的先。
生成ATLSimpleObject.cpp和ATLSimpleObject.h
在.h和.cpp中添加需要導出的接口及實現
源文件中有一個idl文件
在interface里面添加前面寫好的需要導出的接口,[in]:表示傳入參數,[out]:表示傳出參數。基礎變量不用改變,string字符串需要用BSTR轉。或使用VARIANT變量傳遞參數
生成,產生一個ATLProject_i.c 和 ATLProject_i.h(.h中有導出的函數的聲明)。把這兩個文件添加到64位項目下,就能直接調用接口。
驗證過程中參數傳遞的問題:
需要傳圖片進32位dll進行處理,並返回處理后的圖片,使用OpenCV3.0
返回Mat。
使用COM組件提供的VARIANT和SAFEARRY(安全數組)進行Mat數據的傳遞。
VARIANT* matBackData;
SAFEARRAY *pArray1 = nullptr;
HRESULT hr = SafeArrayAllocDescriptor(1, &pArray1);//創建SAFEARRAY結構對象,在棧上
pArray1->cbElements = sizeof(unsigned char); //每個元素占用的字節數
pArray1->rgsabound[0].cElements = 5120 * 5120; //第0維數組元素個數
pArray1->rgsabound[0].lLbound = 0; //第0維數組起始下標
hr = SafeArrayAllocData(pArray1);//在堆上申請內存存放SAFEARRAY
上面這段代碼創建了一個5120 * 5120大小的安全數組
memcpy(pArray1->pvData, umatBackData, 5120 * 5120);
//pArray1->pvData = umatBackData; //不能直接=。
umatBackData為需要放入安全數組的數據。這里umatBackData = mMat.data。mMat是處理后的圖片
matBackData->vt = VT_ARRAY | VT_UI1;//VT_VARIANT //SAFEARRAY的類型必須為VT_ARRAY, VT_UI1: 指明數組數據為unsigned char
matBackData->parray = pArray1;
matBackData可以成功返回數據。在調用端使用完后,需要釋放安全數組
SafeArrayUnaccessData(matBackData.parray);
SafeArrayDestroy(matBackData.parray);
VariantClear(&matBackData);
總結:
使用COM進行64位32位間的接口相互調用,和普通的32調32,64調64方法基本一樣,主要問題在於復雜結構的參數傳遞,可以使用COM提供的VARIANT和SAFEARRY對參數進行打包,然后傳遞。