vc學習(2005-01)

l          定義自己的api

 

 

#ifdef TRANSCLT_EXPORTS

#define CLT_API extern "C" __declspec(dllexport)

#else

#define CLT_API extern "C" __declspec(dllimport)

#endif

 

 

typedef void (*RECVCALLBACK)(PCMD_HEAD pCmd, UINT uHandle, PIP_ADDR pIP, DWORD dwParam = 0);

typedef void (*CONNCALLBACK)(UINT uHandle, PIP_ADDR pIP, DWORD dwParam = 0);

 

 

/* Interface of TransClt.dll */

class ITransClt

{

public:

        virtual BOOL Initialize(DWORD dwSvrIP,

                                                        WORD wSvrPort,

                                                        DWORD dwLocalIP = 0,

                                                        WORD wLocalPort = 0) = 0;

        virtual void Release() = 0;

 

        virtual void RegOnReceive(RECVCALLBACK OnReceive, DWORD dwParam = 0) = 0;

        virtual void RegOnConnect(CONNCALLBACK OnConnect, DWORD dwParam = 0) = 0;

        virtual void RegOnDisconnect(CONNCALLBACK OnDisconnect, DWORD dwParam = 0) = 0;

 

        virtual BOOL SendToServer(LPVOID pBuffer, UINT uSize) = 0;

};

 

/* API interface of TransClt.dll */

CLT_API LPVOID  TransCltCreateObject();

CLT_API DWORD TransCltGetHostIP(int nIPIndex);

 

 

#endif       // _YZ_TCPTRANS_CLIENT_MODULE_INTERFACE_INCLUDE_

 

l          調用有參數的Dll

 

typedef void (WINAPI * TESTDLL)(CString);

HINSTANCE hmod;

hmod = ::LoadLibrary ("ECPMail.dll");

AfxSetResourceHandle(hmod);

if(hmod==NULL)

{

        AfxMessageBox("Fail");

}

TESTDLL lpproc;

lpproc = (TESTDLL)GetProcAddress (hmod,"Show");

if(lpproc!=(TESTDLL)NULL)

{      CString str="sss";

   (*lpproc)(str);

}

FreeLibrary(hmod);

 

}

 

l          Dll的應用

m_pTransClt=(ITransClt*)TransCltCreateObject();

 

if( NULL == m_pTransClt )

                return FALSE;

if( FALSE == m_pTransClt->Initialize(inet_addr("192.168.0.137"), 45876) )

        {

                m_pTransClt->Release();

                m_pTransClt = NULL;

                return FALSE;

        }     

return TRUE;

 

l         modeless Dialog

 

 

For a modeless dialog box, you must provide your own public constructor in your dialog class. To create a modeless dialog box, call your public constructor and then call the dialog object’s Create member function to load the dialog resource. You can call Create either during or after the constructor call. If the dialog resource has the property WS_VISIBLE, the dialog box appears immediately. If not, you must call its ShowWindow member function.

 

