ATL 編寫控制元件 呼叫密碼鍵盤 全過程
阿新 • • 發佈:2019-01-06
寫在前面:小哆把詳細過程貼出來,一方面是記錄備份,可以隨時再利用,另一方面是分享,希望後來的初學者可以輕鬆一些。
"檔案"
[選項]
(填寫名稱)
=============================
(1)建立專案
檔案 -> 新建 -> ATL專案 -> 填寫專案名稱"ActiveXTest" -> [應用程式型別]選擇[動態連結庫(DLL)] -> 完成
完成後,會在右邊[解決方案資源管理器]生成很多"標頭檔案.h"和"實現檔案.CPP",這些都是預設的不要修改。
(3)給"test_op"新增一個方法,以便WEB頁面呼叫。
[類檢視]選擇"itest_op"(灰色鑰匙圖示)滑鼠右鍵新增 -> [新增方法] -> 方法起名為"testFunc"
引數型別選擇LONG 引數名iFlag 引數屬性選擇IN
-> 新增
引數型別選擇BSTR* 引數名passw 引數屬性選擇RETVAL -> 點選完成。
屬性in指輸入引數,屬性out指輸出引數。
這樣在專案中就產生了如下變化:
在test_op.h標頭檔案中添加了一個(在最後一行):
STDMETHOD(testFunc)(LONG iFlag, BSTR* passWord);
並在test_op.cpp檔案中添加了一個實現類:
STDMETHODIMP Ctest_op::testFunc(LONG iFlag, BSTR* passWord)
{
// TODO: 在此新增實現程式碼
return S_OK;
}
(4)在test_op.h 檔案中,呼叫DLL類庫。整體程式碼如下(認為新增的以標註):
(6)回到在test_op.cpp 檔案中,新增實現程式碼如下:
(7)生成DLL:
選[生成],在專案的Debug資料夾裡找到dll檔案"ActiveXTest.dll"
把LOADDLL.dll按照"test_op.h"裡的描述放置,相對路徑時可以放入Debug資料夾
利用iexpress.exe軟體
1.準備好所有你用到的、呼叫的dll,外加1個寫好的inf檔案。[好吧,如果你不會,那小哆後面會一步步教你]
2.解壓後,雙擊iexpress.exe。
[create new self extraction directive file] -> 下一步
[create compressed files only(activex installs)] -> 下一步
[add] ->選中準備好的檔案 -> 下一步
[browse] - 選擇好路徑/命名/儲存 ->[store files long file name inside package] -> 下一步
[don't save] -> 下一步 -> 下一步 -> 完成
3.cab包就此生成。
PS:小哆根據專案經驗,總結出來的。所以肯定是可行的。
附註:setup.inf檔案:
【說明】
①[Add.Code]中dll順序:
{舉例說明}最終生成和呼叫的ActiveXTest.dll,其內部呼叫了LOADDLL.dll。
內部順序是:
ActiveXTest.dll
LOADDLL.dll
②clsid={197E37FC-9916-4881-B766-D43FDD0376E8}
專案裡的idl檔案中,有一段這麼記錄:
library ActiveXTestLib
{
importlib("stdole2.tlb");
[
uuid(197E37FC-9916-4881-B766-D43FDD0376E8)
]
dispinterface _Itest_opEvents
{
properties:
methods:
};
那就選這個uuid吧,別問我為什麼,我也不知道
(8)htm檔案
【附註】
<OBJECT id=CaluNumCtrl codeBase="test2.CAB#version=1,0,0,1" classid="clsid:225EDF53-A85F-4CB5-977D-69509C7E675C"></OBJECT>
CLSID 是 ActiveX 專案生成的序號,具體可以在專案的test_op.rgs 檔案中找到。
ForceRemove {3968A893-A79C-4AB9-B2FD-73BA2B76FB23} = s 'test_op Class'
[這是一個整體,所以,今後就不在贅述其中的東西,除非是前期本人自己理解錯誤,會更正,同時特別備註]
沒有加入加密功能,MD5/DES加密都已實現,但在資源和其他的文章中有描述,本文加入過於贅述。
沒有數字簽名和釋出部分,還未完全明白。
呼叫:LOADDLL.dll
"檔案"
[選項]
(填寫名稱)
=============================
(1)建立專案
檔案 -> 新建 -> ATL專案 -> 填寫專案名稱"ActiveXTest" -> [應用程式型別]選擇[動態連結庫(DLL)] -> 完成
完成後,會在右邊[解決方案資源管理器]生成很多"標頭檔案.h"和"實現檔案.CPP",這些都是預設的不要修改。
右鍵點選專案名稱"ActiveXTest"選擇 -> 新增[類] -> 選擇[ATL簡單物件] -> 新增 -> 簡稱(test_op) -> 下一步:其他不變,在[支援]中選擇[連線點]和[IE物件支援]和[IEI] -> 完成 -> 選擇[覆蓋]
(3)給"test_op"新增一個方法,以便WEB頁面呼叫。
[類檢視]選擇"itest_op"(灰色鑰匙圖示)滑鼠右鍵新增 -> [新增方法] -> 方法起名為"testFunc"
引數型別選擇LONG 引數名iFlag
引數型別選擇BSTR* 引數名passw 引數屬性選擇RETVAL -> 點選完成。
屬性in指輸入引數,屬性out指輸出引數。
這樣在專案中就產生了如下變化:
在test_op.h標頭檔案中添加了一個(在最後一行):
STDMETHOD(testFunc)(LONG iFlag, BSTR* passWord);
並在test_op.cpp檔案中添加了一個實現類:
STDMETHODIMP Ctest_op::testFunc(LONG iFlag, BSTR* passWord)
{
return S_OK;
}
(4)在test_op.h 檔案中,呼叫DLL類庫。整體程式碼如下(認為新增的以標註):
// test_op.h : Ctest_op 的宣告
#pragma once
#include "resource.h" // 主符號
#include "ActiveXTest_i.h"
#include "_Itest_opEvents_CP.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Windows CE 平臺(如不提供完全 DCOM 支援的 Windows Mobile 平臺)上無法正確支援單執行緒 COM 物件。定義 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可強制 ATL 支援建立單執行緒 COM 物件實現並允許使用其單執行緒 COM 物件實現。rgs 檔案中的執行緒模型已被設定為“Free”,原因是該模型是非 DCOM Windows CE 平臺支援的唯一執行緒模型。"
#endif
using namespace ATL;
// Ctest_op
class ATL_NO_VTABLE Ctest_op :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<Ctest_op, &CLSID_test_op>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<Ctest_op>,
public CProxy_Itest_opEvents<Ctest_op>,
public IObjectWithSiteImpl<Ctest_op>,
public IDispatchImpl<Itest_op, &IID_Itest_op, &LIBID_ActiveXTestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
//*******begin*****以下三行實現定義 add by 莫小哆_ly
typedef int (_stdcall *testGetPwd)(int,char*,char*); //型別定義,對應LOADDLL.dll->LoadFunc方法
HINSTANCE hInstLibrary;
testGetPwd _testGetPwd; //類對映
//*******end*****
Ctest_op()
{
//*******begin*****開始呼叫DLL add by 莫小哆_ly
hInstLibrary = LoadLibrary(L"C:\\WINDOWS\\system32\\LOADDLL.dll");//相對路徑時把寫好的LOADDLL.dll檔案放在此專案生成的目錄debug下。
if (hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);//資源釋放
}else{
}
//呼叫方法,返回方法控制代碼。
_testGetPwd = (testGetPwd)GetProcAddress(hInstLibrary, "LoadFunc");
//*******end*****
}
DECLARE_REGISTRY_RESOURCEID(IDR_test_op)
BEGIN_COM_MAP(Ctest_op)
COM_INTERFACE_ENTRY(Itest_op)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(Ctest_op)
CONNECTION_POINT_ENTRY(__uuidof(_Itest_opEvents))
END_CONNECTION_POINT_MAP()
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHOD(testFunc)(LONG iFlag, BSTR* passWord);
};
OBJECT_ENTRY_AUTO(__uuidof(test_op), Ctest_op)
(6)回到在test_op.cpp 檔案中,新增實現程式碼如下:
// test_op.cpp : Ctest_op 的實現
#include "stdafx.h"
#include "test_op.h"
//*****begin*****add by 莫小哆_ly
//#include "md5.h"//用於MD5加密,與本文無關,略去
#pragma comment(lib, "comsuppw.lib")
#include <comutil.h>
//*****end*****
// Ctest_op
STDMETHODIMP Ctest_op::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* const arr[] =
{
&IID_Itest_op
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP Ctest_op::testFunc(LONG iFlag, BSTR* passWord)
{
// TODO: 在此新增實現程式碼
//*****begin*****add by 莫小哆_ly
int iflag = (int)(iFlag);
char* pwd = new char[7];//參考testFunc的約定長度。
char* mac = new char[33];
char *pwd_md5 = new char[32];
_testGetPwd(iflag,pwd,mac);//這裡要求廠家提供的dll裡(int,char*,char*)
//結尾加結束符,防止陣列溢位出現亂碼[燙]
pwd[6]='\0';//密碼6位.0.1.2.3.4.5/pwd[6]->結束符
//MD5加密
//pwd_md5 = MD5String(pwd);
//char*型轉換成BSTR*型別
*passWord = _com_util::ConvertStringToBSTR(pwd);
//*****end*****
this->_AtlFinalRelease();
return S_OK;
}
(7)生成DLL:
選[生成],在專案的Debug資料夾裡找到dll檔案"ActiveXTest.dll"
把LOADDLL.dll按照"test_op.h"裡的描述放置,相對路徑時可以放入Debug資料夾
利用iexpress.exe軟體
1.準備好所有你用到的、呼叫的dll,外加1個寫好的inf檔案。[好吧,如果你不會,那小哆後面會一步步教你]
2.解壓後,雙擊iexpress.exe。
[create new self extraction directive file] -> 下一步
[create compressed files only(activex installs)] -> 下一步
[add] ->選中準備好的檔案 -> 下一步
[browse] - 選擇好路徑/命名/儲存 ->[store files long file name inside package] -> 下一步
[don't save] -> 下一步 -> 下一步 -> 完成
3.cab包就此生成。
PS:小哆根據專案經驗,總結出來的。所以肯定是可行的。
附註:setup.inf檔案:
[version]
signature="$CHICAGO{1}quot;
AdvancedINF=2.0
[Add.Code]
ActiveXTest.dll=ActiveXTest.dll
LOADDLL.dll=LOADDLL.dll
[install.files]
ActiveXTest.dll=ActiveXTest.dll
LOADDLL.dll=LOADDLL.dll
[ActiveXTest.dll]
file-win32-x86=thiscab
RegisterServer=yes
clsid={197E37FC-9916-4881-B766-D43FDD0376E8}
DestDir=11
FileVersion=1,0,0,1
[LOADDLL.dll]
file-win32-x86=thiscab
DestDir=11
FileVersion=1,0,0,1
[RegisterFiles]
%11%/ActiveXTest.dll
【說明】
①[Add.Code]中dll順序:
{舉例說明}最終生成和呼叫的ActiveXTest.dll,其內部呼叫了LOADDLL.dll。
內部順序是:
ActiveXTest.dll
LOADDLL.dll
②clsid={197E37FC-9916-4881-B766-D43FDD0376E8}
專案裡的idl檔案中,有一段這麼記錄:
library ActiveXTestLib
{
importlib("stdole2.tlb");
[
uuid(197E37FC-9916-4881-B766-D43FDD0376E8)
]
dispinterface _Itest_opEvents
{
properties:
methods:
};
那就選這個uuid吧,別問我為什麼,我也不知道
這個到底是什麼情況,我也沒搞清楚,反正選了個這個可以正常執行。
(8)htm檔案
<HTML>
<HEAD>
<TITLE>New Page</TITLE>
<OBJECT id=CaluNumCtrl codeBase="ActiveXTest.CAB#version=1,0,0,1" classid="clsid:3968A893-A79C-4AB9-B2FD-73BA2B76FB23"></OBJECT>
<script language="javascript">
function doTest()
{
var pwd = CaluNumCtrl.testFunc(1);
alert(pwd);
}
</script>
</HEAD>
<BODY>
<input type="button" value="呼叫" id="btnOK" onclick="doTest();"></input>
</BODY>
</HTML>
【附註】
<OBJECT id=CaluNumCtrl codeBase="test2.CAB#version=1,0,0,1" classid="clsid:225EDF53-A85F-4CB5-977D-69509C7E675C"></OBJECT>
CLSID 是 ActiveX 專案生成的序號,具體可以在專案的test_op.rgs 檔案中找到。
ForceRemove {3968A893-A79C-4AB9-B2FD-73BA2B76FB23} = s 'test_op Class'