C++編寫網頁控件,遇到的問題總結


最近做一個溯源的系統,在裏面就涉及到了制卡的過程,而我們又不想做成C/S的形式,只想在B/S上搞定這個問題,這樣就不得不做成ActiveX的形式了!哪知在做這個的過程還真遇到一些問題,讓人糾結了很久,網上也找不到解決方案,最後還是自己慢慢搞定!好,下面就開始來說製作這個控件的過程吧!
      開發環境:Win7 + VS 2010
      首先當然是建立工程咯,這個不用多說了吧,哦,新建一個MFC ActiveX工程,如圖吧
image
確定,下一步到這裏
image
下一步,下一步完成,這樣就建立了一個ActiveX工程了!
下面開始做事吧,多的就不用了,我們就只用系統的AboxBox方法吧,畢竟主要不是說ActiveX的開發的!
 
但是我們還是要做一些事情的,那就是控件安全性的驗證東東!找到代碼文件ActiveXDemo.cpp
在開始處添加頭文件
#include <ObjSafe.h>
然後我們在const WORD _wVerMinor = 0;下面開始添加一部分代碼
/*這裏開始就是爲控件安全添加的東西哦*/
// 控件的CLSID,註冊表用(一定要是實際使用的控件的)可以在ActiveXDemo.idl最下面找到
//  CActiveXDemoCtrl 的類信息
    [
        uuid(FDC2D72B-3B02-4AFD-B48F-7B99BF90C220), licensed
    ]
將uuid裏面的值加入到CLSID_SafeItem 裏面去就行了
const GUID CDECL CLSID_SafeItem = { 0xFDC2D72B, 0x3B02, 0x4AFD,{ 0xB4, 0x8F, 0x7B, 0x99, 0xBF, 0x90, 0xC2, 0x20 }};
/// 創建組件種類
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{  
    ICatRegister* pcr = NULL ;
    HRESULT hr = S_OK ; 
    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
    if (FAILED(hr))    
        return hr;  
        // Make sure the HKCR\Component Categories\{..catid}  
        // key is registered. 
    CATEGORYINFO catinfo; 
    catinfo.catid = catid; 
    catinfo.lcid = 0x0409 ; // english 
            // Make sure the provided description is not too long.  
            // Only copy the first 127 characters if it is. 
    int len = wcslen(catDescription);  
    if (len>127)    
        len = 127; 
    wcsncpy(catinfo.szDescription, catDescription, len); 
//     Make sure the description is null terminated. 
    catinfo.szDescription[len] = '\0';
    hr = pcr->RegisterCategories(1, &catinfo); 
    pcr->Release();
    return hr;
}
// 註冊組件種類
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{  
    // Register your component categories information.
    ICatRegister* pcr = NULL ;  
    HRESULT hr = S_OK ;  
    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
    if (SUCCEEDED(hr))  
    {        // Register this category as being implemented by the class.   
        CATID rgcatid[1] ;    
        rgcatid[0] = catid;  
        hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);  
    }  
    if (pcr != NULL)   
        pcr->Release();
    return hr;
}
// 卸載組件種類
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)

    ICatRegister* pcr = NULL ; 
    HRESULT hr = S_OK ; 
    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
    if (SUCCEEDED(hr)) 
    {    
        // Unregister this category as being implemented by the class.   
        CATID rgcatid[1] ;    
        rgcatid[0] = catid;  
        hr = pcr->;UnRegisterClassImplCategories(clsid, 1, rgcatid);
    }   
    if (pcr != NULL)
        pcr->Release();  
    return hr;
}
然後這在下面找到
// DllRegisterServer - 將項添加到系統註冊表
STDAPI DllRegisterServer(void)
修改代碼爲
STDAPI DllRegisterServer(void)
{
    HRESULT hr;
    AFX_MANAGE_STATE(_afxModuleAddrThis);
    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
        return ResultFromScode(SELFREG_E_TYPELIB);
    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
        return ResultFromScode(SELFREG_E_CLASS);
    ///////////////////////////////////
    // 標記控件初始化安全.
    // 創建初始化安全組件種類
    hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
    if (FAILED(hr))     
        return hr;   
    // 註冊初始化安全  
    hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
    if (FAILED(hr))    
        return hr; 
    // 標記控件腳本安全 
    // 創建腳本安全組件種類  
    hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
    if (FAILED(hr))      
        return hr;   
    // 註冊腳本安全組件種類 
    hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
    if (FAILED(hr))       
        return hr;
    return NOERROR;
}
 
