CA-SDK Sample軟體的SOP by MFC

製作Sample軟體的SOP

開發環境:VC++6
參考文件:4: CA-SDK Software Explanation(某份文件的第四章,網路找不到,要跟廣柏要)
Driver:CA-SDK 4.20
目的:在過程中熟悉VC++操作,得到初步的成就感。
聲明:
此篇文章之所有程式碼,皆由官方參考文件上剪下貼上,並無做任何修改。純粹是要練習官方參考文件中的Sample(只是它寫得很亂,所以我自己另外整理了這一篇)

我們要做出一個這樣的軟體

示範程式使用的工具:VC++6

開啟VC++之後就要開始了。



Step 1.開啟新專案

    File→New(Ctrl+N)
    New對話框就出現了
    • 點選Project標籤,選MCF AppWizard(exe)
    • 命名:Ca200Sample
    • 決定路徑:x:\xx\Ca200Sample
    • 其它(Platforms要選Win32)
    • OK
    第二頁選Diaog、語系同預設值→Next
    第三頁Automation、ActiveX Controls打勾,其它用預設值→Next
    第四頁全預設值→Next
    第五頁直接Finish
    OK之後就可以看見新增好的專案,如下:
    可以看見有一個對話框,有一個預設的「確定」和「取消」的Button。

Step 2.新增物件

新增十個static text
再新增兩個Button。

對它們其中一個按右鍵選擇Properties(屬性)


  • ID是被呼叫的名字
  • Caption是顯示的字(不管函數呼叫名稱)
  • 設定屬性
  • Static6-10的Properties選Style標籤,勾選「Sunken」它就會看起來凹下去。
  • 預設的「取消鍵」的Properties選General標籤
  • 取消勾選「Visible」執行程式時就看不到它了。

物件 ID Caption 作用
State1: IDC_STATIC Lv: 標示Lv
State2: IDC_STATIC x: 標示x
State3: IDC_STATIC y: 標示y
State4: IDC_STATIC T: 標示T
State5: IDC_STATIC duv: 標示duv
State6: IDC_STATIC_LV NULL 顯示Lv值
State7: IDC_STATIC_X NULL 顯示x 值
State8: IDC_STATIC_Y NULL 顯示y 值
State9: IDC_STATIC_T NULL 顯示T 值
State10: IDC_STATIC_DUV NULL 顯示 duv 值
button1: IDC_BUTTON_MSR Measure
button2: IDC_BUTTON_CAL0 0-Cal

Step 3.準備事件觸發設定

用BN_CLICKED觸發0-Cal和Measure
按View→ClassWizard(Ctrl+W)
MFC ClassWizard就出現了
  • Project:Ca200Sample
  • Calss name:CCa200SampleDlg(對話視窗)
  • Object IDs:IDC_BUTTON_CAL0(0-Cal的按鈕物件)
  • Message:BN_CLICKED(按一下的事件)
  • 新增IDC_BUTTON_CAL0物件有BN_CLICKED事件的程式編輯段
  • 新增IDC_BUTTON_MSR物件有BN_CLICKED事件的程式編輯段
直接按OK就可以了
成功之後,可以在MFC ClassWizard的「Message Maps」標籤中,下面的「member functions:」看見
在MFC ClassWizard切到Member Variables標籤
按Add Variables
新增下列的DDX(Dialog Data Exchange)成員到static text
Control IDs Type Variable Type Member Member variable name Category
IDC_STATIC_LV CString m_strLv Value
IDC_STATIC_X CString m_strx Value
IDC_STATIC_Y CString m_stry Value
IDC_STATIC_T CString m_strT Value
IDC_STATIC_DUV CString m_strduv Value
IDC_BUTTON_MSR
IDC_BUTTON_CAL0

Step 4.事件觸發程式

貼上下列式碼
將0-Cal程式段放在Cal0按鈕中執行

Ca200SampleDlg.cpp

...
void CCa200SampleDlg::OnButtonCal0()
{
        // TODO: Add your control notification handler code here
        // CA-SDK
        try{
        m_pCaObj->CalZero();
        }
        catch(_com_error e){
                CString strerr;
                strerr.Format(_T("HR:0x%08x\nMSG:%s"), e.Error(), (LPCSTR)e.Description());
                AfxMessageBox((LPCSTR)strerr);
                return;
        }
        CButton* pb;
        pb = (CButton *)GetDlgItem(IDC_BUTTON_MSR);
        pb->EnableWindow(TRUE);
...
}
貼上下列式碼
將量測程式段放在Measure按鈕中執行

