02 5月 2009
C++ Builder / Delphi 深度歷險 電子書下載
17 7月 2008
Skype4Com in BCB範例 - 將Call In的使用者加入Conference中
以下有範例程式檔,供參考:
Unit1.h
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "SKYPE4COMLib_OCX.h"
#include <OleCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
public: // User declarations
long mConferenceId;
TSkype * mSkype;
__fastcall TForm1(TComponent* Owner);
void __fastcall OnCallStatus( TObject *Sender, ICall* pCall/*[in]*/, TCallStatus Status/*[in]*/);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
#include <vcl.h>
#include <iostream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "SKYPE4COMLib_OCX"
#pragma resource "*.dfm"
TForm1 *Form1;
using namespace std;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
mSkype = new TSkype(Owner);
mSkype->Attach(5,false);
// test if Skype is running, if not, start it;
if( !mSkype->Client->IsRunning )
mSkype->Client->Start(false,true);
// 1st parameter - start Skype in minimized state
// 2nd parameter - show splash screen
//註冊Skype4Com的CallStatus Event
mSkype->OnCallStatus = OnCallStatus;
}
// Call 一位使用者
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ICallPtr call = mSkype->PlaceCall(L"falldog7_test",L"",L"",L"");
}
// 當有使用者Call In進來,則自動接起電話
// 第一位使用者打入,記錄ConferenceId
// 其後打入的使用者,加入此Conference
void __fastcall TForm1::OnCallStatus( TObject *Sender, ICall* _call/*[in]*/, TCallStatus Status/*[in]*/)
{
if( Status == clsRinging ){
if( mConferenceId > 0 ){
_call->Join( mConferenceId );
_call->Answer();
}
else{
_call->Answer();
mConferenceId = _call->ConferenceId;
}
}
}
Skype4Com in BCB範例 - Call其他使用者
1. 使用Skype4Com的Function:PlaceCall
這個方法是Skype4Com現成的Function,但是同一時間Call Out的人數上限只有4人...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ICallPtr call = mSkype->PlaceCall( L"falldog7_test", L"falldog7_test2", L"", L"" );
}
2. 使用Skype4Com的Command模式
這個方法,就好像是使用Windows Message傳送Command的方式一樣,將要傳給Skype的指令儲存在一字串裡,再將此字串傳送給Skype4Com即可。這個方法就沒有人數的上限了!
因此在這個方法裡,可以將使用者的名稱接在Call指令的後面即可。詳細的官網說明。使用Skype4Com提供的Command[ID][Command][Reply][Block][Timeout],取得一個ICommand的物件,再將此Command送給Skype4Com即可。
- ID:Command的ID,可以自行指定
- Command:Command的內容,必須為wchar_t字串
- Reply:預期回傳的字串,預設為""
- Block:是否等待Skype完成此動作
- Timeout:Block的Timeout時間,單位為ms(豪秒),預設為30000
void __fastcall TForm1::Button2Click(TObject *Sender)
{
WideString call_user_list = L"Call falldog7_test, falldog7_test2";
ICommandPtr cmd = mSkype->Command[1][ call_user_list.c_bstr() ][L""][true][5000];
mSkype->SendCommand(cmd);
}
18 4月 2008
[BCB] 升級indy9的元件後 compile後link產生的問題
[Linker Fatal Error] Fatal: Unable to open file 'INDY.BPI'
因為安裝了INDY9.0元件以後,indy.bpi變成了indy60.bpi
兩種方法可以解決:
- 修改預設值,改一遍即可
Project->Option->Packages裡面的Runtime packages,找到indy刪除就可以了(左下角的Default要打勾) - 如果之前已經存在的專案
可用文字編輯器打開*.bpr,搜尋裡面出現的indy.bpi,將它刪除即可
28 2月 2008
Skype4Com in BCB 的一些範例
比較需要注意的是,由於Skype4Com下載下來的壓縮檔裡面的說明檔Skype4Com.chm,裡面所說到的Class name, Function name都不能直接用,因為Skype4Com.dll已經透過BCB封裝過了,所以必須按照BCB編過後的方式去處理才行,封裝過後的檔案在$(BCB)/Imports/裡,有四個檔案,包括SKYPE4COMLib_OCX與SKYPE4COMLib_TLB的.cpp與.h檔。以下的範例有提到,請參考。
#include <vcl.h>範例檔下載連結
#include <iostream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "SKYPE4COMLib_OCX"
#pragma resource "*.dfm"
TForm1 *Form1;
using namespace std;
// 這個程式是用來測試Skype4Com的一些功能
// (1) 要執行這個程式 首先要將$(BCB)/Imports/加入 Include Path
// #include "SKYPE4COMLib_OCX.h"
// (2) 需要新增以下的元件:
// TListBox *ListBox1;
// TButton *Button1;
// TButton *Button2;
// TButton *Button3;
// TMemo *Memo1;
// (3) 需要額外宣告變數:
// TSkype * mSkype;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
mSkype = new TSkype(Owner);
mSkype->Attach(5,false);
// test if Skype is running, if not, start it;
if( !mSkype->Client->IsRunning )
mSkype->Client->Start(false,false);
// 1st parameter - start Skype in minimized state
// 2nd parameter - show splash screen
// Get the count of Friends
int count = mSkype->Friends->get_Count();
// Add Friend list to Memo
for( int i=1 ; i<count ; i++ )// start index from 1 !!!
this->ListBox1->Items->Add( mSkype->Friends->get_Item(i)->get_Handle() );
// 設置處理Skype Event的function
mSkype->OnCallStatus = OnCallStatus;
mSkype->OnMessageStatus = OnMessageStatus;
}
// @target :
// Create 一個Chat Object
// 並傳送訊息給 Friend "falldog7_test"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
IChatPtr chat;
chat = mSkype->CreateChatWith( L"falldog7_test" );
//開啟對話視窗
chat->OpenWindow();
//傳送訊息過去給falldog7_test
chat->SendMessage( L"Fuck You!" );
chat->Disband();
}
// @target :
// 撥電話給 好友 : "falldog7_test"
void __fastcall TForm1::Button2Click(TObject *Sender)
{
ICallPtr call = mSkype->PlaceCall(L"falldog7_test",L"",L"",L"");
}
// @target :
// 取出所有正在通話的 Call ,並將其所有的OutputDevice導至(1) Soundcard (2) File
void __fastcall TForm1::Button3Click(TObject *Sender)
{
wstring path = L"D:\\WorkRoom\\project-中文也行\\test.wav";
ICallCollectionPtr call_list = mSkype->ActiveCalls;
for( int i=1; i<=call_list->Count ; i++ ){
call_list->get_Item(i)->set_OutputDevice( callIoDeviceTypeSoundcard, L"default" );
call_list->get_Item(i)->set_OutputDevice( callIoDeviceTypeFile, const_cast<wchar_t*>(path.c_str()) );
this->Memo1->Lines->Add( "OutputDevice direct success!" );
}
}
// Skype4Com的Event
// 在Skype4Com.chm中定義的 Class : _SkypeEvents 裡面
// HRESULT CallStatus ([in] ICall *pCall,[in] TCallStatus Status)
// This event is caused by a change in call status.
// 經由BCB處理過後的header檔,定義在 $(BCB)/Imports/SKYPE4COMLib_OCX.h 88行
//
// @TCallStatus 的定義在Skype4Com.chm 與 SKYPE4COMLib_TLB.h中都找得到
// @target : 當有人Call我時(Ringing) 就直接接起此通Call
void __fastcall TForm1::OnCallStatus( TObject *Sender, ICall* _call/*[in]*/, TCallStatus Status/*[in]*/)
{
if( Status == clsRinging ){
// ShowMessage("A Call is Rining");
_call->Answer();
}
}
// Skype4Com的Event
// 在Skype4Com.chm中定義的 Class : _SkypeEvents 裡面
// HRESULT MessageStatus ([in] IChatMessage *pMessage,[in] TChatMessageStatus Status)
// This event is caused by a change in chat message status.
// 經由BCB處理過後的header檔,定義在 $(BCB)/Imports/SKYPE4COMLib_OCX.h 93行
//
// @TChatMessageStatus 的定義在Skype4Com.chm 與 SKYPE4COMLib_TLB.h中都找得到
// @target : 當有人傳訊息給我時,就在Memo1上印出訊息
void __fastcall TForm1::OnMessageStatus( TObject *Sender, IChatMessage* pMessage/*[in]*/, TChatMessageStatus Status/*[in]*/)
{
this->Memo1->Lines->Add( AnsiString("From : ")+ pMessage->FromHandle );
if( Status == cmsReceived ){
this->Memo1->Lines->Add( AnsiString("Msg : ")+ pMessage->Body );
}
}
31 1月 2008
Skype4Com in BCB
- 一種是廣為人知的透過Variant去控制Com的物件
- 另一種是使用BCB強大的功能,將Skype4Com.dll解析後,直接使用其中的class
法1 : 透過Variant去控制Com的物件
// Prepare Setp :
// 1. Add a Memo to the Form1
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Memo1->Clear();
//Create a Skype Com object
Variant oSkype;
oSkype = Variant::CreateObject("Skype4COM.Skype");
// test if Skype is running, if not, start it;
if( !oSkype.OlePropertyGet("Client").OlePropertyGet("IsRunning") )
oSkype.OlePropertyGet("Client").OleFunction("Start");
// Connect to Skype via API
oSkype.OleFunction("Attach");
// Get all firends
Variant friends = oSkype.OlePropertyGet("Friends");
int count = friends.OlePropertyGet( "Count" );
Memo1->Lines->Add( "User Count : "+IntToStr(count) );
// Add to Memo
for( int i=1 ; i<=count ; i++ )//start index from 1 !!!
Memo1->Lines->Add( friends.OlePropertyGet("Item", i).OlePropertyGet("Handle") );
}
//---------------------------------------------------------------------------
法2 :
- 下載Skype4Com Releas,解壓縮出Skype4Com.dll
- 打開BCB,點選Component -> Import ActiveX Control -> Add Skype4Com.dll -> Install
- 至元件列表中,點選「ActiveX」,看看有沒有出現「Skype」這個Icon,有的話,就是成功了
- 拉一個Skype元件下來,即可使用TSkype這個class了
- 切記:Skype4Com.dll的位置不能改變,否則BCB會出錯
// Prepare step :延伸閱讀:
// 1. Add a Skype to Form
// 2. Add a Memo to Form
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Skype = new TSkype(Owner);
Skype->Attach(5,false);
// test if Skype is running, if not, start it;
if( !Skype->Client->IsRunning )
Skype->Client->Start(false,false);
// 1st parameter - start Skype in minimized state
// 2nd parameter - show splash screen
// Get the count of Friends
int count = Skype->Friends->get_Count();
Memo1->Lines->Add( IntToStr(count) );
// Add Friend list to Memo
for( int i=1 ; i<count ; i++ )// start index from 1 !!!
Memo1->Lines->Add( Skype->Friends->get_Item(i)->get_Handle() );
}
//---------------------------------------------------------------------------
30 10月 2007
BCB Indy的元件 IdTCPClient的OnWork有問題
在使用時,出現了點問題。它的Event : OnWork,原本的意義應該要是Server端有資料傳進來時,TWorkMode的參數的值會是wmRead,當有資料要寫給Server時,wmRead的值會是wmWrite。但是,在使用時,當有資料要傳要寫時,這個Event都不會被觸發... 再拿它的sample code來看,它竟然是用Timer去判斷是否有資料要讀or寫... 這樣的話,用Event還有什麼意義,真搞不懂。
所以最後的替代方案,就是用以前的元件囉。TClientSocket,它有OnRead的Event可以用,比較方便。
06 10月 2007
BCB Override WndProc的兩種方法
1.
class TForm1 : public TForm
{
virtual void __fastcall WndProc(TMessage&);
//....
};
2.
/// Unit1.h兩種方法的差別在於,法一在程式開始執行時,收到系統Message時,就會跑進WndProc了;法二卻會先跑完TForm1()的Constructor後,才會開始處理系統送來的Message。
class TForm1 : public TForm
{
void __fastcall MyWindowProc(TMessage&);
//...
};
/// Unit1.cpp
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
this->WindowProc = this->MyWindowProc;
//...
}
05 10月 2007
BCB 更新Indy元件後 產生的問題
[C++ Error] winsock2.h(113): E2238 Multiple declaration for 'fd_set'
[C++ Error] winsock.h(55): E2344 Earlier declaration of 'fd_set'
[C++ Error] winsock2.h(116): E2146 Need an identifier to declare
[C++ Error] winsock2.h(157): E2238 Multiple declaration for 'timeval'
[C++ Error] winsock.h(98): E2344 Earlier declaration of 'timeval'
[C++ Error] winsock2.h(213): E2238 Multiple declaration for 'hostent'
....
後來google一下後,找到不少解法,但是只有一種解法能成功...
- 將 Winsock.h 改名爲Winsock1.h
- 將 Winsock2.h 拷貝一份並改名爲 WinSock.h
不過這個方法有個後遺症...當之後再使用Indy9.0的網路元件時,當有hpp裡面#include <winsock2.h>時,就得將它改成#include <winsock.h>才行
04 10月 2007
BCB取得網路連線的名稱
因為Netlimit IP Switcher的需求,所以必須找出「網路連線」的名稱,就是控制台下的網路連線的名稱...比如"區域連線"、"ADSL"...等等的。
原本以為用MIB_IFROW裡頭的data即可,可惜並不是這麼單純...後來終於找到方法了,IP_ADAPTER_INFO裡面記錄了所有Adapter的資訊(可由GetAdaptersInfo取得),裡頭的變數AdapterName即是Adapter的GUID,還不是名稱喔!要取得名稱的話,必須進入Register中查詢後,才能得知。在Register中的路徑是:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}以下是我的簡單測試code
(1) 首先要拉兩個元件...ListBox & Button
(2) #include <Iphlpapi.h> 為了呼叫GetAdaptersInfo
(3) #include <vcl/registry.hpp> 為了查詢Registry
#include <Iphlpapi.h>
#include <vcl/registry.hpp>
//...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
/*** 取得所有網路連線的名稱 ***/
//先透過GetAdaptersInfo取得Adapter的Name ... 此為GUID
//必須去Register取得真正的名稱
ULONG ulLen=4096;
BYTE *pbBuf=new BYTE[ulLen];
IP_ADAPTER_INFO * adp_info=NULL;
TRegistry * registry = new TRegistry();
registry->RootKey = HKEY_LOCAL_MACHINE;
if( ERROR_SUCCESS==GetAdaptersInfo((IP_ADAPTER_INFO*)pbBuf, &ulLen) )
{
adp_info = (IP_ADAPTER_INFO*)pbBuf;
do{
AnsiString key_path = "\\SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
+ AnsiString( adp_info->AdapterName )
+ "\\Connection";
if ( registry->OpenKeyReadOnly( key_path ) ){
if( registry->ValueExists("Name") ){
this->ListBox1->Items->Add( registry->ReadString("Name") );
}
}
registry->CloseKey();
adp_info = adp_info->Next;//point to next adapter!
}while(adp_info!=NULL);
}
delete pbBuf;
delete registry;
}
03 10月 2007
BCB TrayIcon元件 最小化至系統列 的基本應用三法
在BCB中,要將視窗程式要將程式最小化至系統匣中是很簡單的事,BCB提供了一個基本的元件提供使用...TrayIcon,只要用這個元件,就可以達到最小化至系統匣的目的了。TrayIcon的元件在Samples的分類底下。以下三種最小化的方法,供大家參考。
@ 按下縮下鍵就縮到系統列 @
拉入一個TrayIcon的元件, 將屬性Visible設true即可
@ 按關閉鍵時 縮入系統列 @
拉入一個TrayIcon的元件
Override WndProc
//Override的WndProc...
void __fastcall TForm1::WndProc(TMessage &Message){
if (Message.Msg == WM_CLOSE)
{
if (TrayIcon1->Visible == false)
{
TrayIcon1->Visible = true;
TrayIcon1->Minimize();
}
return;
}
WndProc(Message);
}
//再點選TrayIcon的EVENT Restore
void __fastcall TForm1::TrayIcon1Restore(TObject *Sender)
{
TrayIcon1->Visible = false;
}
@ 啟動時 就最小化在系統匣 @
1.在設計程式時,加入一個 TrayIcon 元件於主Form中,並將該元件屬性Visible設為true
2.在主 Form 的 OnActive 事件中寫入兩行程式碼:
Application->Minimize();
ShowWindow(Application->Handle, SW_HIDE);
在Windows上 修改本機端(local)的IP Address
由於最近架了個FTP,想在固定流量時,就更改IP,因此,東找西找,找到了可以修改IP的方法,在這邊供大家參考參考。
Windows提供了一個程式Netsh可以查看、修改IP, Gateway, Mask...等等的設定。因此我們就可以透過Netsh去修改本機端的IP Address。
測試的方法可以在Cmd.exe(命令提示字元)下,輸入netsh,會出現...
netsh >
netsh > interface ip
netsh interface ip > dump
這樣子就可以查看目前介面卡(interface)的IP設定是如何了...
設定IP有兩種格式:(1) DHCP (2) Static
(1) DHCP是浮動IP的設定方法
(2) static是固定IP的設定方法
假設我們今天要將IP改為固定IP:100.1.1.1,則我們可以在Cmd.exe底下輸入
C:\> netsh interface ip netsh interface ip > set address name="區域連線" source=static addr=100.1.1.1 mask=255.255.255.0
或是比較簡易的輸入
netsh interface ip > set address "區域連線" static 100.1.1.1 255.255.255.0
*記得一定要輸入mask的值 否則會出現錯誤訊息
假設我們今天要將IP改為浮動IP,則我們可以在Cmd.exe底下輸入
C:\> netsh interface ip netsh interface ip > set address "區域連線" dhcp
----
若是想寫程式直接執行,就可以修改IP的話,就將netsh後面那一串都當參數即可
在C/C++中的程式碼:
system("netsh interface ip set address \"區域連線\" static 100.1.1.1 255.255.255.0");
在BCB中的程式碼:
AnsiString param = "interface ip set address name=\"區域連線\" source=static addr=100.1.1.1 mask=255.255.255.0";
ShellExecute( Handle, "open", "netsh", param.c_str(), NULL, SW_HIDE );
27 9月 2007
[BCB] 無法new出新的TXMLDocument
BCB中有提供一個內建的物件TXMLDocument
它可以讀進一個xml檔,並建成一個完整的tree
讓user透過它對這個xml檔做操控
而這個物件可透過拖拉Tool bar 「Internet」中的XML圖檔至編輯器中
但是如果想新建的xml的文件一多該怎麼辦?
要read進100個xml檔 就該拉100個TXMLDocument至Form中嗎?!
那這樣就太可怕了....
一開始我以為可以自己寫一個TXMLDocument的pointer
再去new出一個TXMLDocument的物件出來就好了....
結果卻一直有問題...
一直出現不能create TXMLDocument的error!....
TXMLDocument * obj = new TXMLDocument("");
obj->LoadFromFile("user.xml");
後來找到這篇文章才知道
http://www.tinydust.net/prog/diary/2004/02/bcbtxmldocument.html
原來不能直接使用TXMLDocument
而要透過Delphi Interface的物件去create它才行
_di_IXMLDocument
_di_IXMLDocument doc = LoadXMLDocument("user.xml");
其他操作都跟TXMLDocument都一樣了