如果說你不想添加這些東西的話,那麼運行這個控件的時候,他都會提示是否運行!麻煩哇
OK生成工程.我們將控件放在網頁裏試試
<html>
<head>
<title>ActiveX</title>
<OBJECT classid="clsid:FDC2D72B-3B02-4AFD-B48F-7B99BF90C220" id="ActiveXDemo" > </OBJECT>
<script type="text/javascript">
function Open()
{ ActiveXDemo.AboutBox(); }
</script>
</head>
<body bgcolor="#ffffff" >
<form name=stuff>
<input type=button name=test value="Load"/>
</form>
</body>
</html>
這樣就可以看有沒有註冊成功,點擊這個按鈕,如果彈出
image
那麼就代表註冊成功了,要麼就沒有成功!
如果沒有添加上面的那些安全代碼的話,會彈出另外一個窗口
image
這樣的話很妨礙使用!所以還是加上這部分處理的代碼的好!
OK這樣就算了將一個ActiveX控件寫完了,下面的工作就是在裸機上面註冊的事情了!
其實這個裸機也不算是什麼裸機,只是沒有註冊VC裏面的一些文件的.那樣的話是不能使用這個控件的!
先將生成的控件ActiveXDemo.ocx複製到測試機的D:\test目錄下面,在命令提示行下面進行註冊,註冊語句爲regsvr32 (/u 加上這個爲卸載控件)ActiveXDemo.ocx
image
出現錯誤提示,找不到模塊,我們用VC6.0的工具Depends來查看少哪些模塊
image
看到如上的提示,有黃色問號提示的就是沒有的文件,這樣就好辦了,到開發的機子上面去把這些文件找到,然後複製到test目錄下面去再註冊!
找到所有的模塊,過後再次運行depends看看
image
這樣模塊就都找到了.運行命令進行註冊看一下效果!
image
這樣就算是註冊成功了,運行看看效果吧!點擊Load卻是出現下面的腳本錯誤
image
看錯誤提示
image
不支持的對象方法,奇怪了,這樣就說明註冊是註冊成功了,但是卻沒有初始化成功,是不是與我們剛纔看到的mpr.dll那個呈紅色有關呢,那我們到depends裏去看看是什麼原因
image
有一個方法是紅色的,那麼到底是不是這個原因呢!
經過在網上查找資料後,但是網上也沒有好的解決方案,最後在http://www.dependencywalker.com/faq.html這上面看到一條信息
Q.gif
Why am I seeing a lot of applications where MPR.DLL shows up in red under SHLWAPI.DLL because it is missing a function named WNetRestoreConnectionA? I also get a "Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module" message.
A.gif
Some versions of SHLWAPI.DLL (like the one on Windows XP) have a delay-load dependency on the function WNetRestoreConnectionA in MPR.DLL. Missing delay-load functions are not a problem as long as the calling DLL is prepared to handle the situation. Dependency Walker flags all potential problems as it cannot detect if an application intends to handle the issue. In the case of SHLWAPI.DLL, this is not an problem as it does not require WNetRestoreConnectionA to exist and handles the missing function at runtime. This warning can be ignored. See the "How to Interpret Warnings and Errors in Dependency Walker" section in help for more details.
大概意思就是說這個警告是可以忽略的,那麼問題到底是在哪裏呢!後來我偶然發現我將生成的文件,文件夾裏的文件全部都放進去過後,註冊就可以使用了,那就是說,在生成後,除了ocx文件以外應該還有另外的文件是必須的,經過反覆的測試,才發現只有ActiveXDemo.lic這個文件有效.
這時纔想起在ActiveXDemoCtrl.cpp文件代碼中有這麼一段代碼
// 授權字符串
static const TCHAR _szLicFileName[] = _T("ActiveXDemo.lic");
static const WCHAR _szLicString[] = L"Copyright (c) 2010 ";
// CActiveXDemoCtrl::CActiveXDemoCtrlFactory::VerifyUserLicense -
// 檢查是否存在用戶許可證
BOOL CActiveXDemoCtrl::CActiveXDemoCtrlFactory::VerifyUserLicense()
{
    return AfxVerifyLicFile(AfxGetInstanceHandle(), _szLicFileName,
        _szLicString);
}
// CActiveXDemoCtrl::CActiveXDemoCtrlFactory::GetLicenseKey -
// 返回運行時授權密鑰
BOOL CActiveXDemoCtrl::CActiveXDemoCtrlFactory::GetLicenseKey(DWORD dwReserved,
    BSTR *pbstrKey)
{
    if (pbstrKey == NULL)
        return FALSE;
    *pbstrKey = SysAllocString(_szLicString);
    return (*pbstrKey != NULL);
}
原來是沒有運行許可證,才造成這樣的錯誤,將lic文件複製到test目錄下再次註冊控件可以使用了
image
真的是一路走來都是淚啊!到此所有問題解決,終於可以使用了!
當然使用網頁控件的時候會有證書的問題,那個問題大家自己去找解決方案吧,畢竟證書這種東西不好找啊!
OK,本文到此,如有不足之處,請大家請出意見,本人新手!希望高手們不要鄙視哈!

本文出自 “Laputaliya” 博客,請務必保留此出處http://laputaliya.blog.51cto.com/751941/426914

發佈了5 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章