VC程序如何通過(guò)注冊(cè)表判斷一個(gè)特定的OCX控件是否已注冊(cè)
- 2017-09-10 10:25:00
- 網(wǎng)絡(luò)摘錄 轉(zhuǎn)貼
- 7734
把下面的 CLASSID 換成你的 OCX 控件的就可以了:
BOOL CYourApp::IsInstalled()
{
HKEY hKey;
BOOL bPresent;
TCHAR szPath[_MAX_PATH];
DWORD dwRegType;
DWORD cbData = sizeof szPath * sizeof TCHAR;
hKey = NULL;
bPresent = FALSE;
::RegOpenKey(HKEY_CLASSES_ROOT, _T("CLSID\\{D27CDB6E-AE6D-11cf-96B8-444553540000}\\InprocServer32"), &hKey);
if(hKey)
{
HANDLE hfile;
szPath[0] = 0;
::RegQueryValueEx(hKey, NULL, NULL, &dwRegType, (LPBYTE)szPath, &cbData);
::RegCloseKey(hKey);
hfile = ::CreateFile(szPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(INVALID_HANDLE_VALUE != hfile)
{
bPresent = TRUE;
::CloseHandle(hfile);
}
}
return bPresent;
}
先關(guān)閉掉所有子UI線程的窗口,這樣才能讓子UI線程正常結(jié)束掉。使用EnumChildWindows枚舉當(dāng)前程序中的對(duì)話框。
C/C++ code
BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam) { TCHAR szClassName[1024]; ::GetClassName(hwnd,szClassName,1024); DWORD dwProcessID; GetWindowThreadProcessId(hwnd,&dwProcessID); if(!_tcscmp(szClassName,_T("#32770")) //當(dāng)前窗體是對(duì)話框 && dwProcessID==GetCurrentProcessId() && hwnd!=(HWND)lParam)
//當(dāng)前窗體是當(dāng)前程序的,且不是主窗體 { PostMessage(hwnd,WM_CLOSE,0,0); } return TRUE; }
// 主窗體關(guān)閉時(shí)接受消毀消息
void CTSUServerDlg::OnDestroy()
{ EnumChildWindows(GetDesktopWindow()->GetSafeHwnd(),EnumChildProc,(LPARAM)GetSafeHwnd());
WaitForMultiplyObjects(5,hThreadList,TRUE, INFINITE); //等待所有子線程(包含UI線程)結(jié)束}
//當(dāng)用戶點(diǎn)擊要關(guān)閉主窗體時(shí)
void CTSUServerDlg::OnExit() { CDialog::OnCancel(); PostQuitMessage(0); }
用戶界面線程-(含有消息泵的線程)-主線程與用戶界面線程的通信. 收藏
vckbase站點(diǎn)上,由一個(gè)多線程的demo,講得是UI線程,如何開(kāi)啟一個(gè)UI界面線程.但是里面沒(méi)有涉及到主線程如何和UI線程間通信.
這個(gè)問(wèn)題,我搞了好久.
其實(shí)很簡(jiǎn)單,給一個(gè)線程發(fā)消息 PostThreadMessage().
BOOL PostThreadMessage(
DWORD idThread, // thread identifier {這個(gè)參數(shù)為線程ID,不是線程句柄}
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
eg:
int ret = PostThreadMessage( pThread->m_nThreadID, WM_SPLASH_NOTIFY,0, 0 );
if (ret == 0) // :檢查返回值,是否失敗.
{
//AfxMessageBox("post thread msg error!");
if ( ERROR_INVALID_THREAD_ID == GetLastError() )
{
AfxMessageBox("無(wú)效thread ID(你是否把線程句柄傳了進(jìn)去?:))! 或者線程里面沒(méi)有消息泵!!!");
}
}
WM_SPLASH_NOTIFY是自己定義的一個(gè)常量, 可以不用加入消息映射 呵呵. 直接在UI線程的PreTranslateMessage里面捕獲處理就好了.:), 當(dāng)然, 通過(guò)MFC的宏加入消息處理函數(shù)也可以, 不過(guò)原理是一樣的.
, 那么主線程如何知道UI界面線程的ID呢?
答案是: 通過(guò)AfxBeginThread()函數(shù)創(chuàng)建線程時(shí), 返回CWinThread* pThead指針.
AfxBeginThread()返回一個(gè)CWinThread*對(duì)象指針,
CWinThread* pThread = AfxBeginThread(...) ;
pThread->m_nThreadID就是創(chuàng)建線程的ID.
特別注意 , pThead->m_hThread是線程的句柄!!!! 不可以作為PostThreadMessage()的參數(shù),否則會(huì)提示: error C2664: 'PostThreadMessageA' : cannot convert parameter 1 from 'void *' to 'unsigned long' 編譯錯(cuò)誤.
具體參見(jiàn)如下帖子.
http://topic.csdn.net/t/20040509/14/3045752.html
那么我們發(fā)了消息后, 用戶界面線程如何處理消息呢?
重載PreTranslateMessage()函數(shù).
BOOL CUIThread::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if (pMsg->message == WM_SPLASH_NOTIFY )
{
AfxMessageBox("catch!");
}
return CWinThread::PreTranslateMessage(pMsg);
}
補(bǔ)充說(shuō)明兩點(diǎn)
1: 線程ID 不同于線程句柄, ID可用于給線程發(fā)消息.
2: 線程句柄 可用于控制線程的執(zhí)行,比如, 關(guān)閉線程, 暫停線程啥的.
也就是通常意義上的UI界面線程, 可以給該線程發(fā)消息. 呼呼.
3,4的說(shuō)法可能有問(wèn)題,已經(jīng)測(cè)試過(guò),對(duì)于工作線程, 已經(jīng)測(cè)試過(guò), 不可以在工作線程里面peekmessage.(peekmessage總是返回false, peek不到message ), .但是可以work thread成功發(fā)送消息, 但work thread里面 peekmessage老是失敗.不知道CWinThread做了什么手腳.呼呼.
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
參見(jiàn)msdn. PostThreadMessage的解釋.
MSG msg;
while(TRUE)
{
if(m_bThreadExit)
break;
if(::PeekMessage(&msg,NULL,NULL,NULL,PM_NOREMOVE))
{
if(::GetMessage(&msg,NULL,NULL,NULL))
{
if(!PreTranslateMessage(&msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
Sleep(55);
}
需要進(jìn)行dll與exe之間的資源切換,
void DllExport StartDlg()
{
HINSTANCE CurrentResource=AfxGetResourceHandle();
HINSTANCE NewInstance=LoadLibrary(_T( "a1.dll "));
AfxSetResourceHandle(NewInstance);
LineDlg dlg(NULL, UserApp);
dlg.DoModal();
AfxSetResourceHandle(CurrentResource);
FreeLibrary(NewInstance);
}
AFX_MANAGE_STATE(AfxGetStaticModuleState())
下面文章是codeproject上詳細(xì)講解用戶界面線程原理的文章.
http://www.codeproject.com/KB/threads/usinguithreads.aspx
DWORD dwWait = WAIT_FAILED;
HANDLE hThread = CreateThread(...);
do{
dwWait = MsgWaitForMultipleObjects(1, &hThread,
FALSE, 5000,
QS_ALLEVENTS);//wake up for all events, sent messages, posted messages etc.
switch(dwWait)
{
case WAIT_OBJECT_0:
{
//
// The event has become signalled
//
}
break;
case WAIT_OBJECT_0 + 1:
{
MSG msg;
while( PeekMessage(&msg, NULL, 0,0, PM_REMOVE ) )
{
if( msg.message != WM_QUIT)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
break;
}
}
}
break;
case WAIT_TIMEOUT:
{
TRACE(_T("WARNING: Possible Deadlock detected! ThreadID: %d File: %s Line: %d\n"), GetCurrentThreadId(), _T(__FILE__), __LINE__);
}
break;
}
}while( dwWait != WAIT_OBJECT_0 );
bend=TRUE;//改變變量,線程結(jié)束
WaitForSingleObject(pThread->m_hThread,INFINITE);//等待線程結(jié)束
delete pThread;//刪除線程
Cevent threadStart ,threadEnd;
UINT ThreadFunction(LPVOID pParam)
{
::WaitForSingleObject(threadStart.m_hObject,INFINITE);
AfxMessageBox("Thread start.");
while(!bend)
{
Beep(100,100);
Sleep(1000);
Int result=::WaitforSingleObject(threadEnd.m_hObject,0);
//等待threadEnd事件有信號(hào),無(wú)信號(hào)時(shí)線程在這里懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號(hào)
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動(dòng)線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}
線程內(nèi)部 AfxEndThread(2000);
if (m_pThread1 == NULL)
{
return;
}
DWORD dwExitCode = 0;
if (::GetExitCodeThread(m_pThread1->m_hThread, &dwExitCode))
{
if (dwExitCode == STILL_ACTIVE)
{
AfxMessageBox(_T("線程正在運(yùn)行\(zhòng)n"));
}
else
{
CString strText = _T("");
strText.Format("線程退出,退出碼:%d\n", dwExitCode);
AfxMessageBox(strText);
}
}
延時(shí)
DWORD dwStart = GetTickCount();
DWORD dwEnd = dwStart;
do
{
MSG msg;
GetMessage(&msg,NULL,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
dwEnd = GetTickCount();
} while((dwEnd - dwStart) <= 2000);
ATL寫的DLL為什么無(wú)法在其他機(jī)器上注冊(cè)——很急
項(xiàng)目屬性 - 配置屬性 - C++ - 代碼生成,運(yùn)行時(shí)庫(kù)選擇“多線程(/MT)”
單欄選擇"項(xiàng)目"->項(xiàng)目名稱+"屬性",在打開(kāi)的對(duì)話框右側(cè)選"配置屬性"->"常規(guī)",并在右側(cè)將"MFC 的使用"改為"在靜態(tài)庫(kù)中使用 MFC",
只要靜態(tài)鏈接MFC應(yīng)該就可以了吧。你用depends看看你的可執(zhí)行文件都鏈接了哪些DLL。
全局變量一般這樣定義:
1。在一類的.cpp中定義 int myInt;
然后再在要用到的地方的.cpp里extern int myInt;這樣就可以用了。
2。在stdafx.cpp中加入:
int myInt;
然后在stdafx.h中加入:
extern int myInt
這樣定義以后無(wú)論在什么文件中都是可見(jiàn)的.
3。比較規(guī)范的是,先定義一個(gè)Glbs.h,把所有的全局變量原始定義放進(jìn)去。然后定義一個(gè)Externs.h,把你先前定義在Glbs.h中的變量都加上extern。注意:如果你在Glbs.h中設(shè)置了初值,那么在Externs.h中就不要加值了。然后調(diào)用時(shí),第一次調(diào)用的#i nclude <Glbs.h>,以后調(diào)用的#i nclude <Externs.h>
另:
問(wèn):如何在VC++中使用全局變量,以使文檔中的所有類都能訪問(wèn)。
答:把該變量放到該應(yīng)用程序類的頭文件中的attribute處。然后,在程序的任何地方,你都可以用下面的方法來(lái)訪問(wèn)該變量:
CMyApp *app=(CMyApp*)AfxGet-App();
app->MyGlobalVariable=…
用這個(gè)方法,不但可以定義全局變量,也可以定義全局對(duì)象。
例如:
MyClass MyObject;
CMyApp*app=(CMyApp*)AfxGet-App();
app->MyObject.MyFunction();
VC中使用全局變量的2種辦法及防錯(cuò)措施
1. 對(duì)于全局變量存在和函數(shù)一樣的問(wèn)題,為了在其他CPP文件中能夠訪問(wèn)這些變量,必須在主文件的H文件中加上extern聲明,格式如下:
extern varibletype var; (聲明)
在主文件的CPP文件中定義
varibletype var; (定義)
在線程之間傳遞信號(hào)進(jìn)行通信比較復(fù)雜的方法是使用事件對(duì)象,用MFC的Cevent類的對(duì)象來(lái)表示。事件對(duì)象處于兩種狀態(tài)之一:有信號(hào)和無(wú)信號(hào),線程可以監(jiān)視處于有信號(hào)狀態(tài)的事件,以便在適當(dāng)?shù)臅r(shí)候執(zhí)行對(duì)事件的操作。上述例子代碼修改如下:
////////////////////////////////////////////////////////////////////
Cevent threadStart ,threadEnd;
UINT ThreadFunction(LPVOID pParam)
{
::WaitForSingleObject(threadStart.m_hObject,INFINITE);
AfxMessageBox("Thread start.");
while(!bend)
{
Beep(100,100);
Sleep(1000);
Int result=::WaitforSingleObject(threadEnd.m_hObject,0);
//等待threadEnd事件有信號(hào),無(wú)信號(hào)時(shí)線程在這里懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號(hào)
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動(dòng)線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}
在線程之間傳遞信號(hào)進(jìn)行通信比較復(fù)雜的方法是使用事件對(duì)象,用MFC的Cevent類的對(duì)象來(lái)表示。事件對(duì)象處于兩種狀態(tài)之一:有信號(hào)和無(wú)信號(hào),線程可以監(jiān)視處于有信號(hào)狀態(tài)的事件,以便在適當(dāng)?shù)臅r(shí)候執(zhí)行對(duì)事件的操作。上述例子代碼修改如下:
////////////////////////////////////////////////////////////////////
Cevent threadStart ,threadEnd;
UINT ThreadFunction(LPVOID pParam)
{
::WaitForSingleObject(threadStart.m_hObject,INFINITE);
AfxMessageBox("Thread start.");
while(!bend)
{
Beep(100,100);
Sleep(1000);
Int result=::WaitforSingleObject(threadEnd.m_hObject,0);
//等待threadEnd事件有信號(hào),無(wú)信號(hào)時(shí)線程在這里懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號(hào)
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動(dòng)線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}
- office課程播放地址及課程明細(xì)
- Excel Word PPT Access VBA等Office技巧學(xué)習(xí)平臺(tái)
- 將( .accdb) 文件格式數(shù)據(jù)庫(kù)轉(zhuǎn)換為早期版本(.mdb)的文件格式
- 將早期的數(shù)據(jù)庫(kù)文件格式(.mdb)轉(zhuǎn)換為 (.accdb) 文件格式
- KB5002984:配置 Jet Red Database Engine 數(shù)據(jù)庫(kù)引擎和訪問(wèn)連接引擎以阻止對(duì)遠(yuǎn)程數(shù)據(jù)庫(kù)的訪問(wèn)(remote table)
- Access 365 /Access 2019 數(shù)據(jù)庫(kù)中哪些函數(shù)功能和屬性被沙箱模式阻止(如未啟動(dòng)宏時(shí))
- Access Runtime(運(yùn)行時(shí))最全的下載(2007 2010 2013 2016 2019 Access 365)
- access vba代碼太長(zhǎng),換行,分行的寫法
- VB6 VBA Access真正可用并且完美支持中英文的 URLEncode 與 URLDecode 函數(shù)源碼
- 自定義VB中的urlencode函數(shù),將URL中特殊部分進(jìn)行編碼
- Access 函數(shù)簡(jiǎn)化串接sql字符串,減少符號(hào)導(dǎo)致的書寫錯(cuò)誤
- vba完全關(guān)閉IE瀏覽器及調(diào)用IE瀏覽器的簡(jiǎn)單應(yīng)用
- 利用FollowHyperlink方法打開(kāi)超鏈接提示“無(wú)法下載您要求的信息”的解決方案
- 在access中用代碼打開(kāi)文本框中超鏈接地址
- Activex控件或Dll 在某些電腦無(wú)法正常注冊(cè)的解決辦法(regsvr32注冊(cè)時(shí)卡住)
- office使用部分控件時(shí)提示“您沒(méi)有使用該ActiveX控件許可的問(wèn)題”的解決方法
- RTF文件(富文本格式)的一些解析
- Access樹(shù)控件(treeview) 64位Office下出現(xiàn)橫向滾動(dòng)條不會(huì)自動(dòng)定位的解決辦法
- Access中國(guó)樹(shù)控件 在win10電腦 節(jié)點(diǎn)行間距太小的解決辦法
- EXCEL 2019 64位版(Office 2019 64位)早就支持64位Treeview 樹(shù)控件 ListView列表等64位MSCOMMCTL.OCX控件下載
- VBA或VB6調(diào)用WebService(直接Post方式)并解析返回的XML
- 早期PB程序連接Sqlserver出現(xiàn)錯(cuò)誤
- MMC 不能打開(kāi)文件C:/Program Files/Microsoft SQL Server/80/Tools/Binn/SQL Server Enterprise Manager.MSC 可能是由于文件不存在,不是一個(gè)MMC控制臺(tái),或者用后來(lái)的MMC版
- sql server連接不了的解決辦法
- localhost與127.0.0.1區(qū)別
- Roych的淺談數(shù)據(jù)庫(kù)開(kāi)發(fā)系列(Sql Server)
- sqlserver 自動(dòng)備份對(duì)備份目錄沒(méi)有存取權(quán)限的解決辦法
- 安裝Sql server 2005 express 和SQLServer2005 Express版企業(yè)管理器 SQLServer2005_SSMSEE
- 金蝶KIS旗艦版 登錄時(shí)“類型不匹配”
- access行業(yè)交流QQ群-部分行業(yè)交流群(倉(cāng)庫(kù) 人事 工資 考勤 CRM HRM MRP ERP 等)
- access垃圾分類數(shù)據(jù)庫(kù)
- Office提高企業(yè)辦公管理效率
- Access交流網(wǎng)Acccess通用開(kāi)發(fā)平臺(tái)樹(shù)導(dǎo)航出錯(cuò)的解決辦法
- Access交流網(wǎng)Access通用開(kāi)發(fā)平臺(tái)的使用幫助教程及FAQ
- Access采購(gòu)倉(cāng)庫(kù)系統(tǒng)作品源代碼
聯(lián)系人: | 王先生 |
---|---|
Email: | 18449932@qq.com |
QQ: | 18449932 |
微博: | officecn01 |