VC程序如何通過註冊錶判斷一箇特定的OCX控件是否已註冊

2017-09-10 10:25:00
網絡摘録
轉貼
1575


把下麵的   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;  
  }   
 
先關閉掉所有子UI線程的窗口,這樣纔能讓子UI線程正常結束掉。使用EnumChildWindows枚舉當前程序中的對話框。
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")) //當前窗體是對話框 && dwProcessID==GetCurrentProcessId() && hwnd!=(HWND)lParam)
//當前窗體是當前程序的,且不是主窗體 { PostMessage(hwnd,WM_CLOSE,0,0); } return TRUE; }
// 主窗體關閉時接受消譭消息
void CTSUServerDlg::OnDestroy()
{ EnumChildWindows(GetDesktopWindow()->GetSafeHwnd(),EnumChildProc,(LPARAM)GetSafeHwnd());
 WaitForMultiplyObjects(5,hThreadList,TRUE, INFINITE); //等待所有子線程(包含UI線程)結束}
//當用戶點擊要關閉主窗體時
void CTSUServerDlg::OnExit() { CDialog::OnCancel(); PostQuitMessage(0); }
用戶界麵線程-(含有消息泵的線程)-主線程與用戶界麵線程的通信. 收藏
vckbase站點上,由一箇多線程的demo,講得是UI線程,如何開啟一箇UI界麵線程.但是裡麵沒有涉及到主線程如何和UI線程間通信.
這箇問題,我搞瞭好久.
其實很簡單,給一箇線程髮消息 PostThreadMessage().
  BOOL   PostThreadMessage(  
   
          DWORD   idThread, //   thread   identifier     {這箇蔘數爲線程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("無效thread ID(你是否把線程句柄傳瞭進去?:))! 或者線程裡麵沒有消息泵!!!");
  }
 }
WM_SPLASH_NOTIFY是自己定義的一箇常量, 可以不用加入消息映射 呵呵. 直接在UI線程的PreTranslateMessage裡麵捕穫處理就好瞭.:), 當然, 通過MFC的宏加入消息處理函數也可以, 不過原理是一樣的.

   , 那麽主線程如何知道UI界麵線程的ID呢?
答案是: 通過AfxBeginThread()函數創建線程時, 返迴CWinThread* pThead指針.
AfxBeginThread()返迴一箇CWinThread*對象指針,  
  CWinThread*   pThread   =   AfxBeginThread(...)   ;  
  pThread->m_nThreadID就是創建線程的ID.
特彆註意 , pThead->m_hThread是線程的句柄!!!! 不可以作爲PostThreadMessage()的蔘數,否則會提示: error   C2664:   'PostThreadMessageA'   :   cannot   convert   parameter   1   from   'void   *'   to   'unsigned   long'   編譯錯誤.
具體蔘見如下帖子.
http://topic.csdn.net/t/20040509/14/3045752.html
 
那麽我們髮瞭消息後, 用戶界麵線程如何處理消息呢?
重載PreTranslateMessage()函數.
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);
}
 
補充説明兩點
1: 線程ID 不衕於線程句柄, ID可用於給線程髮消息.
2: 線程句柄 可用於控製線程的執行,比如, 關閉線程, 暫停線程啥的.

也就是通常意義上的UI界麵線程, 可以給該線程髮消息. 呼呼.
  3,4的説法可能有問題,已經測試過,對於工作線程, 已經測試過, 不可以在工作線程裡麵peekmessage.(peekmessage總是返迴false, peek不到message ), .但是可以work thread成功髮送消息, 但work thread裡麵 peekmessage老是失敗.不知道CWinThread做瞭什麽手腳.呼呼.

 MSG msg;
 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
蔘見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);
}
需要進行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上詳細講解用戶界麵線程原理的文章.
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;//改變變量,線程結束
WaitForSingleObject(pThread->m_hThread,INFINITE);//等待線程結束
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事件有信號,無信號時線程在這裡懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}
線程內部 AfxEndThread(2000);
if (m_pThread1 == NULL)
 {
  return;
 }
 DWORD dwExitCode = 0;
 if (::GetExitCodeThread(m_pThread1->m_hThread, &dwExitCode))
 {   
  if (dwExitCode == STILL_ACTIVE)
  {
   AfxMessageBox(_T("線程正在運行\n"));
  }
  else
  {
   CString strText = _T("");
   strText.Format("線程退齣,退齣碼:%d\n", dwExitCode);
   AfxMessageBox(strText);
  }
 }
