VC程序如何通过注册表判断一个特定的OCX控件是否已注册
- 2017-09-10 10:25:00
- 网络摘录 转贴
- 7604
把下面的 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();
}
- office课程播放地址及课程明细
- Excel Word PPT Access VBA等Office技巧学习平台
- 将( .accdb) 文件格式数据库转换为早期版本(.mdb)的文件格式
- 将早期的数据库文件格式(.mdb)转换为 (.accdb) 文件格式
- KB5002984:配置 Jet Red Database Engine 数据库引擎和访问连接引擎以阻止对远程数据库的访问(remote table)
- Access 365 /Access 2019 数据库中哪些函数功能和属性被沙箱模式阻止(如未启动宏时)
- Access Runtime(运行时)最全的下载(2007 2010 2013 2016 2019 Access 365)
- Activex控件或Dll 在某些电脑无法正常注册的解决办法(regsvr32注册时卡住)
- office使用部分控件时提示“您没有使用该ActiveX控件许可的问题”的解决方法
- RTF文件(富文本格式)的一些解析
- Access树控件(treeview) 64位Office下出现横向滚动条不会自动定位的解决办法
- Access中国树控件 在win10电脑 节点行间距太小的解决办法
- EXCEL 2019 64位版(Office 2019 64位)早就支持64位Treeview 树控件 ListView列表等64位MSCOMMCTL.OCX控件下载
- VBA或VB6调用WebService(直接Post方式)并解析返回的XML
- 早期PB程序连接Sqlserver出现错误
- MMC 不能打开文件C:/Program Files/Microsoft SQL Server/80/Tools/Binn/SQL Server Enterprise Manager.MSC 可能是由于文件不存在,不是一个MMC控制台,或者用后来的MMC版
- sql server连接不了的解决办法
- localhost与127.0.0.1区别
- Roych的浅谈数据库开发系列(Sql Server)
- sqlserver 自动备份对备份目录没有存取权限的解决办法
- 安装Sql server 2005 express 和SQLServer2005 Express版企业管理器 SQLServer2005_SSMSEE
联系人: | 王先生 |
---|---|
Email: | 18449932@qq.com |
QQ: | 18449932 |
微博: | officecn01 |