17 7月 2008

Skype4Com in BCB範例 - 將Call In的使用者加入Conference中

  在Skype中,當使用者目前有一個通話正在進行,而其他使用者想要加入此通話,則變成為三方通話(即Skype中的多方通話功能),此多方通話稱為一個Conference。使用Skype4Com的功能,只要將新Call In進來的電話,呼叫Join( ConferenceId )的Function,傳入目前正在進行中的Call的ConferenceId,即可達到此功能。

以下有範例程式檔,供參考:
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其他使用者

在Skype4Com裡,如果要Call Out給其他使用者,有兩種方法可以做到。

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);
}

16 7月 2008

[Google App Engine] 介紹 - 建置開發環境

目前Google App Engine(以下簡稱GAE) 1.1版,支援Python 2.5版,而GAE的SDK開發環境,只要是可以執行Python 2.5的平台,都可以,所以無論Windows、Linux或是Mac都可以開發GAE。

1. 安裝GAE SDK

  所以建置開發環境的第一步就是在你的電腦上安裝Python 2.5(以上),然後就可以安裝GAE SDK
  安裝完成後,有兩個python檔案先介紹一下,詳細的用法之後再一一說明:
  • dev_appserv.py :在本機端測試的python執行檔
  • appcfg.py :上傳至GAE Server的python執行檔

2. 本機端測試
  由於GAE是提供虛擬伺服器的服務,所以它的測試環境與一般的Apache、Tomcat類似,可以將你寫好的GAE Code執行起來,然後使用者可以透過瀏覽器輸入http://localhost:8080 (預設是8080的Port,可以更改),去測試你寫好的程式。

2.1 建立Project檔案
  可以在GAE的安裝目錄底下新建一個新資料夾Ex: Test。此Test資料夾內,必須至少有兩個檔案:(1)app.yaml (2)myapp.py。其中,app.yaml是你的Project的config檔(檔名固定),myapp.py就是背後處理網頁的python檔(檔名自訂)。

2.2 app.yaml簡介
  每個Project資料夾中,必須要有一個app.yaml檔,這是一個Project config檔,用來指定Project在GAE上註冊的名稱,目前的版本,還有最重要的URL mapping。比如下面這個範例,是安裝GAE SDK時,裡面附的範例檔 - GuestBook,這是它的app.yaml檔的內容:
application: guestbook
version: 1
runtime: python
api_version: 1

handlers:
- url: .*
script: guestbook.py
  application放的就是Project檔的名稱(上傳至GAE時,就依此名稱存放,因此必須是有註冊成功的名稱才行),version就是目前的開發版本,允許的版本號的範圍為^(?!-)[a-z\d\-]{1,100}$,有興趣的可以試試不一樣的版本號:)
handlers放的就是URL的mapping,會根據url的內容,指定給一個python script檔去執行。而這個guestbook的範例,就是將所有的url都交給guestbook.py這個檔案執行。此url的撰寫方式,支援正規表示法
  所有你的GAE Project底下的URL,第一關卡,就是經過這個app.yaml決定誰去處理。所以你的GAE Project裡的Image、CSS、Javascript檔的URL link,都會經過此app.yaml的處理。因為這些檔案都是直接上傳給瀏覽器即可,不需要額外的處理,所以可以用static_dir這個handler去指定它。如:
handlers:
- url: /images
static_dir: images
- url: /js
static_dir: js
- url: /.*
script: myapp.py
  根據上面這個app.yaml的設定,當url為/images/.*時,會直接從images這個資料夾找到相同名稱的檔案上傳。同樣的,/js/.*也是一樣的做法。而其他所有的url,全會交由myapp.py處理。
  必須注意到的是,url mapping會由上而下找到第一個對應到的url rule,所以/.*這個rule必須擺在最下面,否則所有的url都會符合此rule,就不會找其他的rule了。
  其他更多的app.yaml說明,請參考官網

2.3 本機端執行Project
  當完成上面的步驟後,建好自己的Project,資料夾內至少包括(1)myapp.py (2)app.yaml,就可以執行起來試看看了。在Console Mode底下,到GAE的安裝目錄底下,輸入下面的指令即可(Windows的使用者要先將*.py指定給Python執行)
dev_appserver.py myapp/

  GAE安裝好後,有一個範例檔在:$(GAE)/demos/guestbook。執行的指令為:
dev_appserver.py demos/guestbook

  執行後,即可在瀏覽器中輸入http://localhost:8080,看看Project執行後的成果了。
修改程式碼時,並不需要重新啟動Server,只需要網頁重新整理即可,很方便。

dev_appserver.py有一些參數可以用,僅列出常用的,其餘請參考
 --help
  印出說明訊息
 --port=...
  指定localhost的port,預設為8080
 --clear_datastore
  清除之前的Datastore的data


3 上傳Project至GAE Server
  在Console Mode底下,至GAE安裝目錄,執行appcfg.py即可上傳。
appcfg.py [options] update <app-directory>
  輸入的<app-directory>必須要包含app.yaml,上傳的檔案會根據app.yaml的設定去搜尋需要上傳的檔案。且會根據app.yaml中設定的application名稱,上傳至你註冊的GAE application。上傳時,會詢問你的email和密碼,也可以在[options]裡面,指定--email=...,就不用每次上傳時都手動輸入了。相關的參數請參考

04 7月 2008

Google App Engine 1.1.0 Gql Query Date Property 的Bug

最近在玩Google App Engine時,玩沒多久就發現一個Bug... 應該是Bug沒錯吧=_=

當Gql Query的filter條件加入DateProperty時,就會出錯。解決方法,就是不要用DateProperty,改用DatetimeProperty就行了。

出現的Error Message:
BadValueError: Unsupported type for property : <type 'datetime.date'>

以下是會出錯的範例Code
class TestDB(db.Model):
author = db.UserProperty()
content = db.StringProperty()
date = db.DateProperty()

class MainPage(webapp.RequestHandler):
def get(self):
query = db.GqlQuery("SELECT * FROM TestDB WHERE date>:1", datetime.datetime(2008,7,4) )#Correct!
query = db.GqlQuery("SELECT * FROM TestDB WHERE date>:1", datetime.date(2008,7,4) )#Error!
query.fetch(10)

[Python] datetime取得當月份天數

Python並沒有提供datetime中month的天數(一個月,最多幾天),所以必須要用算的把它算出來,是有點麻煩。以下是我個人的作法,如果有比較好的作法,歡迎交流:)

import datetime
def DaysOfMonth( dt ): #dt的type是datetime or date皆可
#先加一個月,避免邊界值問題。
if dt.day < 15 :
dt = dt+datetime.timedelta(31)
else:
dt = dt+datetime.timedelta(20)
dt = dt+datetime.timedelta(days=(-dt.day))#再扣掉天數
return dt.day

dt = datetime.datetime(2008,7,4)
print DaysOfMonth(dt)
# output>> 31

dt = datetime.date(2008,7,4)
print DaysOfMonth(dt)
# output>> 31