Ca200SampleDlg.cpp

...
void CCa200SampleDlg::OnButtonMsr()
{
// TODO: Add your control notification handler code here
        // CA-SDK
        int i;
        float fLv;
        float fx;
        float fy;
        long lT;
        float fduv;
        for (i = 0; i < 10; i++)
        {
                m_pCaObj->Measure(0);
                fLv = m_pProbeObj ->Lv;
                fx = m_pProbeObj ->sx;
                fy = m_pProbeObj ->sy;
                lT = m_pProbeObj ->T;
                fduv = m_pProbeObj ->duv;
                m_strLv.Format("%4.2f",fLv);
                m_strx.Format("%1.4f",fx);
                m_stry.Format("%1.4f",fy);
                m_strT.Format("%4d",lT);
                m_strduv.Format("%1.4f",fduv);
                UpdateData(FALSE);
        }
}
...
其中
m_pProbObj、m_pCaObj...等,在Step 5.會解釋怎麼出現的。
PORT_USB、SYNC_NTSC、AVRG_FAST、DSP_LXY、DIGT_4...等,會在Const.h檔裡

Step 5.儀器初始化

到主畫面中,左邊的欄位選FileView
貼上下列式碼

Ca200SampleDlg.h

..
#if !defined(AFX_CA200SAMPLEDLG_H__ACD091F1_B9F2_4561_8FD0_F7D37051F8AC__INCLUDED_)
#define AFX_CA200SAMPLEDLG_H__ACD091F1_B9F2_4561_8FD0_F7D37051F8AC__INCLUDED_
//CA-SDK
#import "C:\Program Files\CA-SDK\SDK\CA200Srvr.dll" no_namespace no_implementation
...

Ca200SampleDlg.cpp

...
#include "Ca200SampleDlg.h"
#include "DlgProxy.h"
//CA-SDK
#import "C:\Program Files\CA-SDK\SDK\CA200Srvr.dll" no_namespace implementation_only
在此CA200Srvr.tlh和CA200Srvr.tli檔自動產生
CA200Srvr.tli包含下列的Class
ICa200Ptr
ICasPtr(以下簡稱smart pointer)
ICa200,ICas等是由CA200Srvr.dll提供
嗯...基本上是屁話!
還是要自己Keyin進去
而且不同於上一步在MFC Wizard的Member Variables中的方式
在這好像是先建立公開的類別成員,但是並沒有對應的元件,之前的步驟有對應的元件
在Ca200SampleDlg類別原型中建立這些公開成員
Variable Type Variable Name
IOutputProbesPtr m_pOutputProbesObj
IProbesPtr m_pProbesObj
ICasPtr m_pCasObj
IMemoryPtr m_pMemoryObj
IProbePtr m_pProbeObj
ICaPtr m_pCaObj
ICa200Ptr m_pCa200Obj
貼上程式碼到對應的位置
進行CA儀器的初始化

Ca200SampleDlg.cpp

...
BOOL CCa200SampleDlg::OnInitDialog()
{
        ...
        // TODO: Add extra initialization here
        //CA-SDK
        long lcan = 1;
        _bstr_t strcnfig(_T("1"));
        long lprt = PORT_USB;
        long lbr = 38400;
        _bstr_t strprbid(_T("P1"));
        _variant_t vprbid(_T("P1"));
        try
        {
                m_pCa200Obj = ICa200Ptr(__uuidof(Ca200));
                m_pCa200Obj->SetConfiguration(lcan, strcnfig, lprt, lbr);
        }
        catch(_com_error e)
        {
                CString strerr;
                strerr.Format(_T("HR:0x%08x\nMSG:%s"), e.Error(), (LPCSTR)e.Description());
                AfxMessageBox((LPCSTR)strerr);
                return TRUE;
        }
        m_pCasObj           = m_pCa200Obj->Cas;
        m_pCaObj            = m_pCasObj ->ItemOfNumber[lcan];
        m_pOutputProbesObj  = m_pCaObj ->OutputProbes;
        m_pOutputProbesObj ->RemoveAll();
        m_pOutputProbesObj ->Add(strprbid);
        m_pProbeObj        = m_pOutputProbesObj ->Item[vprbid];
        m_pMemoryObj       = m_pCaObj->Memory;
        m_pCaObj->SyncMode      = SYNC_NTSC;
        m_pCaObj->AveragingMode = AVRG_FAST;
        m_pCaObj->SetAnalogRange(2.5, 2.5);
        m_pCaObj->DisplayMode   = DSP_LXY;
        m_pCaObj->DisplayDigits = DIGT_4;
        m_pMemoryObj->ChannelNO = 0;
return TRUE;
}
...

