你也可以玩转Skype -- 基于Skype API开发外壳程序入门

原文:你也可以玩转Skype
-- 基于Skype API开发外壳程序入门

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

时间: 2024-10-12 17:28:34

你也可以玩转Skype -- 基于Skype API开发外壳程序入门的相关文章

基于IDEA使用Spark API开发Spark程序

清明假期折腾了两天,总结了两种方式使用IDE进行spark程序,记录一下: 第一种方法比较简单,两种方式都是采用SBT进行编译的. 注意:本地不需要安装Scala程序,否则在编译程序时有版本兼容性问题. 一.基于Non-SBT方式 创建一个Scala IDEA工程 我们使用Non-SBT的方式,点击"Next" 命名工程,其他按照默认 点击"Finish"完成工程的创建 修改项目的属性 首先修改Modules选项 在src下创建两个文件夹,并把其属性改为source

【核心API开发】Spark入门教程[3]

本教程源于2016年3月出版书籍<Spark原理.机制及应用> ,在此以知识共享为初衷公开部分内容,如有兴趣,请支持正版书籍. Spark综合了前人分布式数据处理架构和语言的优缺点,使用简洁.一致的函数式语言Scala作为主要开发语言,同时为了方便更多语言背景的人使用,还支持Java.Python和R语言.Spark因为其弹性分布式数据集(RDD)的抽象数据结构设计,通过实现抽象类RDD可以产生面对不同应用场景的子类.本章将先介绍Spark编程模型.RDD的相关概念.常用API源码及应用案例,

Spark API编程动手实战-08-基于IDEA使用Spark API开发Spark程序-01

创建一个Scala IDEA工程: 点击“Next”: 点击“Finish”完成工程的创建: 修改项目的属性: 首先修改Modules选项: 在src下创建两个文件夹,并把其属性改为source: 再修改Libraries: 因为要开发Spark程序,所以需要把Spark的开发需要的jar包导进来: 导入包完成后,在工程的scala下面创建一个package: 创建一个Object对象: 完成初始类的创建: 首先构建Spark Driver的模板代码: 该程序是对前面的搜狗日志的处理代码,只不过

Spark API编程动手实战-08-基于IDEA使用Spark API开发Spark程序-02

接下来进行打包,使用Project  Structure的Artifacts: 使用From modules with dependencies: 选择Main Class: 点击“OK”: 把名称改为SparkDemoJar: 因为每台机器上都安装了Scala和Spark,所以可以把Scala和Spark相关的jar文件都删除掉: 接下来进行Build: 选择“Build Artifacts”: 剩下的操作,就是jar包上传到服务器上,然后执行spark-submit命令,我在之前的文章已经详

Skype发布视频API

原文:Skype发布视频API 相信很多人对Skype多少都应该有一些了解,如果以前没有使用过它的服务的话,也应该在最近的新闻中听说过它的大名.因为,它和我们每天都在接触的公司--Mircrosoft,联系到了一起.今年,5月10日,Mircrosoft宣布85亿美元收购Skype:6月18日,该交易获美国监管机构批准:10月8日,欧盟批准该收购案,标志着Mircrosoft正式完成了对Skype的收购. 相信也有很多读者应该都正在使用或者使用过Skype.Skype是一家全球性的互联网电话公司

基于七牛API开发的前端JavaScript SDK

这是我们工程实践的内容,由于时间原因,具体不赘述,啊~主要还是因为懒o(╯□╰)o工程实践的题目为openedx后端管理系统的功能拓展与优化,我们要优化的一个主要功能便是实现视频本地化上传,我们采用的视频云服务商为七牛云存储,以下链接是基于它的API开发的前端JavaScript SDK,http://developer.qiniu.com/docs/v6/sdk/javascript-sdk.html我的任务是看完,找到需要改的参数,刚刚大概看了一下,很多东西不是很明白,先把我觉得需要改的参数

10月份出版图书《玩转虚拟机基于VMware+Windows》

10月份出版图书<玩转虚拟机基于VMware+Windows> 敬请关注! 淘宝购买网址:91xueit.taobao.com 索取学习所需软件,技术交流加韩老师QQ 458717185 获取韩老师最新动态 关注微信

基于Windows API的粒子随机运动C++实现

基于Windows API编写Windows动画演示程序,具有便捷.不依赖于IDE的特点. 以随机运动粒子系统为例,实现了该动画框架,C++代码与效果图像如下: #include <windows.h> #include <vector> using namespace std; //粒子数量 #define N 1024 //粒子类型 typedef struct Particle { float x, y; float speedx, speedy; COLORREF rgb;

基于ArcGIS API for Javascript的地图编辑工具

转自:http://www.cnblogs.com/znlgis/p/3505646.html 最近工作上需要用ArcGIS API for Javascript来开发一个浏览器上使用的地图编辑工具,分享一下一些相关的开发经验. 我开发的地图编辑工具是根据ESRI提供的例子修改而来的,参考的例子是https://developers.arcgis.com/en/javascript/jssamples/ed_default_editingwidget.html 我们下面只说一些需要注意的问题: