1. 程式人生 > >VC++6.0&&VS2008&MFC&API學習問題總結(一)(多執行緒CreateThread及小問題彙總)

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告一段落。

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)

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之間用空格格開;

變數設定:執行緒函式可以且必須是全域性函式或者是靜態成員函式;