延時
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爲什麽無法在其他機器上註冊——很急
項目屬性 - 配置屬性 - C++ - 代碼生成,運行時庫選擇“多線程(/MT)”
 
 
單欄選擇"項目"->項目名稱+"屬性",在打開的對話框右側選"配置屬性"->"常規",併在右側將"MFC 的使用"改爲"在靜態庫中使用 MFC",
 
隻要靜態鏈接MFC應該就可以瞭吧。你用depends看看你的可執行文件都鏈接瞭哪些DLL。
 
 
全局變量一般這樣定義:
1。在一類的.cpp中定義 int myInt;
然後再在要用到的地方的.cpp裡extern int myInt;這樣就可以用瞭。

2。在stdafx.cpp中加入:
int myInt;
然後在stdafx.h中加入:
extern int myInt
這樣定義以後無論在什麽文件中都是可見的.

3。比較規範的是,先定義一箇Glbs.h,把所有的全局變量原始定義放進去。然後定義一箇Externs.h,把你先前定義在Glbs.h中的變量都加上extern。註意:如果你在Glbs.h中設置瞭初值,那麽在Externs.h中就不要加值瞭。然後調用時,第一次調用的#i nclude <Glbs.h>,以後調用的#i nclude <Externs.h>

另:

問:如何在VC++中使用全局變量,以使文檔中的所有類都能訪問。 
答:把該變量放到該應用程序類的頭文件中的attribute處。然後,在程序的任何地方,你都可以用下麵的方法來訪問該變量: 
CMyApp *app=(CMyApp*)AfxGet-App(); 
app->MyGlobalVariable=… 
用這箇方法,不但可以定義全局變量,也可以定義全局對象。 
例如: 
MyClass MyObject; 
CMyApp*app=(CMyApp*)AfxGet-App(); 
app->MyObject.MyFunction(); 

VC中使用全局變量的2種辦法及防錯措施 

1. 對於全局變量存在和函數一樣的問題,爲瞭在其他CPP文件中能夠訪問這些變量,必鬚在主文件的H文件中加上extern聲明,格式如下: 
extern varibletype var; (聲明)
在主文件的CPP文件中定義 
varibletype var; (定義)
在線程之間傳遞信號進行通信比較複雜的方法是使用事件對象,用MFC的Cevent類的對象來錶示。事件對象處於兩種狀態之一:有信號和無信號,線程可以監視處於有信號狀態的事件,以便在適當的時候執行對事件的操作。上述例子代碼修改如下:
////////////////////////////////////////////////////////////////////
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事件有信號,無信號時線程在這裡懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}
在線程之間傳遞信號進行通信比較複雜的方法是使用事件對象,用MFC的Cevent類的對象來錶示。事件對象處於兩種狀態之一:有信號和無信號,線程可以監視處於有信號狀態的事件,以便在適當的時候執行對事件的操作。上述例子代碼修改如下:
////////////////////////////////////////////////////////////////////
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事件有信號,無信號時線程在這裡懸停
If(result==Wait_OBJECT_0)
Bend=TRUE;
}
::PostMessage(hWnd,WM_USERMSG,0,0);
return 0;
}
/////////////////////////////////////////////////////////////
Void CtestView::OninitialUpdate()
{
hWnd=GetSafeHwnd();
threadStart.SetEvent();//threadStart事件有信號
pThread=AfxBeginThread(ThreadFunction,hWnd);//啟動線程
pThread->m_bAutoDelete=FALSE;
Cview::OnInitialUpdate();
}
////////////////////////////////////////////////////////////////
Void CtestView::OnDestroy()
{
threadEnd.SetEvent();
WaitForSingleObject(pThread->m_hThread,INFINITE);
delete pThread;
Cview::OnDestroy();
}

分享