VC++6.0&&VS2008&MFC&API学习问题总结(一)(多线程CreateThread及小问题汇总)

以下资料部分收集于网络,部分是自己碰到的问题(内容将陆续更新):

1、VC++6.0无法设置断点:先关闭程序,然后删除目录下的.opt和.ncb文件,重新打开项目,就OK!


2、这个无奈问题折腾了很久,一直以为是数据库问题,本来是修改的东西,害我把数据库整体变成了access的:vc++如何利用ADO在连接sql2005

m_pConnection->Open("Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=HRMS;Data Source=.\\SQLEXPRESS","","",adModeUnknown); //建立数据库连接,Data Source不需要完整路径,但是尽量添加,防止出错

Provider=SQLOLEDB.1 ------打开数据库用oledb的方式连接
Integrated Security=SSPI
  Microsoft安全支持提供器接口(SSPI)是定义得较全面的公用API,用来获得验证、信息完整性、信息隐私等集成安全服务,以及用于所有分布式应用程序协议的安全方面的服务。应用程序协议设计者能够利用该接口获得不同的安全性服务而不必修改协议本身。上面这句话的意思就是这个连接采用了这个接口,如果没有定义就会出错!
Persist Security Info ----是否保存安全信息
User ID-------------------用户名
PassWord------------------密码
Initial Catalog-----------数据库的名称或者数据库ip或者目录
Data Source---------------数据源

[DBNETLIB][ConnectionOpen(connect()).]SQL Server 不存在或拒绝访问的解决办法:这个问题基本上是连接数据库的连接字出错,网上天马行空的还是跳过吧!

更为详细的VC+ADO下连接并操作sql2005数据库方法总结操作请参考:http://topic.csdn.net/u/20111028/14/186567e7-e9a2-4ee8-8eb6-5604d4ebd9db.html,至此,数据库部分:ado,odbc来操作sql/access告一段落。


3、MFC类成员函数作为线程函数的解决办法

int  dwThreadId;    HANDLE hTread=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)ThreadFunc1,this,0,(LPDWORD)&dwThreadId);

//(LPTHREAD_START_ROUTINE)如果不加的话出现如下问题(其实说来说去就是不符合createthread各个参数的类型,保险起见都强制类型转换,如此函数最后一个参数(LPDWORD)&dwThreadId)

error C2664: 'CreateThread' : cannot convert parameter 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)

正常的成员函数不能作为线程函数!这时候怎么办呢?~可以把要作为线程函数的成员函数定义成static的,如
public:
         static DWORD WINAPI globalConverterFunc(LPVOID lp);
这样,编译可以通过!但是问题又来了,static成员不能操作非static成员变量,就是没有this指针~解决办法是,建立线程时,传递一个this指针就啦~如:
HANDLE hThread;
	DWORD ThreadID;
	hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)globalConverterFunc,this,0,&ThreadID);
这样,在static线程函数里面,做个强制类型转换,把lp转换成类指针,问题解决!
自己在写程序中是这么做的:
声明:static DWORD WINAPI ReadPortThread(LPVOID lpParameter);
调用:HANDLE m_hReadThread=CreateThread(NULL,0,ReadPortThread,this,0,NULL);
多线程函数部分:
DWORD WINAPI CSerialPorts::ReadPortThread(LPVOID lpParameter)
{
    CSerialPorts* m_pSerial=(CSerialPorts*)lpParameter;    //把lpParameter转换成类指针
    CThreadDlg* m_Thread=new CThreadDlg();                 //在CSerialPorts的多线程下调用CThreadDlg类中的函数
    ....................
    m_Thread->DataArrivedMsg(buf,dwLength);
}
LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递),然后在使用的时候再转换回来。  
可以将其理解为long型的指针,指向void型。 

4、int num = 10;char str[100]; itoa(num, str, 2);       itoa的头文件是<stdlib.h>,因此keil或者c中都是可以用的!