Step 6.Sink Object

用MFC ClassWizard建立新類別CCaEvent
按Add Class→New...來新增新類別
新增一個類別CCaEvent是以CCmdTarget為基礎的類別
再來,新增CCaEvent的成員函數(Method)
到MFC ClassWizard的Automation標籤
設定Class name:CCaEvent
選Add Method...
出現對話框如下
在此設定的東西,將會出現在CCaEvent.ccp
定義CCaEvent的成員函數及內容
  • External name:ExeCalZero
  • Internal name:ExeCalZero
  • Return type:void(無回傳值)
  • 無回傳值的Method是一種介面函數,定義呼叫時要存取Class靜態成員的方法
貼上程式碼

Ca200Sample.odl

...
        //  Class information for CCaEvent
        //CA-SDK
        //[ uuid(D8D16B03-170A-4340-B718-0A4402531938) ]
        [uuid(f7663750-5900-45eb-905f-78c5d5378481) ]
        coclass CaEvent
        {
                [default] dispinterface ICaEvent;
...
IID_ICaEvent在CaEvent實現檔中,應該也要對成員函數下相同的定義。
也要移除掉static繼承成員。
參考此IID也貼到下列的程式段,才會OK。

CaEvent.cpp

...
//CA-SDK
// {8DCF1114-787E-446C-BF4F-D283C178FA49}
//static const IID IID_ICaEvent =
//{ 0x8dcf1114, 0x787e, 0x446c, { 0xbf, 0x4f, 0xd2, 0x83, 0xc1, 0x78, 0xfa, 0x49 } };
//f7663750-5900-45eb-905f-78c5d5378481
const IID IID_ICaEvent =
{ 0xf7663750, 0x5900, 0x45eb, { 0x90, 0x5f, 0x78, 0xc5, 0xd5, 0x37, 0x84, 0x81 } };
...

CaEvent.h

...
//CA-SDK
extern const IID IID_ICaEvent;
/////////////////////////////////////////////////////////////////////////////
// CCaEvent command target
class CCaEvent : public CCmdTarget
{
DECLARE_DYNCREATE(CCaEvent)
...
新增0-Cal的事件觸發程式碼,相同的軟體,當事件發生時,Measure會變不能按。

CaEvent.cpp

...
void CCaEvent::ExeCalZero()
{
        // TODO: Add your dispatch handler code here
        // CA-SDK
        CWinApp* papp = AfxGetApp();
        CCa200SampleDlg* pdlg = reinterpret_cast(papp -> m_pMainWnd);
        CButton* pb;
        pb = (CButton *)(pdlg ->GetDlgItem(IDC_BUTTON_MSR));
        pb->EnableWindow(FALSE);
}
改變sink class裡的public成員構造
貼上程式到下列程式段中,直接建立sink object,才會OK。

CaEvent.h

...
class CCaEvent : public CCmdTarget
{
        DECLARE_DYNCREATE(CCaEvent)
        //CA-SDK
        // CCaEvent(); // protected constructor used by dynamic creation
        // Attributes
        public:
                // Operations
        public:
                //CA-SDK
                CCaEvent();
        ...
};
...
最後,沒錯!這一步快結束啦!
就是要在CaEvent.cpp裡include Ca200SampleDlg.h檔
不然現在compiler會出問題
CCa200SampleDlg* pdlg無定義

CaEvent.cpp

// CaEvent.cpp : implementation file
//
#include "stdafx.h"
#include "Ca200Sample.h"
#include "CaEvent.h"
#include "Ca200SampleDlg.h"
...
最後的最後,沒錯!剛剛是「快」結束啦!這次是真的...這一步之後就結束啦!
增加下列的Public成員變數到Ca200SampleDlg
Variable Type Variable Name
IConnectionPointPtr m_pIConnectionPointObj
IDispatch* m_pIDispatch
DWORD m_dwCk

Step 7. Sink Object建立連結和事件觸發

貼上下列式碼
初始化Sink Object

Ca200Sample.cpp

BOOL CCa200SampleDlg::OnInitDialog()
...
        m_dwCk = 0;
        CCaEvent* pevntobj;
        if (NULL != (pevntobj = new CCaEvent)){    //{bmc circle1.bmp}
            m_pIDispatch = pevntobj ->GetIDispatch(FALSE);
            IConnectionPointContainerPtr pcpcobj;
                DWORD dwck;
                pcpcobj = m_pCaObj;
                pcpcobj -> FindConnectionPoint(IID_ICaEvent, &m_pIConnectionPointObj);
                m_pIConnectionPointObj ->Advise(m_pIDispatch, &dwck);
                m_dwCk = dwck;
        }
        ...
}

貼上下列式碼
結束CA儀器到PC的遠端連線

Ca200Sample.cpp

void CCa200SampleDlg::OnOK()
{
        if (CanExit())
        //CA-SDK
        {
                if (m_dwCk != 0)
                {
                        m_pIConnectionPointObj ->Unadvise(m_dwCk);
                }
                m_pIDispatch ->Release();
                m_pCaObj ->RemoteMode = 0;
                CDialog::OnOK();
        }
}
在Ca200SampleDlg.cpp上include CaEvent.h檔

Ca200Sample.cpp

// Ca200SampleDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Ca200Sample.h"
#include "Ca200SampleDlg.h"
#include "DlgProxy.h"
#include "CaEvent.h"
...

Step 8. 錯誤觸發

其實可以略,因為它早就存在不用貼上了。
但是還是介紹一下好了

Ca200SampleDlg.cpp

BOOL CCa200SampleDlg::OnInitDialog()
{
...
        try
        {
                m_pCa200Obj = ICa200Ptr(__uuidof(Ca200));
                m_pCa200Obj->SetConfiguration(lcan, strcnfig, lprt, lbr);
        }
        catch(_com_error e)
        {
                CString strerr;
                strerr.Format(_T("HR:0x%08x\nMSG:%s"), e.Error(), (LPCSTR)e.Description());
                AfxMessageBox((LPCSTR)strerr);
                return TRUE;
        }
...
}

Step 9. Const.h檔

這是最後一步了!貼完就完了!
File→New
等等!在貼上之前(因為貼上是最後一步)
要先將Const.h include 到Ca200SampleDlg.cpp檔裡

Ca200SampleDlg.cpp

// Ca200SampleDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Ca200Sample.h"
#include "Ca200SampleDlg.h"
#include "DlgProxy.h"
#include "CaEvent.h"
#include "Const.h"
...
最後貼上Const.h檔內容,就完成啦!
檔案:Const.h
程式碼:
// Const.h
// Definitions file
// Comm port type
#define PORT_USB 0
#define PORT_COM1 1
#define PORT_COM2 2
#define PORT_COM3 3
#define PORT_COM4 4
#define PORT_COM5 5
#definee PORT_COMMAX 255
// CA display mode
#define DSP_LXY 0
#define DSP_DUV 1
#define DSP_ANL 2
#define DSP_ANLG 3
#define DSP_ANLR 4
#define DSP_PUV 5
#define DSP_FMA 6
#define DSP_XYZC 7
#define DSP_JEITA 8
#define DSP_XYZ 9
// CA sync mode
#define SYNC_NTSC 0
#define SYNC_PAL 1
#define SYNC_EXT 2
#define SYNC_UNIV 3
#define SYNC_INT 4
// CA display digits
#define DIGT_3 0
#define DIGT_4 1
// CAFAST/SLOW setting
#define AVRG_SLOW 0
#define AVRG_FAST 1
#define AVRG_AUTO 2
// CA luminance units
#define BUNIT_FL 0
#define BUNIT_CD 1
// Konica Minolta calibration standard
#define CAL_D65 1
#define CAL_9300 2
#define CAL_CA100 3
// CA type
#define CATYPE_210 0
#define CATYPE_210S 1
#define CATYPE_100PLUS 2
#define CATYPE_200 3
// Probe type
#define PROBETYPE_CA100PLUS 1001
#define PROBETYPE_CA100PLUSH 1002
#define PROBETYPE_CA210 2100
#define PROBETYPE_CA210S 2101
// Remote mode
#define REMOTE_OFF 0
#define REMOTE_ON 1
#define REMOTE_LOCK 2
// Reference color
#define CAL_RED 0
#define CAL_GREEN 1
#define CAL_BLUE 2
#define CAL_WHITE 3

結束!compiler一下看看吧!

文章分類維度