DWORD idThread, //線程ID,通過創(chuàng)建線程后的id
UINT Msg, //消息id
WPARAM wParam,
LPARAM lParam);
代碼片段如下:
kenlistian厚積薄發(fā). 勤為槳,思為帆 |
2009年3月22日 #
2009年3月17日 #
2009年3月13日 #
2009年3月9日 #
對于pin的連接過程,總結(jié)下.
1.
應(yīng)用程序通過調(diào)用filter graph 管理器方法來連接filter.
應(yīng)用程序調(diào)用IFilterGraph::ConnectDirect
IGraphBuilder::Connect來指定不同的filter直接連接,
也可用IGraphBuilder::RenderFile自動實現(xiàn)連接
應(yīng)用程序可以通過IFilterGraph::AddFilter將filter 添加graph中,
當(dāng)一個filter被添加到graph中時,filter圖表管理器通過IBaseFilter::JoinFilterGraph來通知filter.
這點說明, 不是filter的直接連接函數(shù)相互鏈接,而是在以上內(nèi)部調(diào)用實現(xiàn)的.
2. 考慮到以前描述
FilterA ---->FilterB
的連接檢查媒體類型 邏輯基本就是這樣:
循環(huán)FilterA的輸出pin,再循環(huán)FilterB的輸入Pin媒體類型是否和pmt媒體類型
匹配
for (j = 0 ; j<FilterB.PinIn.MediaTypeCount; j++)
{
if (FilterB.PinIn.MediaType[j] = pmt )
{
if(FilterA.PinIn.ReceiveConnection(FilterA.PinOut, FilterB.MediaType[i]) = OK)
return TRUE;
}
}
for (i= 0; i< FilterA.PinOut.MediaTypeCount; i++)
{
if (FilterA.PinOut.MediaType[i] 是否在FilterB.PinIn中是否支持)
if (FilterA.PinIn.ReceiveConnection(FilterA.PinOut, FilterA.MediaType[i]) = OK)
return TRUE;
}
在實現(xiàn)上,調(diào)用次序以下過程:
filterGraph首先調(diào)用FilterA.PinOut::Connect().
FilterA.IPinOut::Connect()
原型:IPin::Connect(IPin* pReceivePin, const AM_MEDIA_TYPE * pmt)
該Connect參數(shù)為
pReceivePin 為 FilterB的輸入Pin,
pmt 是FilterA的當(dāng)前媒體類型.
在內(nèi)部調(diào)用(主要)
hr = AgreeMediaType(pReceivePin, pmt);
檢查pReceivePin 有否pmt的媒體類型.
有,則自然ok
沒有,失敗,退出該函數(shù).
則在AgreeMediaType做了以上邏輯循環(huán).
IPin::AgreeMediaType函數(shù)處理如下:
1.判斷pmt 是否是完全媒體類型,是則按全媒體類型模式出來
2.非完全媒體類型
IPin::EnumMediaTypes(IEnumMediaTypes** pEnum)
獲取枚舉指針(指向Pin中的媒體類型集合).
先枚舉filterB的輸入Pin的媒體類型的枚舉集,
調(diào)用TryMediaTypes 函數(shù)去判斷是否匹配.
還不匹配,取出FilterA的枚舉類指針.再調(diào)用TryMediaTyes
IPin::TryMediaType()處理
原型:
HRESULT CBasePin::TryMediaTypes(IPin*pReceivePin, const CMediaType*pmt,
IEnumMediaType *pEnum)
在該函數(shù)處理:
for (pmt in 所有該枚舉集中的枚舉媒體類型 )
{
AttemptConnect(pReceivePin, pmt)
}
在AttemptConnection中調(diào)用
CBasePin::AttemptConnection(IPin* pReceivePin, const CMediaType*pmt)
檢查FilterA 的CheckConnect(pReceivePin)
FilterA的PInOut::CheckMediaType(pmt)
ok,return
FilterA的PinOut::SetMediaType(pmt)
pReceivePin->ReceiveConnection(...) (filterB 的PinIn)
ok,return
FilterA的PinOut::CompleteConnect(pReceivePin)
2009年2月6日 #
自定義消息處理
(不知道在wxpython,wxruby如何自定義類型消息?
最好裝個wxpython,在其demo現(xiàn)場編寫現(xiàn)場查看結(jié)果)
步驟如下:
1.在宏里處理如下:
a.
xxxx 為自定義數(shù)字,不過翻到wxwidget內(nèi)部,其宏定義中該value好像
沒用!(...)
b. 定義wxEvT_MYCOMMAND 標(biāo)識
c. 定義宏EVT_MYCOMMAND
格式中把自定義標(biāo)識改為自己即可.拷貝.
2.在BEGIN_EVENT_TABLE表中自定義映射.
3.處理投遞
自定義消息發(fā)送,this 一般是接受消息handler,也可其它wxEvtHandler.
4.自定義消息處理函數(shù)
必須符合wxCommandEventFunction格式,既為如下:
2009年2月3日 #
2009年1月5日 #
幾個格式細(xì)節(jié)備記(混)
typedef struct _MediaType {
GUID majortype;
GUID subtype;
BOOL bFixedSizeSamples;
BOOL bTemporalCompression;
ULONG lSampleSize;
GUID formattype;
IUnknown *pUnk; //not use
ULONG cbFormat;
BYTE *pbFormat;
} AM_MEDIA_TYPE;
主要有
majortype 媒體類型大致說明
subtype 更一步的細(xì)致說明
formattype
包括有以下:其對應(yīng)的不同的數(shù)據(jù)格式
FORMAT_None
FORMAT_DvInfo
FORMAT_MPEGVideo
FORMAT_MPEG2Video
FORMAT_VideoInfo
FORMAT_VideoInfo2
FORMAT_WaveFormatEx
GUID_NULL
cbForamt成員指定了格式塊pbFormat的大小.
pbFormat指針指向格式子塊。
pbFormat是一個void*的指針,因為格式塊會因為媒體類型
的不同而有不同的指向。如音頻填充的是WAVEFORMATEX結(jié)構(gòu)
數(shù)據(jù).
可以從中取出傳來的數(shù)據(jù)格式。
//TWaveFormatEx 結(jié)構(gòu):
TWaveFormatEx = packed record
wFormatTag: Word; {指定格式類型; 默認(rèn) WAVE_FORMAT_PCM = 1;}
nChannels: Word; {指出波形數(shù)據(jù)的通道數(shù); 單聲道為 1, 立體聲為 2}
nSamplesPerSec: DWORD; {指定樣本速率(每秒的樣本數(shù))}一般為8000
nAvgBytesPerSec: DWORD; {指定數(shù)據(jù)傳輸?shù)钠骄俾?每秒的字節(jié)數(shù))} 每秒的字節(jié)數(shù):
nBlockAlign: Word; {指定塊對齊(單位字節(jié)), 塊對齊是數(shù)據(jù)的最小單位}
wBitsPerSample: Word; {采樣大小(字節(jié))}每個樣本的BIT數(shù)目,一般為16
cbSize: Word; {應(yīng)該是該結(jié)構(gòu)的大小}
end;
nChannels : 對于pcm,其nchannels不超過2,對于非pcm格式,則超過2.
nSamplesPerSec : 通常為8kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz.
nAvgBytesPerSec : 每秒傳送字節(jié)數(shù) = nSamplesPerSec * nBlockAlign
nBlockAlign : 對齊字節(jié) = nChannels * wBitsPerSample / 8
就是表示一個樣本的最小字節(jié).
wBitsPerSample : 在格式默認(rèn)情況下,一般為8,16,表示的是樣本的bit 數(shù)
對于一個8位,11k傳輸?shù)牧Ⅲw聲則
nChannels = 2
nSamplesPerSec(每秒的樣本數(shù)) = 11025 就是取樣數(shù)
nBlockAlign = 2 * 8 / 8= 2 對齊字節(jié),最小樣本字節(jié)數(shù)
nAvgBytesPerSec = 11025 * 2 = 22050
wBitsPerSample = 8
下面的圖列清楚從另一個方面表達(dá)樣本
樣本1 | 樣本2 | ...n | |
8位單聲道 | 0聲道 | 0聲道 | |
8位立體聲 | 0聲道L 1聲道R | 0聲道L 1聲R道 | |
16位單聲道 | 0聲道(低字節(jié)) 0聲道(高字節(jié)) | 0聲道(低字節(jié)) 0聲道(高字節(jié)) | |
16位立體聲 |
0聲道(低字節(jié))0聲道(高字節(jié))1聲道(低) 1聲道(高) |
同左 |
---------
waveform-audio 緩存格式
typedef struct {
LPSTR lpData; //內(nèi)存指針,放置音頻pcm樣本數(shù)據(jù)
DWORD dwBufferLength; //長度
DWORD dwBytesRecorded; //已錄音的字節(jié)長度
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops; //循環(huán)次數(shù)
struct wavehdr_tag* lpNext; //保留
DWORD reserved; //保留
} WAVEHDR;
其中l(wèi)pdata 即為pcm格式樣本數(shù)據(jù)。
采樣大小為8位,則采樣的動態(tài)范圍為20*log(256)分貝=48db。
樣本大小為16位,則采樣動態(tài)范圍為20*log(65536)大約是96分貝
振幅大小: 20*log(A1/A2)分貝,A1,A2為兩個聲音的振幅。
則對于的音頻:
8位 20 * lg( lpData[0] /256)
16位 20 * lg( lpData[0]--lpData[1] / 65536)
考慮到單雙道,還需要相應(yīng)取出左右聲道的值。
考慮到lg求值為負(fù)48至0之間,則在實際轉(zhuǎn)換中需要+48or96.
樣本大小 數(shù)據(jù)格式 最大值 最小值
8位PCM unsigned int 256 0
16位PCM int 32767 -32767
8位音頻是unsigned 存放波形,取振幅要-127.
而16位因其存放為int 類型,直接套用公式.
audiometer左右聲道音量探測程序(參考代碼(delphi版)
2008年12月28日 #
2008年12月27日 #
1、配置DirectDound的開發(fā)環(huán)境
包含以下
#include <mmsystem.h>
#include <dsound.h>
添加Dsound.lib庫
comctl32.lib dxerr9.lib winmm.lib dsound.lib dxguid.lib odbc32.lib odbccp32.lib,
2 DiectDound幾個對象
創(chuàng)建一個設(shè)備對象,后通過設(shè)備對象創(chuàng)建緩沖區(qū)對象。
輔助緩沖區(qū)由應(yīng)用程序創(chuàng)建和管理,DirectSound會自動地創(chuàng)建和管理主緩沖區(qū),
3 播放音頻文件開發(fā)的基本流程
a 創(chuàng)建一個設(shè)備對象,設(shè)置設(shè)備對象的協(xié)作度。
調(diào)用DirectSoundCreat8創(chuàng)建一個支持IDirectSound8接口的對象,
這個對象通常代表缺省的播放設(shè)備。
如果沒有聲音輸出設(shè)備,這個函數(shù)就返回error,或者,在VXD驅(qū)動程序下,
如果聲音輸出設(shè)備正被某個應(yīng)用程序通過waveform格式的api函數(shù)所控制,
該函數(shù)也返回error。
當(dāng)創(chuàng)建完設(shè)備對象后,調(diào)用IDirectSound8::SetCooperativeLevel來設(shè)置
協(xié)作度,否則聽不到聲音.
b.創(chuàng)建一個輔助Buffer,也叫后備緩沖區(qū)
(IDirectSound8::CreateSoundBuffer)
創(chuàng)建的buffer稱作輔助緩沖區(qū),Direcsound通過把幾個后備緩沖區(qū)的聲音
混合到主緩沖區(qū)中,然后輸出到聲音輸出設(shè)備上,達(dá)到混音的效果。
c. 獲取PCM類型的數(shù)據(jù)
將WAV文件或者其他資源的數(shù)據(jù)讀取到緩沖區(qū)中。
d. 將數(shù)據(jù)讀取到緩沖區(qū)
其中用到以下來鎖緩沖區(qū)。
IDirectSoundBuffer8::Lock
IDirectSoundBuffer8::Unlock.
e. 播放緩沖區(qū)中的數(shù)據(jù)
IDirectSoundBuffer8::Play 播放緩沖區(qū)中的音頻數(shù)據(jù),
IDirectSoundBuffer8::Stop 暫停播放數(shù)據(jù),
獲取或者設(shè)置正在播放的音頻的音量的大小
IDirectSoundBuffer8::GetVolume
IDirectSoundBuffer8::SetVolume
獲取設(shè)置音頻播放的頻率
IDirectSoundBuffer8::GetFrequency
IDirectSoundBuffer8::SetFrequency
主緩沖區(qū)的頻率不允許改動,
設(shè)置音頻在左右聲道播放的位置
IDirectSoundBuffer8::GetPan
IDirectSoundBuffer8::SetPan
包含全部音頻數(shù)據(jù)的緩沖區(qū)我們稱為靜態(tài)的緩沖區(qū),
盡管不同的聲音可能會反復(fù)使用同一個內(nèi)存buffer,但靜態(tài)緩沖區(qū)的數(shù)據(jù)只寫入一次。
靜態(tài)緩沖區(qū)只填充一次數(shù)據(jù),然后就可以play,
給靜態(tài)緩沖區(qū)加載數(shù)據(jù)分下面幾個步驟
1、用IDirectSoundBuffer8::Lock函數(shù)來鎖定所有的內(nèi)存,
指定你鎖定內(nèi)存中你開始寫入數(shù)據(jù)的偏移位置,并且取回該偏移位置的地址。
2、采用標(biāo)準(zhǔn)的數(shù)據(jù)copy方法,將音頻數(shù)據(jù)復(fù)制到返回的地址。
3、調(diào)用IDirectSoundBuffer8::Unlock.,解鎖該地址。
用static buffer 播放wav方法
f 流緩沖區(qū)播放超大型的wave文件
流緩沖區(qū)就是播放那些比較長的音頻文件,邊播放,邊填充DirectSound緩沖區(qū)。
DirectSound的通知機制
因為Stream buffer 大小只夠容納一部分?jǐn)?shù)據(jù),在播放完緩沖區(qū)中的數(shù)據(jù)后,
DirectSound就會通知應(yīng)用程序,將新的數(shù)據(jù)填充到DirectSound的緩沖區(qū)中。
當(dāng)DirectSound播放到buffer的1920,3840,5760,7680等位置時,
Directsound就會通知應(yīng)用程序,將g_event,設(shè)置為通知態(tài);
應(yīng)用程序就通過WaitForMultipleObjects 函數(shù)等待DirectSound的通知,
將數(shù)據(jù)填充到DirectSoun的輔助緩沖區(qū)。
2008年12月15日 #
2008年12月10日 #
2008年12月9日 #
1.采用系統(tǒng)設(shè)備枚舉器來枚舉.
根據(jù)硬件系統(tǒng)種類來枚舉系統(tǒng)中注冊的filter。
每一種不同的硬件可能有自己的filter,也可能所有的硬件設(shè)備共用filter。
系統(tǒng)設(shè)備枚舉器是根據(jù)不同的種類來創(chuàng)建的,如,音頻壓縮,視頻捕捉。
不同種類的枚舉器對于每一種設(shè)備返回一個獨立的名稱(moniker)。
下面的步驟是使用設(shè)備枚舉器來獲取設(shè)備:
1) 創(chuàng)建枚舉器組件,CLSID為CLSID_SystemDeviceEnum
2) 指定某一種類型設(shè)備,獲取該種類枚舉器
通過ICreateDevEnum::CreateClassEnumerator獲取某一種類的枚舉器,
該函數(shù)返回一個IEnumMoniker接口指針,
通過檢查返回值是否為S_OK來判斷是否獲取到該種類枚舉器.
3) 用IEnumMoniker::Next枚舉每一個moniker。
這個方法返回一個IMoniker接口指針。
4) 通過IMoniker::BindToStorage獲取設(shè)備的名稱
大致例子如下:
2.采用Filer Mapper。
類似條件查詢。
比系統(tǒng)設(shè)備枚舉器(System Device Enumerator)的效率要低一些。
當(dāng)要枚舉某特定種類的filter時,應(yīng)采用系統(tǒng)設(shè)備枚舉器方法,但搜索支持某種
媒體類型的filter時,用filter mapper.
Filter Mapper 通過IFilerMapper2接口搜索接口,
通過調(diào)用IFilterMapper2::EnumMatchingFilters方法,傳遞一些參數(shù)來定義搜索條件,
返回一個適合條件的filter的枚舉器,
返回的是一個IEnumMoniker接口,并對于每個適合的filter都提供一個單獨的moniker。
例子:
2008年12月8日 #
使用DirectShow寫一個音頻捕捉例子
DirectShow對硬件的支持是通過特定的包裝Filter來實現(xiàn)的。
聲卡使用的是Audio Capture Filter,F(xiàn)ilter內(nèi)部使用以waveIn開頭
的一套API實現(xiàn)(如waveInOpen等)。
運行GraphEdit,插入Filter時,在“Audio Capture Sources”目錄下,
就能看到所有代表本地機器上的聲卡的各個Filter(裝了幾張聲卡,就會有幾個Filter)
DirectShow加入一個硬件Filter,是靠“枚舉”;聲卡Filter也不例外。
代表聲卡的Filter都注冊在CLSID_AudioInputDeviceCategory目錄下,
使用系統(tǒng)設(shè)備枚舉器枚舉這個目錄,就能發(fā)現(xiàn)要創(chuàng)建的聲卡對象。
(如何枚舉這里就不再贅述了。)
當(dāng)成功加入聲卡Filter后,接下去的問題就是要將這個Filter與其他Filter相連。
想捕捉生成一個Wave文件,采用過濾器的勾連如下
聲卡filter--->Wave Dest Filter ---->File Writer Filter
Wave Dest Filter是微軟DirectX SDK自帶的過濾器
其功能是,當(dāng)結(jié)束捕捉時,往Wave文件中寫入一個文件頭信息。
Filte Write Filter 是微軟系統(tǒng)過濾器。
用graphedit可以勾連后測試下。
//采用程序來連接過濾器的大致方法:
//沒有處理錯誤
void BuildAudioCaptureGraph(void)
{
IBaseFilter *pSrc = NULL, //捕捉音頻設(shè)備
*pWaveDest = NULL, //處理音頻過濾器
*pWriter = NULL; //產(chǎn)生文件過濾器
IFileSinkFilter *pSink= NULL;
IGraphBuilder *pGraph;
// Create the Filter Graph Manager.
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
// Add the audio capture filter.
//這里省略了枚舉設(shè)備處理
FindAudioCapture(&pSrc);
// audio capture devices and picks one.
pGraph->AddFilter(pSrc, L"Capture");
// Add the WavDest and the File Writer.
AddFilterByClsid(pGraph, L"WavDest", CLSID_WavDest, &pWavDest);
AddFilterByClsid(pGraph, L"File Writer", CLSID_FileWriter, &pWriter);
//是writer接口中屬性
pWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pSink);
pSink->SetFileName(L"C:\test.wav", NULL);
//連接filter
ConnectTwoFilters(pGraph, pSrc, pWavDest);
ConnectTwoFilters(pGraph, pWavDest, pWriter);
}
DirectShow技術(shù)是建立在DirectDraw和DirectSound組件基礎(chǔ)之上的,
它通過DirectDraw對顯卡進(jìn)行控制以顯示視頻,
通過DirectSound對聲卡進(jìn)行控制以播放聲音。
DirectShow功能實現(xiàn):
1.可提供高質(zhì)量的多媒體流的捕獲和回放功能;
2.支持多種媒體格式,包括ASF(Advanced Systems Format),MPEG(Motion Picture Experts Group),AVI(Audio-Video Interleaved),MP3(MPEG Audio Layer-3)和WAV聲音文件;
3.可從硬件上捕獲媒體數(shù)據(jù)流;
4.可自動檢測并使用視頻和音頻加速硬件。
故,DirectShow是用于多媒體應(yīng)用開發(fā)。(其實就是一個軟編碼(or解碼))
它充分發(fā)揮媒體的性能,提高運行速度,可以簡化媒體播放、媒體間的格式轉(zhuǎn)換
和媒體捕獲等工作。同時,它還具有極大的可擴(kuò)展性和靈活性,可以由用戶自己
創(chuàng)建組件,并將這個組件加入DirectShow結(jié)構(gòu)中以支持新的格式或特殊的效果。
應(yīng)用程序與DirectShow組件以及DirectShow所支持的軟硬件之間的關(guān)系
如圖1
二。概念
1.過濾器
過濾器分為以下幾種類型:
a 源過濾器(source filter):
源過濾器引入數(shù)據(jù)到過濾器圖表中,數(shù)據(jù)來源可以是文件、網(wǎng)絡(luò)、照相機等。
不同的源過濾器處理不同類型的數(shù)據(jù)源。
b 變換過濾器(transform filter):
變換過濾器的工作是獲取輸入流,處理數(shù)據(jù),并生成輸出流。
變換過濾器對數(shù)據(jù)的處理包括編解碼、格式轉(zhuǎn)換、壓縮解壓縮等。
c 提交過濾器(renderer filter):
接收數(shù)據(jù)并把數(shù)據(jù)提交給外設(shè)。
d 分割過濾器(splitter filter):
把輸入流分割成多個輸出。
如,AVI分割過濾器把一個AVI格式的字節(jié)流分割成視頻流和音頻流。
e 混合過濾器(mux filter):
把多個輸入組合成一個單獨的數(shù)據(jù)流。
如,AVI混合過濾器把視頻流和音頻流合成一個AVI格式的字節(jié)流。
過濾器的這些分類并不是絕對的,如一個ASF讀過濾器(ASF Reader filter)
既是一個源過濾器又是一個分割過濾器。
2 filter graph
過濾器圖表用來連接過濾器以控制媒體流,它也可以將數(shù)據(jù)返回給應(yīng)用程序,
并搜索所支持的過濾器。
過濾器有三種可能的狀態(tài):運行、停止和暫停。
暫停是一種中間狀態(tài),停止?fàn)顟B(tài)到運行狀態(tài)必定經(jīng)過暫停狀態(tài)。
暫停可以理解為數(shù)據(jù)就緒狀態(tài),是為了快速切換到運行狀態(tài)而設(shè)計的。
在暫停狀態(tài)下,數(shù)據(jù)線程是啟動的,但被提交過濾器阻塞了。
通常情況下,過濾器圖表中所有過濾器的狀態(tài)是一致的。
3. 引腳(pin)
過濾器可以和一個或多個過濾器相連,
連接的接口也是COM形式的,稱為引腳。
過濾器利用引腳在各個過濾器間傳輸數(shù)據(jù)。
每個引腳都從Ipin這個COM對象派生出來的。
每個引腳都是過濾器的私有對象,過濾器可以動態(tài)的創(chuàng)建引腳,銷毀引腳,自由控制引腳的生存時間。
引腳分輸入引腳(Input pin)和輸出引腳(Output pin)兩種類型,
兩個相連的引腳必須是不同種類的,即輸入引腳只能和輸出引腳相連
過濾器之間的連接(也就是引腳之間的連接),實際上是連接雙方媒體類型(Media Type)協(xié)商的過程。(媒體類型,不完全媒體類型 再下一節(jié)有講解)
連接的大致過程為:
如果調(diào)用連接函數(shù)時已經(jīng)指定了完整的媒體類型,則用這個媒體類型進(jìn)行連接,
成功與否都結(jié)束連接過程;
如果沒有指定或不完全指定了媒體類型,
則枚舉過程見后面.其兩個filter的連接設(shè)定如下.
Filter A ------------------> Filter B
------------------------------------------------------------- ------------------
說明:
媒體類型(Media Type)
兩個過濾器相連時,必須使用一致的媒體類型,否則這兩個過濾器就不能相連。
媒體類型能識別上一級過濾器傳送給下一級過濾器的數(shù)據(jù)類型,并對數(shù)據(jù)進(jìn)行分類。
媒體類型的結(jié)構(gòu) AM_MEDIA_TYPE
AM_MEDIA_TYPE由三部分組成:
Major type
Subtype
Format type
都使用GUID 來唯一標(biāo)示
Major type主要定性描述一種媒體類型,這種媒體類型可以是視頻、音頻、比特數(shù)據(jù)流或MIDI數(shù)據(jù)等;
Subtype 進(jìn)一步細(xì)化媒體類型,
拿視頻的說就是進(jìn)一步指定是RGB-24,還是RGB-32,或是UYVY等;
Format type則用一個結(jié)構(gòu)更進(jìn)一步細(xì)化媒體類型。
媒體類型的三個部分都指定了某個具體的GUID值,則稱這個媒體類型是完全指定的;
媒體類型的三個部分中有任何一個值是GUID_NULL,則稱這個媒體類型是不完全指定的。
GUID_NULL起通配符作用
pinout和pinin的連接過程可以用下面邏輯語言表達(dá).
1.如調(diào)用連接函數(shù)時已經(jīng)指定了完整的Media type,則用這個Media type進(jìn)行連接,
成功與否都結(jié)束連接過程;
2.如沒有指定或不完全指定了Media type,
則如下:
BOOL CheckFilterB_PinIn()
{
for(i = 0 ; i < FilterB.FPinIn.MediaTypeCount ; i++)
{
if (IsSameMediaType(FilterA.FPinOut,FilterB.FPinIn.MediaType[i]) = True)
{
return TRUE; //Pin之間的連接成功;
}
}
return FALSE; //在Input pin不支持該媒體類型,失敗.
}
返回FALSE再枚舉Output pin上的所有Media type,并逐一用這些Media type與Input pin進(jìn)行連接。
for(i = 0 ; i < FilterA.FPinOut.MediaTypeCount; i++)
{
if (CheckFilteB_PinIn(FilterA.FPinOut.MediaType[i]) = True )
{
return TRUE;
}
}
return FALSE; //filterA和filterB的連接失敗.
DirectShow 的幾個接口說明
(1) IGraphBuilder接口
用于構(gòu)造Filter Graph的接口,建立和管理一系列的Filter,過濾和處理源媒體流。
(2) IMediaControl接口
用于控制多媒體流在Filter Graph中的流動,如流的啟動和停止。
(3) IMediaEvent接口
用于捕獲播放過程中發(fā)生的事件,并通知應(yīng)用程序,如EC_COMPLETE等。
(4) IVideoWindow接口
用于控制視頻窗口的屬性。
(5) IMeadiaSeeking接口
用于查找媒體的接口,定位流媒體,控制多媒體數(shù)據(jù)播放提供精確控制。
(6) IBaseFilter接口
從ImediaFilter接口繼承,用來定義一個具體的過濾器指針,并對多媒體數(shù)據(jù)進(jìn)行處理。
(7) IPin接口
用于管理兩個過濾器之間的Pin,從而連接過濾器。
(8) IsampleGrabberCB接口
是Sample Grabber過濾器的一個接口,用于當(dāng)流媒體數(shù)據(jù)通過過濾器時進(jìn)行采樣以獲得幀圖象。
Filter必須加入到Filter Graph并接入到工作鏈路中才能發(fā)揮作用。
如想繞過Filter Graph而直接使用Filter實現(xiàn)的功能模塊,那就要將Filter功能
移植成DirectX媒體對象(DMO)。
Filter有3種狀態(tài):停止、暫停和運行。
Filter Chain是相互連接著的一條Filter鏈路,并且鏈路中的每個Filter全都有一個處于“已連接”狀態(tài)的
輸入Pin,至多有一個處于“已連接”狀態(tài)的輸出Pin,這條Filter鏈路中的數(shù)據(jù)流不依賴鏈路外的其他Filter。
Filter Chain通過IFilterChain接口來進(jìn)行相關(guān)操作。
當(dāng)Filter Graph處于運行狀態(tài)下,F(xiàn)ilter Chain可以在運行和停止?fàn)顟B(tài)之間切換;
當(dāng)Filter Graph處于暫停狀態(tài)下,F(xiàn)ilter Chain可以在暫停和停止?fàn)顟B(tài)之間切換。
Filter Chain只有兩種狀態(tài)轉(zhuǎn)換。
Filter的數(shù)據(jù)傳送
Filter之間以Sample的形式傳送數(shù)據(jù)。
Sample是一個封裝了一定大小數(shù)據(jù)內(nèi)存的COM組件。
用于數(shù)據(jù)傳輸?shù)囊话闶禽斎雙in上實現(xiàn)的IMemInputPin接口。
2008年11月14日 #
2008年11月5日 #
前言:wxWidgets 是跨平臺的GUI庫,用VC6會影響它的跨平臺性嗎?當(dāng)然不會,我們只是用VC6充當(dāng)編譯器和編輯器,只要編寫代碼時注意不使用Windows相關(guān)的特性,寫出的代碼仍然是跨平臺的,仍然是可以在其它操作系統(tǒng)下(如Linux)使用其它C++編譯器(如GCC)編譯并運行的。
為什么用VC6,只不過此文專門針對VC6而已。
點擊菜單:File -> New... 創(chuàng)建一個"Win32 Application" Project,項目名稱為"wxProject",點擊OK按鈕,
在下一步的提示中選擇"An Empty Project",點擊Finish按鈕完成項目的創(chuàng)建。
以下的設(shè)置和操作可能有一些繁瑣,但這是一勞永逸的事情。只要你完成了第一個空白工程,以后再需要創(chuàng)建工程時復(fù)制一份就可以了。
以下四個編譯配置并不要求都必須設(shè)置好,如果您不打算使用Unicode,那么不用設(shè)置"Win32 Unicode Debug"和"Win32 Unicode Release",如果您僅僅想調(diào)試程序而非發(fā)布,則只需設(shè)置相應(yīng)的"Debug"不用設(shè)置"Release"。最簡單的情況下,只需設(shè)置"Win32 Debug"。
還有一點要注意,您需要事先編譯出相應(yīng)版本的 wxWidgets 庫文件。如"Win32 Unicode Debug"需要
Unicode+Debug 版本的 wxWidgets 庫。(wxWidgets 各種版本庫均可通過
點擊菜單:Project -> Settings... 打開項目屬性設(shè)置對話框。
C/C++ General:
Preprocessor definitions: WIN32,_DEBUG,__WXMSW__,__WXDEBUG__,_MBCS,_WINDOWS,NOPCH
C/C++ Code Generation:
Use run-time library: Debug Multithreaded DLL
Link General:
Object/library modules: wxmsw26d_xrc.lib wxmsw26d_html.lib wxmsw26d_adv.lib wxmsw26d_core.lib wxbase26d_xml.lib wxbase26d.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib wxregexd.lib wxexpatd.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib wsock32.lib odbc32.lib
C/C++ General:
Preprocessor definitions: WIN32,NDEBUG,__WXMSW__,_MBCS,_WINDOWS,NOPCH
C/C++ Code Generation:
Use run-time library: Multithreaded DLL
Link General:
Object/library modules: wxmsw26_xrc.lib wxmsw26_html.lib wxmsw26_adv.lib wxmsw26_core.lib wxbase26_xml.lib wxbase26.lib wxtiff.lib wxjpeg.lib wxpng.lib wxzlib.lib wxregex.lib wxexpat.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib wsock32.lib odbc32.lib
進(jìn)行以下操作之前,請先通過菜單 Build -> Configurations... 增加兩個編譯配置"Win32 Unicode Debug"和"Win32 Unicode Release"(分別復(fù)制于"Win32 Debug"和"Win32 Release")。
C/C++ General:
Preprocessor definitions: WIN32,_DEBUG,__WXMSW__,__WXDEBUG__,_UNICODE,_WINDOWS,NOPCH
C/C++ Code Generation:
Use run-time library: Debug Multithreaded DLL
Link General:
Object/library modules: wxmsw26ud_xrc.lib wxmsw26ud_html.lib wxmsw26ud_adv.lib wxmsw26ud_core.lib wxbase26ud_xml.lib wxbase26ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib wxregexud.lib wxexpatd.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib wsock32.lib odbc32.lib
C/C++ General:
Preprocessor definitions: WIN32,NDEBUG,__WXMSW__,_UNICODE,_WINDOWS,NOPCH
C/C++ Code Generation:
Use run-time library: Multithreaded DLL
Link General:
Object/library modules: wxmsw26u_xrc.lib wxmsw26u_html.lib wxmsw26u_adv.lib wxmsw26u_core.lib wxbase26u_xml.lib wxbase26u.lib wxtiff.lib wxjpeg.lib wxpng.lib wxzlib.lib wxregexu.lib wxexpat.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib wsock32.lib odbc32.lib
在前面的設(shè)置中,指定了wxWidgets的庫文件(*.lib),但VC可能并不知道到哪個目錄去尋找這些文件。同時,我們的源代碼中也要包含 (include)wxWidgets的頭文件,其頭文件所在目錄也需要指定。另外,為了更好的調(diào)試wx程序,最好把wxWidgets的源代碼所在目錄 也設(shè)置好。
點擊菜單 Tools -> Options...,進(jìn)入 Directories 頁,分別加入以下路徑(下面的
Include files:
\include
\include\msvc Library files:
\lib\vc_lib Source files:
\src
這一設(shè)置是針對VC全局的,以后再用VC創(chuàng)建wxWigets程序,就不用設(shè)置這些路徑了。
各個編譯器不同,有的支持預(yù)編譯頭文件,有的不支持,支持預(yù)編譯頭文件的,使用的語法也有所不同,如果在每個源文件中都重復(fù)的寫未免不爽,還是集中到一個頭文件中來比較好。但是注意,有了此文件并不決定或限制你使用還是不使用預(yù)編譯頭文件,用不用以及怎么用還是在你。
點擊菜單 File -> New...,新建一個C/C++頭文件 wx_pch.h,其內(nèi)容如下:
#ifndef WX_PCH_H_INCLUDED #define WX_PCH_H_INCLUDED #if ( defined(USE_PCH) && !defined(WX_PRECOMP ) ) #define WX_PRECOMP #endif // USE_PCH // basic wxWidgets headers #include <wx/wxprec.h> // for use xrc files #include <wx/xrc/xmlres.h> #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include <wx/wx.h> #endif #ifdef USE_PCH // put here all your rarely-changing header files #endif // USE_PCH #endif // WX_PCH_H_INCLUDED |
wxWidgets官方文檔是大概也是這樣推薦,Code::Blocks中基本上就是這樣子,我只是簡單的增加了一行"#include
以后,工程中的源文件,只要包含(include) wx_pch.h 文件就可以了。
點擊菜單 Insert -> New Class...,新建一個名稱為"App"的類(類名稱可以隨意),考慮到代碼的跨平臺性,建議將其所在文件的名稱修改為全部使用小寫字母(如 app.h/app.cpp)。此操作將生成文件 app.h 和 app.cpp。
VC在這里生成的類代碼顯然是不滿足我們的要求的,需要進(jìn)行以下修改:
app.h
增加預(yù)編譯頭文件 wx_pch.h 的包含(以后創(chuàng)建的每個.h文件都要包含它):#include "wx_pch.h"
指定App類的父類為wxApp:即將"class App"修改為"class App : public wxApp"
為類增加虛方法OnInit()的聲明:virtual bool OnInit();
在類聲明的下方增加 wxWidgets App 聲明:DECLARE_APP(App)
最終 app.h 的內(nèi)容如下(其中經(jīng)過手工改寫的地方已用黃色背景突出顯示):
// by: liigo.com
#if !defined( AFX_APP_H__B4514AF3_2125_487B_BD66_AF638A80E73A__INCLUDED_)
#define AFX_APP_H__B4514AF3_2125_487B_BD66_AF638A80E73A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "wx_pch.h"
class App : public wxApp
{
public :
App();
virtual ~App();
virtual bool OnInit ();
};
DECLARE_APP(App )
#endif // !defined(AFX_APP_H__B4514AF3_2125_487B_BD66_AF638A80E73A__INCLUDED_)
app.cpp
增加頭文件包含(此頭文件將在下面創(chuàng)建MainFrame類時創(chuàng)建):#include "mainframe.h"
增加 OnInit() 方法的定義(其中用到的MainFrame類定義于mainframe.h,見后文):
bool App::OnInit()
{
MainFrame* mainFrame = new MainFrame(NULL, _("MainFrame by liigo.com"));
mainFrame->Show ();
SetTopWindow(mainFrame);
return true;
}在類定義的上方增加 wxWidgets App 定義:IMPLEMENT_APP(App)
最終 app.cpp 的內(nèi)容如下(其中經(jīng)過手工改寫的地方已用黃色背景突出顯示):
#include "app.h"
IMPLEMENT_APP (App)
App:: App()
{
}
App::~App()
{
}
bool App::OnInit()
{
MainFrame* mainFrame = new MainFrame(NULL, _("MainFrame by liigo.com"));
mainFrame-> Show();
SetTopWindow(mainFrame);
return true;
}
點擊菜單 Insert -> New Class...,新建一個名稱為"MainFrame"的類(類名稱可以隨意),考慮到代碼的跨平臺性,建議將其所在文件的名稱修改為全部使用小寫字母 (如 mainframe.h/mainframe.cpp)。此操作將生成文件 mainframe.h 和 mainframe.cpp。
下面對VC生成的類代碼進(jìn)行相應(yīng)的修改:
mainframe.h
增加預(yù)編譯頭文件的包含:#include "wx_pch.h"
指定MainFrane類的父類為wxFrame:class MainFrame : public wxFrame
修改構(gòu)造函數(shù)的聲明:MainFrame(wxWindow* parent, const wxString& title);
在類定義的末尾增加事件表聲明:DECLARE_EVENT_TABLE()
最終 mainframe.h 的內(nèi)容如下(其中經(jīng)過手工改寫的地方已用黃色背景突出顯示):
#if !defined(AFX_MAINFRAME_H__1BC90331_B69E_40F2_BDF7_197550D70F07__INCLUDED_ )
#define AFX_MAINFRAME_H__1BC90331_B69E_40F2_BDF7_197550D70F07__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "wx_pch.h"
class MainFrame : public wxFrame
{
public:
MainFrame( wxWindow* parent, const wxString & title);
virtual ~MainFrame();
DECLARE_EVENT_TABLE()
};
#endif // !defined(AFX_MAINFRAME_H__1BC90331_B69E_40F2_BDF7_197550D70F07__INCLUDED_)
mainframe.cpp
修改構(gòu)造函數(shù)的定義:
MainFrame::MainFrame(wxWindow* parent, const wxString& title) : wxFrame(parent, wxID_ANY, title)
{
//wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, _("some text"));
}增加事件表定義(BEGIN_EVENT_TABLE 與 END_EVENT_TABLE 之間保留空白,留待以后綁定事件):
BEGIN_EVENT_TABLE(MainFrame, wxFrame)
END_EVENT_TABLE()最終 mainframe.cpp 的內(nèi)容如下(其中經(jīng)過手工改寫的地方已用黃色背景突出顯示):
#include "mainframe.h"
BEGIN_EVENT_TABLE (MainFrame, wxFrame)
END_EVENT_TABLE()
MainFrame::MainFrame( wxWindow* parent, const wxString& title) : wxFrame (parent, wxID_ANY, title)
{
//wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, _("some text"));
}
MainFrame ::~MainFrame()
{
}
至此,一個wxWidget的空白Project已經(jīng)創(chuàng)建完畢
編譯生成的 exe 文件的大小:
可執(zhí)行文件大小 | Debug | Release |
Unicode | 3.78M | 956K |
非Unicode | 3.60M | 932K |
此數(shù)據(jù)全部是靜態(tài)鏈接wxWidgets的結(jié)果。動態(tài)鏈接的話,EXE的大小沒有意義——別忘了wxWidgets的版DLLs的大小總共約4到5M(Release版)。
向 wxFrame 或 wxDialog 中添加子控件是比較容易的,只需在其子類的構(gòu)造函數(shù)中 new 相應(yīng)的子控件就可以了。
這是最簡單的情況:
MainFrame::MainFrame(wxWindow* parent, const wxString& title) : wxFrame(parent, wxID_ANY, title) { wxTextCtrl * text = new wxTextCtrl( this, wxID_ANY, _("some text")); } |
沒錯,只要"new"一下就搞定了,控件會自動出現(xiàn)在wxFrame中。這是運行結(jié)果:
如果界面再復(fù)雜一些,上面這種方法就行不通了,我們需要引入"Sizer"(詳見http://www.wxwidgets.org/manuals/2.6.3/wx_sizeroverview.html(Sizer一覽)):
MainFrame::MainFrame(wxWindow* parent, const wxString& title) : wxFrame(parent, wxID_ANY, title) { wxTextCtrl * textCtrl = new wxTextCtrl( this, ID_TEXTCTRL, _T("some text"), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); wxButton * button = new wxButton(this , ID_BUTTON, _("測試按鈕"), wxDefaultPosition , wxDefaultSize, 0 ); wxBoxSizer* vBoxSizer = new wxBoxSizer(wxVERTICAL); this ->SetSizer(vBoxSizer); vBoxSizer->Add (textCtrl, 1, wxALL|wxEXPAND, 5); vBoxSizer->Add(button, 0 , wxALIGN_CENTER_HORIZONTAL|wxALL|wxALIGN_BOTTOM, 5); } |
上面是多行編輯框控件,下面是按鈕控件,當(dāng)窗口大小變化時,編輯框控件將在水平和垂直方向上自動擴(kuò)展,而按鈕始終位于窗口底部居中。
上述代碼中涉及的控件ID(ID_TEXTCTRL,ID_BUTTON)是我們在 mainframe.cpp 中自行定義的(定義控件ID的目的是為了下一步了事件處理):
enum CtrlID { ID_TEXTCTRL, ID_BUTTON }; |
參考文檔:http://www.wxwidgets.org/manuals/2.6.3/wx_sizeroverview.html(Sizer一覽)
采用XML格式文件(XRC文件)定義程序界面也是不錯的方式,詳見:http://www.wxwidgets.org/manuals/2.6.3/wx_xrcoverview.html(基于XML的資源系統(tǒng)一覽)。
無論如何,手工進(jìn)行界面布局總是很繁雜,我們需要(可視化)工具的幫助:http://www.wxwidgets.org/apps2.htm
在wxWidgets中處理事件,主要有兩個步驟:編寫"事件處理函數(shù)(方法)",填寫"事件表(EVENT_TABLE)"。
事件處理函數(shù)(方法)視事件的不同而有所不同,但也有規(guī)律:沒有返回值,只有一個引用型參數(shù)(且一定是wxEvent的子類),不是虛方法(virtual method)。事件處理函數(shù)(方法)的名稱沒有特殊規(guī)定,可以自行命名。
作為示例,我們來處理上圖中"測試按鈕"被按下的事件。
根據(jù)wxWidgets文檔,要處理按鈕事件,需在自己的類中添加如下事件處理函數(shù)(方法):void MainFrame::OnButtonClick (wxCommandEvent &event)
具體說來就是,在 mainframe.h 文件中的 MainFrame 類中增加新的 OnButtonClick() 方法聲明:
private: void OnButtonClick( wxCommandEvent& event); |
并在 mainframe.cpp 文件中增加 OnButtonClick() 方法的定義:
void MainFrame::OnButtonClick( wxCommandEvent &event) { //取編輯框中的文本并用信息框顯示出來 wxString text = ((wxTextCtrl*)this-> FindWindow(ID_TEXTCTRL))->GetValue(); wxMessageBox (text); } |
下面需要在 mainframe.cpp 中填寫"事件表(EVENT_TABLE)",以便我們的"事件處理函數(shù)(方法)"能在適當(dāng)?shù)臅r機(即事件觸發(fā)時)被調(diào)用:
BEGIN_EVENT_TABLE(MainFrame, wxFrame ) EVT_BUTTON(ID_BUTTON, MainFrame ::OnButtonClick) END_EVENT_TABLE() |
在這個事件表中,我們使用宏 EVT_BUTTON 指定了按鈕的ID,以及"事件處理函數(shù)(方法)"。
注:上面一直講"事件處理函數(shù)(方法)",其實是"方法(method)"不是"函數(shù)(function)",只是"方法"這個詞在編程領(lǐng)域和在日 常生活中可以有不同的理解("方法"也可以理解為"方式"),我如果說成"事件處理方法",難免會產(chǎn)生歧義。當(dāng)然,"事件處理函數(shù)(方法)"似乎也并不十 分合適,應(yīng)稱為"事件處理'方法'"或"事件處理方法(method)"?再深究下去就有咬文嚼字的嫌疑了,聰明的讀者早已明白我的意思了吧?
如何處理其它事件?
說白了,關(guān)鍵要知道兩點:事件處理函數(shù)(方法)的參數(shù)是什么類型,填寫參數(shù)表時用哪一個宏(EVT_*)。
再補充一點:要知道"什么控件"在"什么時機"會觸發(fā)"什么事件"。
要知道這些,就需要對wxWidgets的事件處理有一個比較全面的了解。
建議看一下wxWidgets官方文檔中的這篇文章:http://www.wxwidgets.org/manuals/2.6.3/wx_eventhandlingoverview.html(事件處理一覽)
尤其是其中的 Event macros summary(事件宏概要)一段。
電子書《Cross-Platform GUI Programming with wxWidgets》附錄9(Appendix I, 617頁)中對事件處理時所涉及的事件類型(wxXXXEvent)和事件宏(EVT_*)有比較好的總結(jié),建議看一下,最好打印出來放在手邊,以便隨時參考。
本文所涉及的完整源代碼可在此下載:http://liigo.diy.myrice.com/article/wxProject/wxProject.zip
了解 Sizer,熟悉界面設(shè)計:http://www.wxwidgets.org/manuals/2.6.3/wx_sizeroverview.html
了解 事件處理:http://www.wxwidgets.org/manuals/2.6.3/wx_eventhandlingoverview.html
了解 wxWidgets 提供了哪些控件,它們各自的屬性、方法、事件,以及它們的用法。
去 wxWidgets.org 上找第三方的控件/庫:http://www.wxwidgets.org/contrib2.htm#classes
去 wxWiki 上找第三方的控件/庫:http://www.wxwidgets.org/wiki/index.php/Table_Of_Contents#Pages_about_classes.2C_functions_or_macros
GUI庫嘛?無非就是控件(component)的使用:布局、操作、事件處理。
2008年10月29日 #
2008年10月27日 #
2008年7月17日 #
2008年7月15日 #
2008年7月14日 #
2008年6月3日 #
wxbase28.lib wxbase28d.lib wxbase28_net.lib wxbase28d_net.lib wxbase28_xml.lib wxbase28d_xml.lib wxmsw28_core.lib wxmsw28d_core.lib wxmsw28_html.lib wxmsw28d_html.lib wxmsw28_adv.lib wxmsw28d_adv.lib
在vc中設(shè)置lib,可以把該目錄加入,也可以直接把生成的文件丟在vc的lib目錄。
關(guān)于unicode模式編輯如上。
在include設(shè)置中,需要加入wxWidgets目錄中的include目錄。
運行demo程序測試.
注意:在include也需要把setup.h頭文件加入。該頭也根據(jù)生成的lib目錄中調(diào)用。
不過最好加在預(yù)處理的include directory目錄編輯框中。
2008年5月8日 #
2008年4月29日 #
1.正則表達(dá)式筆記
必須記住的幾個符號和組合
. 匹配除換行符以外的所有字符一次
? 匹配 0 次或一次
* 匹配 0 次或多次
+ 匹配 1 次或多次
使用范例:
x? 匹配 0 次或一次 x 字符串界定范圍和位置
^ 匹配字符開頭的字符
$ 匹配字符結(jié)尾的字符
{m} 匹配剛好是 m 個 的指定字符串
{m,n} 匹配在 m個 以上 n個 以下 的指定字符串
{m,} 匹配 m個 以上 的指定字符串
[] 匹配符合 [] 內(nèi)的字符
[^] 匹配不符合 [] 內(nèi)的字符
[0-9] 匹配所有數(shù)字字符
[a-z] 匹配所有小寫字母字符
[^0-9] 匹配所有非數(shù)字字符
[^a-z] 匹配所有非小寫字母字符
\b 匹配以英文字母,數(shù)字為邊界的字符串
\d 匹配一個數(shù)字的字符,和 [0-9] 語法一樣
\w 英文字母或數(shù)字的字符串,和 [a-zA-Z0-9] 語法一樣
\s 空格,和 [\n\t\r\f] 語法一樣
\B 匹配不以英文字母,數(shù)值為邊界的字符串
\D 非數(shù)字,其他同 \d
\S 非空格,和 [^\n\t\r\f] 語法一樣
\W 非英文字母或數(shù)字的字符串,和 [^a-zA-Z0-9] 語法一樣
a|b|c 匹配符合a字符 或是b字符 或是c字符 的字符串
abc 匹配含有 abc 的字符串
轉(zhuǎn)義: 使用\ 來取消元字符的特殊意義。包括 . * + \ [ ] { } ( ) ^ $
?的多重定義-懶惰限定符
*? 重復(fù)任意次,但盡可能少重復(fù)
+? 重復(fù)1次或更多次,但盡可能少重復(fù)
?? 重復(fù)0次或1次,但盡可能少重復(fù)
{n,m}? 重復(fù)n到m次,但盡可能少重復(fù)
{n,}? 重復(fù)n次以上,但盡可能少重復(fù)
斷言匹配: 有4個
(?=exp) 零寬先行斷言,它匹配文本中的某些位置,這些位置的后面能匹配給定的后綴exp。
比如/b/w+(?=ing/b),匹配以ing結(jié)尾的單詞的前面部分(除了ing以外的部分),
zc:根據(jù)后綴匹配而已。和$區(qū)別在于$是行尾匹配。
如I'm singing while you're dancing. 它會匹配sing和danc。
(?<=exp) 零寬后行斷言,它匹配文本中的某些位置,這些位置的前面能給定的前綴匹配exp。
如(?<=\bre)\w+\b會匹配以re開頭的單詞的后半部分(除了re以外的部分),
zc:匹配前綴。
例如在查找reading a book時,它匹配ading。
(?!exp) 零寬負(fù)向先行斷言。會匹配后綴exp不存在的位置。
zc: 若不是exp或者沒有則匹配,用^在于存在一個不匹配某個exp的其他字符,而!保證不匹配exp外可以不跟任何字符。
如:\d{3}(?!\d)匹配三位數(shù)字,而且這三位數(shù)字的后面不能是數(shù)字。 也可以是只有前3位數(shù)字。比較\d{3}(^\d)有區(qū)別.
(?<!exp) 零寬負(fù)向后行斷言。查找前綴exp不存在的位置.
條件匹配: (zc:這個復(fù)雜,但也不復(fù)雜。屬于perl中的擴(kuò)展部分,略)
Conditional Expressions
(?(condition)yes-pattern|no-pattern)
attempts to match yes-pattern if the condition is true, otherwise attempts to match no-pattern.
(?(condition)yes-pattern) attempts to match yes-pattern if the condition is true, otherwise fails.
condition may be either a forward lookahead assert, or the index of a marked sub-expression
(the condition becomes true if the sub-expression has been matched).
2. boost中分有match,search,replace,在vc中,其正則表達(dá)式以上\表示需要雙反斜杠表示。其中在
match是匹配整個句子,在實際應(yīng)用中,必須是構(gòu)造整個句子的正則表達(dá),而在一篇文章匹配的話,以search用的
比較多,如下見一個片段。沒有用到std,可見用boost在匹配查詢時,其比較麻煩:
void test123()
{
CString str = "singing while youre dancing.";
regex ee_all("\\b\\w+\\b");
cmatch result;
CString ret;
while(regex_search(str, result, ee_all,match_perl)){
for(int i=0; i < result.size(); i++){
ret = result[i].str().c_str();
AfxMessageBox(ret);
str = result[i].second;
}
}
}
2008年4月23日 #
2008年4月22日 #
1.這里下載boots,http://downloads.sourceforge.net,我下載的是boost_1_35_0.zip,鏈接如下:
http://downloads.sourceforge.net/boost/boost_1_35_0.zip?modtime=1206795434&big_mirror=0
2.解壓后打開目錄
\boost_1_35_0\boost_1_35_0\libs\regex\build編譯vc6下版本vc6.mak文件,具體如下:
a。打開dos環(huán)境,把vc6目錄中的Microsoft Visual Studio\VC98\Bin下的VCVARS32.BAT拖入dos窗做環(huán)境設(shè)置。
b。運行namke -f vc6.mak。
c。把生成的dll和lib放在自己的目錄中,最好在vc6的vc98下建一個目錄,畢竟是vc6下的編譯碼。然后在vc6中設(shè)置包含lib file。
文件include包含目錄 boost_1_35_0\boost_1_35_0\boost_1_35_0
3.測試,粘貼到vc中直接編譯。
如果編譯出現(xiàn)minimal builder不支持的話,則去掉set中的minimal builder勾選。
還有若出現(xiàn)類似fatal error C1001: INTERNAL COMPILER ERROR錯誤的話,則采用rebuilder來重建,一般是可以通過。
為啥為什么出現(xiàn)這個內(nèi)部編譯錯誤,倒不清楚。不過,不影響vc下的正則處理使用暫時不管了。
#include "stdafx.h"
#include <boost/regex.hpp>
#include <string>
#include <iostream>
using namespace std;
using namespace boost;
regex ee("a+b");
int main()
{
string str = "aaaaaaab";
if(regex_match(str.c_str(), ee))
{
cout<<"match ok"<<endl;
}
getchar();
return 0;
}
備注原文:http://dotnet.csdn.net/page/66e7a1c1-981e-4609-93fc-a3c34a6a5308
2008年4月21日 #
其實,插件不過就是調(diào)用dll中的函數(shù)而已,不過通過類似一個com中的接口,再通過接口查詢到相應(yīng)的服務(wù)來處理。
復(fù)雜的插件,當(dāng)然有考慮采用com方式的,不過作為編寫程序的原則是簡單,實效,通用。又何須采用太過專業(yè)的方法。
技術(shù)不過是手段,能在達(dá)到目的的最大化程度上實現(xiàn),就足矣。
下面的例子來自網(wǎng)上,作者不詳,稍微整編下。直接貼代碼在上面。源碼打包放在自己博客的文檔中。算是自己學(xué)習(xí)整理,
也感謝提供者。
源碼學(xué)習(xí):http://m.shnenglu.com/Files/kenlistian/test_plus.rar
1.定義插件的接口結(jié)構(gòu)
/*
定義一個plus 接口結(jié)構(gòu)
*/
typedef struct PlugInModule{
DWORD Ver ; //版本
char *Author ; //作者說明
char *Description; //模塊說明
BYTE *InputPointer; //輸入數(shù)據(jù)
DWORD dwSize ; //輸入數(shù)據(jù)的大小
HWND hParentWnd ; //主程序的父窗口
HINSTANCE hDllInst ; //Dll句柄
void (*PlugIn_Config)( struct PlugInModule * pModule ); //設(shè)置函數(shù)
void (*PlugIn_Init)( struct PlugInModule * pModule ); //初始化函數(shù)
void (*PlugIn_Quit)( struct PlugInModule * pModule ); //退出函數(shù)
void (*PlugIn_Run )( struct PlugInModule * pModule ); //執(zhí)行函數(shù)
} PlugInModule;
其中接口結(jié)構(gòu)函數(shù),被規(guī)定了4個,也就是說這個接口函數(shù)定死了,如果以后應(yīng)為功能增加等等,
則估計這個結(jié)構(gòu)都要改寫。所以采用com方式接口方式則是一種好的選擇,而那種模式,每次還要注冊com,
則莫免麻煩和釘死在windows平臺上。
2.以上接口結(jié)構(gòu)放置在頭文件中。作為主程序和dll共享的頭文件,其中,再在頭文件中具體聲明以上結(jié)構(gòu)體中函數(shù)。
void plusDll_Config( struct PlugInModule * pModule); //設(shè)置函數(shù)
void PlusDll_Init( struct PlugInModule * pModule ); //初始化函數(shù)
void plusDll_Quit( struct PlugInModule * pModule ); //退出函數(shù)
void plusDll_Run( struct PlugInModule * pModule ); //執(zhí)行函數(shù)
3.在頭文件中聲明一個返回該結(jié)構(gòu)的函數(shù)。其實就是一個回調(diào)函數(shù)。把該結(jié)構(gòu)返回給主程序的一個export 函數(shù)。
typedef PlugInModule* (*GETPLUGINMODULE)(); //聲明接口函數(shù)地址
/**
導(dǎo)出函數(shù),主程序首先獲取該接口函數(shù),獲得 dll中的函數(shù)地址,調(diào)用
*/
DLL_001_API PlugInModule* GetPlugInModuleFunction(); //DLL_001_API ==> __declspec(dllexport)
4.在dll中定義該插件結(jié)構(gòu),把地址通過GetPlugInModuleFunction傳入到主程序。
5.分別實現(xiàn)dll中和主程序的定義部分。通過動態(tài)加載方式即可實現(xiàn)取出dll的結(jié)構(gòu)體指針。
如下示:
hDLL = LoadLibrary("dll_001\\debug\\dll_001.dll");
if (hDLL)
MessageBox(NULL,"plus_Dll load ok", "", MB_OK);
else
{
MessageBox(NULL, "not found plus_dll","",MB_OK);
return 0;
}
pFunction = (GETPLUGINMODULE)::GetProcAddress(hDLL,"GetPlugInModuleFunction");
if (pFunction != NULL)
{
dllplus_module = (*pFunction)();
dllplus_module->PlugIn_Init(dllplus_module);
dllplus_module->PlugIn_Run(dllplus_module);
dllplus_module->PlugIn_Quit(dllplus_module);
}
::FreeLibrary(hDLL);//卸載MyDll.dll文件;
好長時間沒更新了,主要這段時間忙學(xué)ruby。沒多少時間溫故一下c++及其細(xì)節(jié)。對于編程為生涯的人生中,其c/c++是一把好的工具,但是在長年累月編寫代碼中,更加明白的編程的思想才是靈魂,沒有思想的編程,也不過如同拿把寶劍而無所作為。就是再精通c++也不過是稱之為某語言專家。而對于使用工具的人來說,不僅是要善于運用工具,而且更應(yīng)該是發(fā)揮工具去實現(xiàn)你的要求。
但很多人在對待c/c++時,太多的時候,如同時常撫摸自己手中寶劍而忘卻了要去面對的項目。
我時常以CS游戲中的武器向同事和朋友來比喻,c如同CS中的阻擊步槍,而C++如同Ak47,而java,c#如同制式武器中的m41突擊步槍,這些都是在編程世界中的主力廝殺武器,我們可以選擇C可以瞄準(zhǔn)任何項目,也能性能極高的射中項目的要害,但是持C之人,所積累的經(jīng)驗,所對項目的開發(fā)時間緩急,都在一定程度上影響了采用c的要求,C++和AK47有點類似,狂暴有效,但不是一般人能夠在項目開發(fā)中始終保持開發(fā)的速度和效率,在CS中AK47,頭三槍效率極高,但如在編程世界中項目的大量和迫近時,往往和CS中AK47中子彈都飛散到敵手周圍一樣變得雜亂低效。所以一般而言,采用制式武器中的java,C#是作為現(xiàn)代工業(yè)編程的主要制式武器,精確有效,彈量充足。
也許,選擇以上制式武器也都是一種個人愛好和企業(yè)的側(cè)重,但是再怎么著,也必須在裝備了一主力武器外還得配備近戰(zhàn)的武器,和朋友說起,你得像cs中配了主力武器外,還得配把近戰(zhàn)手槍,以備各種要求。如同CS中持槍盤斗到最后,也得抽出短槍盤環(huán)近斗,這也類似在項目吃緊時,臨時有額外的要求時,用制式工具也許來不及或者不值得花大工夫去處理時,用用那些膠水語言(動態(tài)語言)則是非常省力和高效率的。也就是說膠水語言就如同近戰(zhàn)手槍,簡單有效實用。
談到動態(tài)語言,有太多,其實熟悉和能運營一,二門即可,如老牌的perl,稱之為千年老妖的python,新興的殺手工具ruby,簡單平淡的vb or javascript,還有那些我從來沒用過的的lua,lisp,schema等,會這些,不能自以為是的又以為精通了一門語言來比較c/c++的優(yōu)劣,但也不能以c/c++ 性能優(yōu)異理由而拒絕學(xué)習(xí)其他的理由。只是方便我們達(dá)到我們的目的。
2008年3月5日 #
補:沒辦法;俺的cnit的博客發(fā)布不上去,就發(fā)在俺的cpp博客吧。
由于工作緣故,需要處理一接口發(fā)送來的xml串,對方采用java以字節(jié)流模式post一個xml串,
在asp中采用request估計把它加載到xml解析器中應(yīng)該報無法解析。
采用Request.binaryRead 即可解決,但是要注意幾個細(xì)節(jié)方面。
一一到來。
1. 讀取字節(jié)流
Dim vtBody
iReceive = Request.TotalBytes
vtBody = Request.BinaryRead(iReceive)
2. 轉(zhuǎn)換字節(jié)流為字符串,有以下幾個函數(shù)可以任選。
' a。byte --> str ,該轉(zhuǎn)換只適用小數(shù)據(jù),但是所有ie沒有問題,,,
Function bytes2BSTR(vIn)
strReturn = ""
For i = 1 To LenB(vIn)
ThisCharCode = AscB(MidB(vIn,i,1))
If ThisCharCode < &H80 Then
strReturn = strReturn & Chr(ThisCharCode)
Else
NextCharCode = AscB(MidB(vIn,i+1,1))
strReturn = strReturn & Chr(CLng(ThisCharCode) * &H100 + CInt(NextCharCode))
i = i + 1
End If
Next
bytes2BSTR = strReturn
End Function
'b。采用 ado record來轉(zhuǎn)換,該轉(zhuǎn)換速度快,轉(zhuǎn)換數(shù)據(jù)大,據(jù)說對ie5支持不夠好,
function rsbinarytostring(xbinary)
Dim binary
If vartype(xbinary)= 8 then
binary = multibytetobinary(xbinary)
Else
binary = xbinary
End If
Dim rs, lbinary
const adlongvarchar = 201
Set rs = createobject("adodb.recordset")
lbinary = lenb(binary)
If lbinary>0 Then
rs.fields.append "mbinary", adlongvarchar, lbinary
rs.open
rs.addnew
rs("mbinary").appendchunk binary
rs.update
rsbinarytostring = rs("mbinary").Value
rs.Close
Else
rsbinarytostring = ""
end if
End Function
'***************************************************
'c。采用流解析字符串,該轉(zhuǎn)換速度快,轉(zhuǎn)換數(shù)據(jù)大,據(jù)說對ie5支持不夠好,
function stream_binarytostring(binary, charset)
set binarystream = createobject("adodb.stream")
'讀入字節(jié)流
binarystream.type = 1
binarystream.open
binarystream.write binary
'內(nèi)部以字符方式返回
binarystream.position = 0
binarystream.type = 2
If len(charset) > 0 Then
binarystream.charset = charset
Else
binarystream.charset = "us-ascii"
End If
stream_binarytostring = binarystream.readtext
end function
則調(diào)用上面任一個進(jìn)行轉(zhuǎn)換即可。如:
strBody = stream_binarytostring(vtBody, "utf-8")
3. 將strBody解碼
如果調(diào)用Response.Write strBody ,則在ie上可以看到正常的xml結(jié)構(gòu)體部分。
但是如果你要是寫在文本中,你將會看到的是如下的樣式:
%3C%3Fxml+version+%3D+%221.0%22+encoding%3D%22UTF-8%22+%3F%3E%3CROOT%3E%3CUSER%3Egtzx%3C%2FUSER%3E%3CPASS%3Egtzx%3C%2FPASS%3E%3CMO%3E%3CMOID%3E291AC5FDBD0DF4EF2B2A2950FB730610%3C%2FMOID%3E%3CMSGFORMAT%3E15%3C%2FMSGFORMAT%3E%3CCLASSID%3Ehttp%3A%。。。。%3E%3CSERVICEID%3E1981%3C%2FSERVICEID%3E%3CCITYID%3E102%3C%2FCITYID%3E%3CPROVINCEID%3E16%3C%2FPROVINCEID%3E%3CMOUSEID%3E2%3C%2FMOUSEID%3E%3CSPNUMBER%3E10666066%3C%2FSPNUMBER%3E%3CLINKID%3E%3C%2FLINKID%3E%3CREMARK%3E%3C%2FREMARK%3E%3C%2FMO%3E%3C%2FROOT%3E
這表示是url 編碼方式,它把utf-8編碼進(jìn)行了再一次編碼,如果你要是xml解析器來解析的話,恐怕它是干不了活的。(也許有,但是asp中玩那個xmldocument實在是不想研究下去)
不過再需要做個urlDecode轉(zhuǎn)換,這個asp函數(shù),網(wǎng)上一大把,搜出一個,粘貼下來就可以去掉%并轉(zhuǎn)換utf-8格式。這里貼出一個修改的urlDecode函數(shù),
'*****************************************************
'功能描述:URL解碼碼函數(shù)
'輸入?yún)?shù):vURL編碼的字符串
'返回值:解碼后的字符串
Public Function URLDecoding(sIn)
Dim s,i,l,c,t,n : s="" : l=Len(sIn)
For i=1 To l
c=Mid(sIn,i,1)
If c<>"%" Then
s = s & c
Else
c=Mid(sIn,i+1,2) : i=i+2 : t=CInt("&H" & c)
If t<&H80 Then
s=s & Chr(t)
Else
c=Mid(sIn,i+1,3)
If Left(c,1)<>"%" Then
URLDecoding=s
Exit Function
Else
c=Right(c,2) : n=CInt("&H" & c)
t=t*256+n-65536
s = s & Chr(t) : i=i+3
End If
End If
End If
Next
s=Replace(s, "+"," ")
URLDecoding=s
End Function
4. 調(diào)用xml解析器,加載以上字符串,即可解決。
'***********************************************************
'解析xml文件
'***********************************************************
Dim xml
Set xml = Server.CreateObject ("msxml2.DOMDocument")
xml.Async = False
xml.Loadxml(strBody)
5.讀出xml中的節(jié)點,寫入文本或者寫入數(shù)據(jù)庫,ok。
總結(jié):
在asp中采用xmlhttp發(fā)送或者接收,是不考慮字節(jié)流模式發(fā)送的,直接調(diào)用xmlhttp中的send即可。管它是
按啥模式發(fā)送的,但是在其他語言編程中,比如java,c#,or vc中,有可能是按字節(jié)流方式發(fā)送出去的,那么,
如果想圖個方便,直接用asp寫個接口處理下,就要考慮下和其他程序處理的細(xì)節(jié)。
2008年2月18日 #
今天本來想偷個懶,直接拿demo的一個chat代碼做一個監(jiān)控服務(wù)程序。采用的是傳統(tǒng)的CSocket和CArchive方式處理序列化消息發(fā)送既可以了。
在做的途中,覺得搞一個線程處理讀一個list字符串,有字符串就調(diào)用CSocket繼承類,通過序列化方法發(fā)送出去就可以了。
結(jié)果修改運行后,卻本來想偷懶卻變出偷不了懶,在通過序列化方式發(fā)送老是報一個Sockcore.cpp中的566的ASSERT錯誤。
#ifdef _DEBUG
void CAsyncSocket::AssertValid() const
{
CObject::AssertValid();
ASSERT(m_hSocket == INVALID_SOCKET || CAsyncSocket::FromHandle(m_hSocket) != NULL);
}
仔細(xì)看這個ASSERT,就是報socket的問題。
程序反復(fù)看了看,也沒有查出問題。在google搜了搜,
http://topic.csdn.net/t/20020521/20/741527.html
http://topic.csdn.net/t/20020626/12/830990.html
從中有些啟發(fā),把send部分從線程中采用主線程發(fā)送,立馬解決問題。看來CSocket的繼承類是估計不支持在線程模式下運行。也有人說CSocket繼承類只能用于主線程,而不能在線程中,當(dāng)然,是否這樣,還需要確認(rèn)。不過,如果想寫線程下的socket類,最好還是從socket構(gòu)造吧,免得繞彎路。否則,調(diào)試來調(diào)試去,困惑在深深的MFC代碼內(nèi)核代碼中簡直是浪費時間。