l          關於Dll的使用

 

        typedef LPVOID (WINAPI * TESTDLL)();

        HINSTANCE hmod;

        hmod = ::LoadLibrary ("ECPMail.dll");

        AfxSetResourceHandle(hmod);//十分重要

        if(hmod==NULL)

        {

                AfxMessageBox("Fail");

        }

        TESTDLL CreatMailObject;

        CreatMailObject = (TESTDLL)GetProcAddress (hmod,"ECPMailCreateObject");

       

        if(CreatMailObject!=(TESTDLL)NULL)

        {     

 

                IECPMail* m_pECPMail=NULL;

                m_pECPMail=(IECPMail*)CreatMailObject();

 

                m_pECPMail->Initialize(m_dwSvrIP ,45877, m_dwBindIP,45876,AfxGetMainWnd());

                       

                /*

                if( FALSE == m_pECPMail->Initialize(m_dwSvrIP ,45877, m_dwBindIP,45876))

                                {

                                        m_pECPMail->Release();

                                        m_pECPMail = NULL;

                                       

                                }     

                }

        else AfxMessageBox("load Function Faild");

        FreeLibrary(hmod);

 

 

 

 

l          設定一個事件的超時響應

        if(WAIT_TIMEOUT == WaitForSingleObject(g_eventQueryDNUsed,TIMEOUT_WAIT_SVR))

        {

                dwError = ERR_WAIT_SVR_TIMEOUT;

        }

        else

        {

                dwError = g_dwRetQueryDNUsed;

                g_dwRetQueryDNUsed = 0;

                g_eventQueryDNUsed.ResetEvent();

        }

l          如何在靜態函數中調用本身類的動態函數

 

第一步:

static void OnReceive(PCMD_HEAD pCmd, UINT uHandle, PIP_ADDR pIP, DWORD dwParam);

DWORD dwParam-------指向本身類的指針

 

 

 

void MailManage::OnReceive(PCMD_HEAD pCmd, UINT uHandle, PIP_ADDR pIP, DWORD dwParam)

{

        if( 0 != IsBadWritePtr(pCmd->pBuf, pCmd->nBufSize) )

                return;

        // CWnd* pWnd = AfxGetMainWnd();

        MailManage *pManage = (MailManage *)dwParam;

        switch(pCmd->dwCmd)

                {

                        case CMD_MAIL_UPDATE_RET:

                        SetEvent(pManage->g_hEventUpdateMailList);          

                                break;

                       

                        default:

                                break;

                }

}

 

 

        WriteDebugInfo(DBG_THREAD,"/n DistributeRecvData Begin Thread Count = %d MAX_THREAD = %d /n",pThis->m_dwDistribeThreadCount,pThis->m_dwWorkThread);

        CString strDebug = "";

        strDebug.Format("/n DistributeRecvData() Begin! dwThreadCount = %d ThreadID = 0x%x",pThis->m_dwDistribeThreadCount,GetCurrentThreadId());

        OutputDebugString(strDebug);

 

 

 

 

SetParentWnd(CWnd *pParent)

 

AfxGetMainWnd()

 

數據庫編程--dao

 

char sql[ 100 ];

sprintf( sql, "DeviceID = '%s'", m_DeviceID );

rs.FindFirst( ( LPCTSTR )sql );

 

關於DAO數據庫編程的幾點經驗

作者:廣東南海昭信科技有限公司 king_koo

 

 

前言

本文是作者在DAO數據庫編程中積累的經驗,希望對使用DAO進行開發的朋友有所幫助。

 

一、如何在新建時沒選數據庫支持的程序中加入數據庫支持

 

以對話框DAO-Access爲例:

1.1用類嚮導新建類.Name:"mydb", Base Class:"DaoRecordset",選擇正確的數據源和表.

:vc6無法直接對access2000進行支持,要用的話先轉換爲97版才行。

 

1.2mydb頭文件加入#include"afxdao.h".在對話框類頭文件加入#include"mydb.h".

 

1.3測試:在對話框類加入一按鈕,在其響應函數內加入如下代碼:

mydb db;

db.Open();

MessageBox(db.m_answerA);

db.Close();

這裏假設我的數據庫表裏有answerA字段.

 

二、如何在數據庫沒有靜態綁定其它控件的程序手工加入靜態綁定.

 

仍以上面爲例.先把先前的按鈕及其消息處理函數刪掉.加入一EDIT控件.

 

2.1 聲明:在對話框頭文件的AFX_DATA內加入:mydb* rec;如下:

//{{AFX_DATA(CAaaDlg)

      enum { IDD = IDD_AAA_DIALOG };

      mydb* rec;

      // NOTE: the ClassWizard will add data members here

//}}AFX_DATA

 

2.2 綁定:在類嚮導爲edit控件添成員變量m_amswerA.(在嚮導中選擇)

 

2.3 初始化:在對話框構造函數內加入

rec=new mydb;

rec->Open();

     

2.4 銷燬:響應對話框WM_CLOSE消息,加入消息處理代碼:

rec->Close();

delete rec;

     

2.5 測試:編譯運行,就可以看到EDIT框裏出現了數據庫的內容.唯一不足的是不能自動更新顯示.需手工UpdateData(0);

 

三、如何確保上述程序拷到別人機裏仍可運行.(數據庫也拷在同一目錄)

 

把剛纔mydbGetDefaultDBName()函數內容改爲:

char str[255];

GetCurrentDirectory(255,str);

strcat(str,"//my.mdb");

return _T(str);

 

後記

雖然DAO逐漸被ADO所取代,但仍舊有許多網友通過DAO來學習VC下的數據庫編程,以上是自己摸索所得的經驗,希望對初學者有所幫助,有不妥之處請各位大蝦指正!

 

10.8 DAO

 

10.8.1 什麼是DAO

 

  DAO(Database Access Object)使用Microsoft Jet數據庫引擎來訪問數據庫。Microsoft Jet爲象AccessVisual Basic這樣的產品提供了數據引擎。

 

  與ODBC一樣,DAO提供了一組API供編程使用。MFC也提供了一組DAO類,封裝了底層的API,從而大大簡化了程序的開發。利用MFCDAO類,用戶可以編寫獨立於DBMS的應用程序。

 

  DAO是從Visual C++4.0版開始引入的。一般地講,DAO類提供了比ODBC類更廣泛的支持。一方面,只要有ODBC驅動程序,使用Microsoft JetDAO就可以訪問ODBC數據源。另一方面,由於DAO是基於Microsoft Jet引擎的,因而在訪問Access數據庫(*.MDB文件)時具有很好的性能。

 

10.8.2 DAOODBC的相似之處

 

DAO類與ODBC類相比具有很多相似之處,這主要有下面幾點:

 

二者都支持對各種ODBC數據源的訪問。雖然二者使用的數據引擎不同,但都可以滿足用戶編寫獨立於DBMS的應用程序的要求。

 

DAO提供了與ODBC功能相似的MFC類。例如,DAOCDaoDatabase類對應ODBCCDatabase類,CDaoRecordset對應CRecordsetCDaoRecordView對應CRecordViewCDaoException對應CDBException。這些對應的類功能相似,它們的大部分成員函數都是相同的。

 

AppWizardClassWizard對使用DAOODBC對象的應用程序提供了類似的支持。

 

  由於DAOODBC類的許多方面都比較相似,因此只要用戶掌握了ODBC,就很容易學會使用DAO。實際上,用戶可以很輕鬆地把數據庫應用程序從ODBC移植到DAO

 

  Visual C++隨盤提供了一個名爲DaoEnrol的例子,該例實際上是Enroll的一個DAO版本。讀者可以打開DaoEnrol工程看一看,它的源代碼與Enroll的極爲相似。讀者可以按照建立Enroll的步驟來建立DaoEnrol,其中只有若干個地方有差別,這主要有以下幾點:

 

選取的數據源不同。在用AppWizard創建DaoEnrol時,以及在用ClassWizard創建CDaoRecordset類的派生類時,在Database Options對話框中應該選擇DAO而不是ODBC。而且DAO的數據源是通過選擇一個.MDB文件來指定的,即點擊“...”按鈕後在文件對話框中選擇要訪問的.MDB文件。

 

記錄集的缺省類型不同。ODBC記錄集的缺省類型是快照(Snapshot),而DAO則是動態集(Dynaset)

 

參數化的方式不同。DAO記錄集的m_strFilterm_strSort中的參數不是“?”號,而是一個有意義的參數名。例如,在下面的過濾器中有一個名爲CourseIDParam的參數。

m_pSet->m_strFilter ="CourseID = CourseIDParam";

DoFieldExchange函數中,有下面兩行:

pFX->SetFieldType(CDaoFieldExchange::param);

DFX_Text(pFX, _T("CourseIDParam"), m_strCourseIDParam);

DFX函數的第二個參數也是CourseIDParam

 

處理異常的方式不同。例如,在刪除記錄時,對異常的處理如下所示:

 

try

 

{

 

m_pSet->Delete();

 

}

 

catch(CDaoException* e)

 

{

 

AfxMessageBox(e->

 

m_pErrorInfo->m_strDescription);

 

e->Delete();

 

}

 

  除了上述差別外,AppWizardClassWizard也隱藏了一些細微的不同之處,例如,DAO記錄集是使用是DFX數據交換機制(DAO record field exchange)而不是RFX,在DAO記錄集的DoFieldExchange中使用的是DFX函數而不是RFX函數。

 

10.8.3 DAO的特色

 

  DAO可以通過ODBC驅動程序訪問ODBC數據源。但DAO是基於Microsoft Jet引擎的,通過該引擎,DAO可以直接訪問AccessFoxProdBASEParadoxExcelLotus WK等數據庫。CDaoDatabase類可以直接與這些數據庫進行連接,而不必在ODBC管理器中註冊DSN。例如,下面的代碼用來打開一個FoxPro數據庫:

 

CDaoDatabase daoDb;

 

daoDb.Open( “”,FALSE,FALSE,"FoxPro 2.5;DATABASE=c://zyf");

 

CDaoDatabase::Open函數用來連接某個數據庫,該函數的聲明爲:

 

virtual void Open( LPCTSTR lpszName, BOOL bExclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR lpszConnect = _T("") );

throw( CDaoException, CMemoryException );

 

 

 

  參數bExclusive如果爲TRUE,則函數以獨佔方式打開數據庫,否則就用共享方式。如果bReadOnlyTRUE,那麼就以只讀方式打開數據庫。如果要打開一個Access數據庫,則可以在lpszName參數中指定MDB文件名。如果要訪問非Access數據庫,則應使該參數爲“”,並在lpszConnect中說明一個連接字符串。連接字符串的形式一般爲 數據庫類型;DATABASE=路徑(文件)”,例如 “dBASE III;DATABASE=c://MYDIR”

 

  Open函數也可以打開一個ODBC數據源,但這需要相應的ODBC驅動程序,並需要在ODBC管理器中註冊DSN。此時lpszConnect的形式爲 “ODBC;DSN=MyDataSource”。顯然,用DAO訪問象FoxPro這樣的數據庫時,直接打開比把它當作ODBC數據源打開要省事。

 

  支持DDLDAO對數據庫編程良好支持的一個重要體現。DDL(Data Definition Language)SQL術語中叫做“數據定義語言”,它用來完成生成、修改和刪除數據庫結構的操作。ODBC類只支持DML(Data Manipulation Language,數據操作語言),不支持DDL,所以用ODBC類只能完成數據的操作,不能涉及數據庫的結構。要執行DDL操作,只有通過ODBC API。而DAO類同時提供了對DMLDDL的支持,這意味着程序可以使用DAO類方便的創建數據庫及修改數據庫的結構。

 

  與ODBC相比,DAO提供了一些新類來加強其功能,這些新類包括:

 

CDaoTableDef類提供了對錶的結構的定義。調用CDaoTableDef::Open可以獲得表的結構定義。調用CDaoTableDef::Create可以創建一張新表,調用CDaoTableDef:: CreateField可爲表添加字段,調用CDaoTableDef::CreateIndex可以爲表添加索引。調用CDaoTableDef::Append可以把新創建的表保存到數據庫中。

 

CDaoQueryDef類代表一個查詢定義(Query definition),該定義可以被存儲到數據庫中。

 

CDaoWorkspace提供了數據工作區(Workspace)。一個工作區可以包含幾個數據庫,工作區可以對所屬的數據庫進行全體或單獨的事務處理,工作區也負責數據庫的安全性。如果需要,程序可以打開多個工作區。

 

  DAO的另一個重要特色在於它對Access數據庫提供了強大的支持。由於DAO是基於Microsoft Jet引擎的,所以DAO肯定要在Access數據庫上多作一些文章。例如,調用CDaoDatabase::Create可以直接建立一個MDB文件,代碼如下所示:

m_db.Create(“C://MYDIR//MYDB.MDB”);

 

利用AppWizardClassWizard,用戶可以方便地開發出性能優良的基於DAOAccess數據庫應用程序。

 

10.8.4 ODBC還是DAO

 

由於DAO可以訪問ODBC數據源,下面幾條可以作爲DAO替代ODBC的理由:

 

在某些情況下可以獲得更好的性能,特別是在訪問Microsoft Jet.MDB)數據庫時。

 

ODBC兼容

 

DAO允許數據有效檢查

 

DAO允許用戶說明表與表之間的關係

 

  當然,DAO的出現並不意味着ODBC已經過時了。如果用戶的工作必須嚴格限於ODBC數據源,尤其是在開發Client/Server結構的應用程序時,用ODBC有較好的性能。

 

直接通過DAO讀寫Access文件

作者:徐景周

下載示例源代碼 http://www.vckbase.com/code/downcode.asp?id=1643

 

直接利用DAO來創建、讀寫Access文件,總的說來,對比上篇《直接通過ODBC讀、寫Excel文件》來講,要簡單一些。在下面的示例中,我們將用到兩種方法:SQLDAO類函數來混合實現它們,這樣做的目地,我想可以使大家更加方便靈活的運用它們來完成你想要做的東西。在示例程序中默認指定創建數據庫名爲:Demo.mdb,內部表名爲:DemoTable,寫入兩個字段:名字和年齡,採用和上一篇讀寫Excel類似的操作,你也可以根據自己需要來動態改變它們。示例程序運行界面如下所示:

 

 

 

下面讓我們來簡要看看它的實現步驟:

1. 首先,應確保包含進了afxdao.h頭文件,可以在StdAfx.h文件中包含它,如下:

 

 

#include <afxdao.h>                        //加入DAO數據庫支持

 

2. 聲明DAO庫及其記錄集變量,可在你的實現文件中加入下面代碼: CDaoDatabase db;                                       //數據庫

CDaoRecordset RecSet(&db);         //記錄集

 

3. 接着,先讓我們來實現它的創建及寫入操作void CRWAccessDlg::OnWriteAccess()

{

        //獲取主程序所在路徑,存在sPath

        CString sPath;

        GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH);

        sPath.ReleaseBuffer ();

        int nPos;

        nPos=sPath.ReverseFind (''//'');

        sPath=sPath.Left (nPos);

 

        //默認創建數據名:Demo.mdb,內部表名:DemoTable,表內有二個字段:姓名、年齡

        CString lpszFile = sPath + "//Demo.mdb";

       

        CFileFind  fFind;

        BOOL bSuccess;

        bSuccess=fFind.FindFile(lpszFile);

 

        fFind.Close ();

    //是否已有創建好的Demo.mdb文件,沒有則創建它

        if(!bSuccess)

        {

                db.Create(lpszFile);

 

                CString SqlCmd = "CREATE TABLE DemoTable(Name VARCHAR(20),Age VARCHAR(3));";

                db.Execute(SqlCmd);

       

                //打開已創建的數據表

                RecSet.Open(AFX_DAO_USE_DEFAULT_TYPE,

                        "SELECT * FROM DemoTable", 0);

                //加入第一個記錄,用SQL語句

                db.Execute("INSERT INTO DemoTable (Name,Age) VALUES (''徐景周'',26)");

               

                //加入第二個記錄,用DAO涵數

                RecSet.AddNew();

                RecSet.SetFieldValue("Name","徐志慧");

                RecSet.SetFieldValue("Age","21");

                RecSet.Update();

               

                //加入第三個記錄,用DAO涵數

                RecSet.AddNew();

                RecSet.SetFieldValue("Name","郭徽");

                RecSet.SetFieldValue("Age","27");

                RecSet.Update();

               

                //關閉記錄集及庫

                RecSet.Close();

                db.Close();

 

                AfxMessageBox("Access文件寫入成功!");

        }

        else

                AfxMessageBox("Demo.mdb數據庫已經創建!");

       

}

 

4. 最後,讓我們來實現它的讀取操作。void CRWAccessDlg::OnReadAccess()

{

        COleVariant var;              // 字段類型

        var.ChangeType(VT_BSTR, NULL);

        CString strName,strAge,strFile;

 

        //清空列表框

        m_AccessList.ResetContent();

 

        //獲取主程序所在路徑,存在sPath

        CString sPath;

        GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH);

        sPath.ReleaseBuffer ();

    int nPos;

        nPos=sPath.ReverseFind (''//'');

        sPath=sPath.Left (nPos);

 

        strFile = sPath + "//demo.mdb";

        db.Open(strFile);              // 打開已創建的demo數據庫及DamoTable

        RecSet.Open(AFX_DAO_USE_DEFAULT_TYPE,"SELECT * FROM DemoTable",NULL);

 

        while(!RecSet.IsEOF())    // 有沒有到表結尾

        {

                RecSet.GetFieldValue("Name",var);

                strName = (LPCSTR)var.pbstrVal;

                RecSet.GetFieldValue("Age",var);

                strAge = (LPCSTR)var.pbstrVal;

                m_AccessList.AddString( strName + " --> "+strAge );

 

                RecSet.MoveNext();

        }

 

        //關閉記錄集及庫

        RecSet.Close();

        db.Close();

}

 

以上部分代碼的具體實現的細節問題,可在下載實例代碼後,仔細查看源碼既可(內有詳細註釋)

 

如果在DAO程序中用的是SQL方法,abc123的位置用%s,然後用逗號m_DeviceID,例如:strSQl=("Select * from 表名 Where 字段名='%s'",m_strname)

m_pDaoDatabase->Excute(strSQL);

m_pDaoDatabase是數據庫指針。

 

 

m_pMainWnd->SetWindowText("Receiver");

 

 

CString str="Receiver";

 

CWnd *pWnd=CWnd::FindWindow(NULL,str);

 

if(pWnd)

 

pWnd->SendMessage(WM_COMM,0,0);

 

Handle

 

HandlePathName好像關係不大,有幾種函數可以找Handle

 

HWND FindWindow(

  LPCTSTR lpClassName,  // class name

  LPCTSTR lpWindowName  // window name

);

 

BOOL EnumWindows(

  WNDENUMPROC lpEnumFunc,  // callback function

  LPARAM lParam            // application-defined value

);

 

函數原型:HWND GetWindowHWND hWndUNIT nCmd);

 

    參數:

 

    hWnd:窗口句柄。要獲得的窗口句柄是依據nCmd參數值相對於這個窗口的句柄。

 

    nCmd:說明指定窗口與要獲得句柄的窗口之間的關係。該參數值可以是下列之一:

 

    GW_CHILD:如果指定窗口是父窗口,則獲得的是在Z序頂端的子窗口的句柄,否則爲NULL。函數僅檢查指定父窗口的子窗口,不檢查繼承窗口。

 

    GW_ENABLEDPOUP:(WindowsNT 5.0)返回的句柄標識了屬於指定窗口的處於使能狀態彈出式窗口(檢索使用第一個由GW_HWNDNEXT 查找到的滿足前述條件的窗口);如果無使能窗口,則獲得的句柄與指定窗口相同。

 

    GW_HWNDFIRST:返回的句柄標識了在Z序最高端的相同類型的窗口。如果指定窗口是最高端窗口,則該句柄標識了在Z序最高端的最高端窗口;如果指定窗口是頂層窗口,則該句柄標識了在z序最高端的頂層窗口:如果指定窗口是子窗口,則句柄標識了在Z序最高端的同屬窗口。

 

    GW_HWNDLAST:返回的句柄標識了在z序最低端的相同類型的窗口。如果指定窗口是最高端窗口,則該柄標識了在z序最低端的最高端窗口:如果指定窗口是頂層窗口,則該句柄標識了在z序最低端的頂層窗口;如果指定窗口是子窗口,則句柄標識了在Z序最低端的同屬窗口。

 

    GW_HWNDNEXT:返回的句柄標識了在Z序中指定窗口下的相同類型的窗口。如果指定窗口是最高端窗口,則該句柄標識了在指定窗口下的最高端窗口:如果指定窗口是頂層窗口,則該句柄標識了在指定窗口下的頂層窗口;如果指定窗口是子窗口,則句柄標識了在指定窗口下的同屬窗口。

 

    GW HWNDPREV:返回的句柄標識了在Z序中指定窗口上的相同類型的窗口。如果指定窗口是最高端窗口,則該句柄標識了在指定窗口上的最高端窗口;如果指定窗口是頂層窗口,則該句柄標識了在指定窗口上的頂層窗口;如果指定窗口是子窗口,則句柄標識了在指定窗口上的同屬窗口。

 

    GW_OWNER:返回的句柄標識了指定窗口的所有者窗口(如果存在)。

 

    返回值:如果函數成功,返回值爲窗口句柄;如果與指定窗口有特定關係的窗口不存在,則返回值爲NULL

 

    若想獲得更多錯誤信息,請調用GetLastError函數。

 

    備註:在循環體中調用函數EnumChildWindow比調用GetWindow函數可靠。調用GetWindow函數實現該任務的應用程序可能會陷入死循環或退回一個已被銷燬的窗口句柄。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章