Skype是目前這個星球上最厲害的IM+VOIP軟體,Skype現在已經改變了全球2.8億人的生活。你,值得擁有! :)
Skype中文官網:http://skype.tom.com/
Skype全球官網:http://www.skype.com/
Skype也是世界上最開放,最具創新意識的IM工具,他提供了Skype API, Skype4COM, Skype4Java幾種形式的開發介面給Skype愛好者編寫Skype的互動程式或者Skype的外掛程式。你可以使用任何你熟悉的語言,比如C/C++,VB, C#,Delphi,Java甚至PHP,VBScript。通過你的專業知識,去影響2.8億的Skype使用者。你也可以做到!:)
Skype全球開發人員社區:http://developer.skype.com/
下面我們將展示一個最簡單的訪問Skype API的C++代碼:
這裡可以下載對應的VC6工程:http://wh.hust.colin.googlepages.com/SkypeInteractiveDemo.rar
//
// Copyright (c) 2004-2006, Skype Limited.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of the Skype Limited nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// tab size: 2
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <rpcdce.h>
HWND hInit_MainWindowHandle; ///<本程式建立的視窗的控制代碼
HINSTANCE hInit_ProcessHandle; ///<本程式的進程控制代碼
char acInit_WindowClassName[128]; ///<本程式建立的視窗類別名
HANDLE hGlobal_ThreadShutdownEvent;
bool volatile fGlobal_ThreadRunning=true;
//Skype定義的訊息ID,Skype通過向第三方程式發送這類訊息來告知請求串連的結果
UINT uiGlobal_MsgID_SkypeControlAPIAttach;
//Skype定義的訊息ID,當第三方程式想擷取Skype的互動時,
//必須通過廣播(HWND_BROADCAST)發送這個訊息,Skype收到後給使用者彈出提示
//當使用者允許後,互動關係就建立起來了。
UINT uiGlobal_MsgID_SkypeControlAPIDiscover;
//Skype的視窗控制代碼
HWND hGlobal_SkypeAPIWindowHandle=NULL;
//BOOL變數標識是否列印更詳細的訊息內容
#if defined(_DEBUG)
bool volatile fGlobal_DumpWindowsMessages=true;
#else
bool volatile fGlobal_DumpWindowsMessages=false;
#endif
DWORD ulGlobal_PromptConsoleMode=0;
HANDLE volatile hGlobal_PromptConsoleHandle=NULL;
enum {
//第三方程式串連成功,在wParam中可以擷取到Skype的API視窗控制代碼
SKYPECONTROLAPI_ATTACH_SUCCESS=0,
//Skype已經收到串連請求了,並給使用者彈出了第三方程式請求訪問Skype的提示
//這時候串連並沒有成功建立,必須等到SKYPECONTROLAPI_ATTACH_SUCCESS訊息才行
SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION=1,
//Skype使用者拒絕了第三方程式的訪問請求
SKYPECONTROLAPI_ATTACH_REFUSED=2,
//API介面當前不可使用。這種情況有時候發生,比如當前Skype沒有任何使用者登入進去。
//第三方程式必須等到Skype廣播了SKYPECONTROLAPI_ATTACH_API_AVAILABLE訊息時再去嘗試串連才有效
SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE=3,
SKYPECONTROLAPI_ATTACH_API_AVAILABLE=0x8001
};
//從標準輸入視窗中擷取一行輸入到pacPromptBuffer中
bool Global_Console_ReadRow( char *pacPromptBuffer, unsigned int uiMaxLength)
{
HANDLE hConsoleHandle, hDuplicatedConsoleHandle;
DWORD ulCharactersRead, ulConsoleMode;
unsigned int uiNewLength;
BOOL fReadConsoleResult;
bool fReturnStatus;
char cCharacter;
fReturnStatus=false;
//擷取標準輸入視窗的輸入緩衝區控制代碼
while((hConsoleHandle=GetStdHandle(STD_INPUT_HANDLE))!=INVALID_HANDLE_VALUE)
{
if( DuplicateHandle( GetCurrentProcess(), hConsoleHandle,
GetCurrentProcess(), &hDuplicatedConsoleHandle, 0, FALSE,
DUPLICATE_SAME_ACCESS)==FALSE )
break;
GetConsoleMode( hDuplicatedConsoleHandle, &ulConsoleMode);
SetConsoleMode( hDuplicatedConsoleHandle, ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_ECHO_INPUT);
hGlobal_PromptConsoleHandle=hDuplicatedConsoleHandle;
ulGlobal_PromptConsoleMode=ulConsoleMode;
fReadConsoleResult=ReadConsole( hGlobal_PromptConsoleHandle,
(LPVOID)pacPromptBuffer, uiMaxLength, &ulCharactersRead, (LPVOID)0);
if( hGlobal_PromptConsoleHandle==(HANDLE)0 )
break;
hGlobal_PromptConsoleHandle=(HANDLE)0;
SetConsoleMode( hDuplicatedConsoleHandle, ulConsoleMode);
CloseHandle(hDuplicatedConsoleHandle);
if( fReadConsoleResult==FALSE || ulCharactersRead>uiMaxLength )
break;
pacPromptBuffer[ulCharactersRead]=0;
uiNewLength=ulCharactersRead;
while(uiNewLength!=0)
{
cCharacter=pacPromptBuffer[uiNewLength-1];
if( cCharacter!='/r' && cCharacter!='/n' )
break;
uiNewLength--;
}
pacPromptBuffer[uiNewLength]=0;
fReturnStatus=true;
break;
}
if( fReturnStatus==false )
pacPromptBuffer[0]=0;
return(fReturnStatus);
}
//輸入控制台的回收清理
void Global_Console_CancelReadRow(void)
{
if( hGlobal_PromptConsoleHandle!=(HANDLE)0 )
{
SetConsoleMode( hGlobal_PromptConsoleHandle, ulGlobal_PromptConsoleMode);
CloseHandle(hGlobal_PromptConsoleHandle);
hGlobal_PromptConsoleHandle=(HANDLE)0;
}
}
static LRESULT APIENTRY SkypeAPITest_Windows_WindowProc(
HWND hWindow, UINT uiMessage, WPARAM uiParam, LPARAM ulParam)
{
LRESULT lReturnCode;
bool fIssueDefProc;
lReturnCode=0;
fIssueDefProc=false;
switch(uiMessage)
{
case WM_DESTROY:
hInit_MainWindowHandle=NULL;
PostQuitMessage(0);
break;
case WM_COPYDATA:
//Skype與第三方程式的訊息傳送使用WM_COPYDATA
//當Skype通過WM_COPYDATA向所有已串連的第三方程式發送訊息時,會把Skype的視窗控制代碼放到uiParam中
if( hGlobal_SkypeAPIWindowHandle==(HWND)uiParam )
{
PCOPYDATASTRUCT poCopyData=(PCOPYDATASTRUCT)ulParam;
printf( "Message from Skype(%u): %.*s/n", poCopyData->dwData, poCopyData->cbData, poCopyData->lpData);
lReturnCode=1;
}
break;
default:
//如果訊息類型是uiGlobal_MsgID_SkypeControlAPIAttach,則表示串連相關的
if( uiMessage==uiGlobal_MsgID_SkypeControlAPIAttach )
{
switch(ulParam)
{
case SKYPECONTROLAPI_ATTACH_SUCCESS:
printf("!!! Connected; to terminate issue #disconnect/n");
hGlobal_SkypeAPIWindowHandle=(HWND)uiParam;
break;
case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
printf("!!! Pending authorization/n");
break;
case SKYPECONTROLAPI_ATTACH_REFUSED:
printf("!!! Connection refused/n");
break;
case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
printf("!!! Skype API not available/n");
break;
case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:
printf("!!! Try connect now (API available); issue #connect/n");
break;
}
lReturnCode=1;
break;
}
fIssueDefProc=true;
break;
}
if( fIssueDefProc )
lReturnCode=DefWindowProc( hWindow, uiMessage, uiParam, ulParam);
if( fGlobal_DumpWindowsMessages )
{
printf( "WindowProc: hWindow=0x%08X, MainWindow=0x%08X, Message=%5u, WParam=0x%08X, LParam=0x%08X; Return=%ld%s/n",
hWindow, hInit_MainWindowHandle, uiMessage, uiParam, ulParam, lReturnCode, fIssueDefProc? " (default)":"");
}
return(lReturnCode);
}
bool Initialize_CreateWindowClass(void)
{
unsigned char *paucUUIDString;
RPC_STATUS lUUIDResult;
bool fReturnStatus;
UUID oUUID;
fReturnStatus=false;
lUUIDResult=UuidCreate(&oUUID);
hInit_ProcessHandle=(HINSTANCE)OpenProcess( PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId());
if( hInit_ProcessHandle!=NULL && (lUUIDResult==RPC_S_OK || lUUIDResult==RPC_S_UUID_LOCAL_ONLY) )
{
if( UuidToString( &oUUID, &paucUUIDString)==RPC_S_OK )
{
WNDCLASS oWindowClass;
//產生視窗類別名(含UUID)
strcpy( acInit_WindowClassName, "Skype-API-Test-");
strcat( acInit_WindowClassName, (char *)paucUUIDString);
oWindowClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
//指定視窗的訊息回呼函數是SkypeAPITest_Windows_WindowProc
oWindowClass.lpfnWndProc=(WNDPROC)&SkypeAPITest_Windows_WindowProc;
oWindowClass.cbClsExtra=0;
oWindowClass.cbWndExtra=0;
oWindowClass.hInstance=hInit_ProcessHandle;
oWindowClass.hIcon=NULL;
oWindowClass.hCursor=NULL;
oWindowClass.hbrBackground=NULL;
oWindowClass.lpszMenuName=NULL;
oWindowClass.lpszClassName=acInit_WindowClassName;
//註冊視窗類別
if( RegisterClass(&oWindowClass)!=0 )
fReturnStatus=true;
RpcStringFree(&paucUUIDString);
}
}
if( fReturnStatus==false )
CloseHandle(hInit_ProcessHandle),hInit_ProcessHandle=NULL;
return(fReturnStatus);
}
void DeInitialize_DestroyWindowClass(void)
{
//登出視窗類別
UnregisterClass( acInit_WindowClassName, hInit_ProcessHandle);
CloseHandle(hInit_ProcessHandle),hInit_ProcessHandle=NULL;
}
bool Initialize_CreateMainWindow(void)
{
//建立視窗,並把控制代碼儲存到hInit_MainWindowHandle
hInit_MainWindowHandle=CreateWindowEx( WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,
acInit_WindowClassName, "", WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 128, 128, NULL, 0, hInit_ProcessHandle, 0);
return(hInit_MainWindowHandle!=NULL? true:false);
}
void DeInitialize_DestroyMainWindow(void)
{
//銷毀視窗
if( hInit_MainWindowHandle!=NULL )
DestroyWindow(hInit_MainWindowHandle),hInit_MainWindowHandle=NULL;
}
void Global_MessageLoop(void)
{
//訊息處理迴圈
MSG oMessage;
while(GetMessage( &oMessage, 0, 0, 0)!=FALSE)
{
TranslateMessage(&oMessage);
DispatchMessage(&oMessage);
}
}
//這是一個線程函數,主要用於接收使用者的輸入指令並執行
void __cdecl Global_InputProcessingThread(void *)
{
static char acInputRow[1024];
bool fProcessed;
//線程開始執行時預設去串連Skype,發送請求訪問Skype API的訊息。由於一開始我們不知道SKype的API視窗控制代碼值,只能
//通過HWND_BROADCAST廣播這個訊息給所有系統中在前台的視窗,如果Skype視窗存在,則自然也會收到。
if( SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0)!=0 )
{
//接受使用者輸入指令
while(Global_Console_ReadRow( acInputRow, sizeof(acInputRow)-1))
{
//退出程式
if( stricmp( acInputRow, "#quit")==0 ||
stricmp( acInputRow, "#exit")==0 )
break;
fProcessed=false;
//開啟顯示訊息詳細資料
if( stricmp( acInputRow, "#dbgon")==0 )
{
printf( "SkypeControlAPIAttach=%u, SkypeControlAPIDiscover=%u, hInit_MainWindowHandle=0x%08lX/n",
uiGlobal_MsgID_SkypeControlAPIAttach, uiGlobal_MsgID_SkypeControlAPIDiscover, hInit_MainWindowHandle);
fGlobal_DumpWindowsMessages=true,fProcessed=true;
}
//關閉顯示訊息詳細資料
if( stricmp( acInputRow, "#dbgoff")==0 )
fGlobal_DumpWindowsMessages=false,fProcessed=true;
//請求訪問Skype API
if( stricmp( acInputRow, "#connect")==0 )
{
SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0);
fProcessed=true;
}
//停止訪問Skype API。由代碼可以看出,這是一個假斷開,
//因為只是設定hGlobal_SkypeAPIWindowHandle為空白,從而不再處理和列印這個視窗發送的WM_COPYDATA訊息
if( stricmp( acInputRow, "#disconnect")==0 )
{
hGlobal_SkypeAPIWindowHandle=NULL;
printf("!!! Disconnected/n");
fProcessed=true;
}
//其它使用者輸入內容,則直接作為Skype API命令發送給Skype處理
if( fProcessed==false && hGlobal_SkypeAPIWindowHandle!=NULL )
{
COPYDATASTRUCT oCopyData;
// send command to skype
oCopyData.dwData=0;
oCopyData.lpData=acInputRow;
oCopyData.cbData=strlen(acInputRow)+1;
if( oCopyData.cbData!=1 )
{
if( SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData)==FALSE )
{
hGlobal_SkypeAPIWindowHandle=NULL;
printf("!!! Disconnected/n");
}
}
}
}
}
PostMessage( hInit_MainWindowHandle, WM_CLOSE, 0, 0);
SetEvent(hGlobal_ThreadShutdownEvent);
fGlobal_ThreadRunning=false;
}
void main(void)
{
//擷取到Skype註冊到系統的兩類訊息ID
uiGlobal_MsgID_SkypeControlAPIAttach=RegisterWindowMessage("SkypeControlAPIAttach");
uiGlobal_MsgID_SkypeControlAPIDiscover=RegisterWindowMessage("SkypeControlAPIDiscover");
if( uiGlobal_MsgID_SkypeControlAPIAttach!=0 && uiGlobal_MsgID_SkypeControlAPIDiscover!=0 )
{
//註冊視窗類別並建立視窗
if( Initialize_CreateWindowClass() )
{
if( Initialize_CreateMainWindow() )
{
hGlobal_ThreadShutdownEvent=CreateEvent( NULL, TRUE, FALSE, NULL);
if( hGlobal_ThreadShutdownEvent!=NULL )
{
//單獨啟動一個進程接收使用者輸入指令並處理
if( _beginthread( &Global_InputProcessingThread, 64*1024, NULL)!=(unsigned long)-1 )
{
//main主線程在此迴圈處理視窗訊息
Global_MessageLoop();
//記憶體回收和清理工作
Global_Console_CancelReadRow();
WaitForSingleObject( hGlobal_ThreadShutdownEvent, INFINITE);
}
CloseHandle(hGlobal_ThreadShutdownEvent);
}
DeInitialize_DestroyMainWindow();
}
DeInitialize_DestroyWindowClass();
}
}
}