itoa()函数有3个参数:第一个参数是要转换的数字,第二个参数是目标字符串,第三个参数是转移数字时所用 的基数。在上例中,转换基数为10。10:十进制;2:二进制……
//             m_Show=num;        //更新edit控件数据的方法之一
//             UpdateData(FALSE);//将成员变量的数据传给界面 而UpdateData(TRUE);的话是将界面数据传给成员变量


5、ASSERT(m_nTimer != 0);如果m_nTimer!=0返回非0继续运行,如果0则显示错误内容,但不会终止程序运行,如果想显示错误并终止运行使用

VERIFY( booleanExpression)


6、vs2008中char []' to 'LPCTSTR'报错:

m_Show.SetWindowText("你好");如果上述报错,在项目(project)->属性(property)中常规(general)中有个字符集选项,里面有选用多字节还是Unicode改成多字节(Multi-Byte),问题解决。


7、再现离奇问题,EVC工程,当然VC6也可能出现:

0120514\Mfc\Src\dlgcore.cpp(1006) : error C2491: 'CDialog::classCDialog' : ……几十号错误,都是因为莫名在工程中的资源中添加了dlgcore.cpp,把他删掉即可。


8、MFC几个常用的消息映射

    工具栏的载入OnCreate函数是“消息”中的WM_CREATE消息映射的;

    定时器使用OnTimer函数是“消息”中的WM_TIMER消息映射的;

    OnInitDialog是在"重写"中的OnInitDialog消息映射的;

    其他:windows消息常见的有鼠标消息(如WM_LBUTTONDOWN)消息)、键盘字符消息(WM_CHAR消息)、键盘按键消息(WM_KEYDOWN)、窗口重画消息WM_PAINT,水平和垂直条滚动消息WM_HSCROLL和WM_VSCROLL)以及系统时钟消息WM_TIMER等。


9、mfc基于对话框的应用程序如何添加菜单栏:在对话框头文件中声明CMenu 变量,例如CMenu m_Menu;在OnInitDlg()中加入如下语句:m_Menu.LoadMenu("此处加入你的菜单id");SetMenu(&m_Menu);


10、线程问题:error C3867: ...function call missing argument list=====

    hRecvThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)CommRecvTread,this,0,NULL);其中CommRecvTread声明一定要加上static如下static DWORD CommRecvTread(LPVOID pParam);——个人理解,线程是全局跑的,如果你所有的线程都在一个类下当然可以不加static但如果有其他类,则必须加保证其全局性。


11、 CreateEvent讲解

事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。

产生事件对象的函数如下:  

HANDLE     CreateEvent(

        LPSECURITY_ATTRIBUTES     lpEventAttributes,     //     SD   
        BOOL     bManualReset,                                                 //     reset     type   
        BOOL     bInitialState,                                                      //     initial     state   
        LPCTSTR     lpName                                                       //     object     name   
    );   
    该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。

参数说明:
    lpEventAttributes     一般为NULL  
    bManualReset              创建的Event是自动复位还是人工复位.如果true,人工复位,  一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号.    如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,  该Event就会自动复位,变成无信号.   如果想在每次调用WaitForSingleObject后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。
    bInitialState             初始状态,true,有信号,false无信号   
    lpName                  事件对象的名称。您在OpenEvent函数中可能使用。

注释:
   一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()   来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()      来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.  
    PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.   

    对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于人工复位的Event对象,它释放所有等待的thread. 


12、Visual C++开发调试技巧

如何清除所有的断点Ctrl + Shift + F9

如何检测程序中的括号是否匹配Ctrl + ]

添加Lib文件到当前工程单击菜单【Project】->【Settings…】弹出“Project Setting”对话框,切换到“Link”标签页,在“Object/library modules”处输入Lib文件名称,不同的Lib之间用空格格开;

变量设定:线程函数可以且必须是全局函数或者是静态成员函数;




你可能感兴趣的:(网络,mfc,vc++)