i'm quite new to skype and windows gui programming in general, so i am trying to write a small program which basically mimics the c++ console example given on this site.
basically, what i'm trying to do is create a window with a menu. the menu will contain skype commands (in the example below, i have implemented code for the FOCUS command).
at the moment, the program will attach itself to skype and display the received messages, but i cannot send custom data to the api. i have tried using a handle to the skype api window, but this returns false when using the sendmessage function. HWND_BROADCAST does not seem to produce any result either.
if someone could point me in the right direction, i'd really appreciate it.
here's the code:
CODE
#include <windows.h>
#include <string>
#include <process.h>
using namespace std;
#define ID_FILE_EXIT 9001
#define ID_TOOLS_CONNECT 9002
#define ID_TOOLS_DISCONNECT 9003
#define ID_TOOLS_FOCUS 9004
enum {
SKYPECONTROLAPI_ATTACH_SUCCESS=0, // Client is successfully attached and API window handle can be found in wParam parameter
SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION=1, // Skype has acknowledged connection request and is waiting for confirmation from the user.
// The client is not yet attached and should wait for SKYPECONTROLAPI_ATTACH_SUCCESS message
SKYPECONTROLAPI_ATTACH_REFUSED=2, // User has explicitly denied access to client
SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE=3, // API is not available at the moment. For example, this happens when no user is currently logged in.
// Client should wait for SKYPECONTROLAPI_ATTACH_API_AVAILABLE broadcast before making any further
// connection attempts.
SKYPECONTROLAPI_ATTACH_API_AVAILABLE=0x8001
};
const char g_szClassName[] = "skype api test";
HWND hInit_MainWindowHandle;
HWND hGlobal_SkypeAPIWindowHandle=NULL; // Variable to hold handle to Skype API window
HANDLE hGlobal_ThreadShutdownEvent;
UINT uiGlobal_MsgID_SkypeControlAPIAttach;
UINT uiGlobal_MsgID_SkypeControlAPIDiscover;
bool volatile fGlobal_ThreadRunning=true;
bool ipFlag = false;
string acInputRow = "#null";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
bool defaultEnd = false;
switch(Message)
{
case WM_CREATE:
{
// Create the menu
HMENU hMenu, hSubMenu;
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_CONNECT, "&Connect");
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_DISCONNECT, "&Disconnect");
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_FOCUS, "Focus &Skype");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Tools");
SetMenu(hwnd, hMenu);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
// Code to handle menu selections
case ID_FILE_EXIT:
hGlobal_SkypeAPIWindowHandle=NULL;
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_TOOLS_CONNECT:
{
}
break;
case ID_TOOLS_DISCONNECT:
break;
case ID_TOOLS_FOCUS:
{
acInputRow = "FOCUS";
}
break;
}
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_COPYDATA:
{
// Print response received from Skype
if( hGlobal_SkypeAPIWindowHandle==(HWND)wParam )
{
PCOPYDATASTRUCT poCopyData=(PCOPYDATASTRUCT)lParam;
MessageBox(hwnd, (char *)poCopyData->lpData, "Skype response:", MB_OK | MB_ICONINFORMATION);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
{
// If attempting to attach to the Skype API
if( Message==uiGlobal_MsgID_SkypeControlAPIAttach )
{
// Check the status code received from the Skype API
switch(lParam)
{
// Connection established
case SKYPECONTROLAPI_ATTACH_SUCCESS:
MessageBox(hwnd, "Connected!", "Alert!", MB_OK | MB_ICONINFORMATION);
hGlobal_SkypeAPIWindowHandle=(HWND)wParam;
break;
// Requires authorization from user
case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
MessageBox(hwnd, "Pending authorization", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// Connection refused
case SKYPECONTROLAPI_ATTACH_REFUSED:
MessageBox(hwnd, "Connection refused!", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// Skype not running / logged in
case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
MessageBox(hwnd, "Skype API not available!", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// API is available for connection
case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:
MessageBox(hwnd, "Try connect now (API available)", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
}
break;
}
return DefWindowProc( hwnd, Message, wParam, lParam);
}
break;
}
return 0;
}
void __cdecl Global_InputProcessingThread(void *)
{
bool fProcessed; // Processed? flag
// Send discover message to find Skype API...
if(SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0)!=0)
{ //
// Structure to hold data to be sent to Skype API
COPYDATASTRUCT oCopyData;
while(true)
{
if (!ipFlag)
{
// Compare user input from console
// Quit
if( acInputRow.compare("#quit")==0 ||
acInputRow.compare("#exit")==0 )
{
break;
}
fProcessed=false;
if( acInputRow.compare("#null")==0 )
fProcessed=true;
// Connect to Skype API
if( acInputRow.compare("#connect")==0 )
{
SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0);
fProcessed=true;
acInputRow = "#null";
}
// Disconnect from Skype API
if( acInputRow.compare("#disconnect")==0 )
{
hGlobal_SkypeAPIWindowHandle=NULL;
fProcessed=true;
acInputRow = "#null";
}
// Connect to Skype API
if( acInputRow.compare("FOCUS")==0 )
{
// Convert from CString to char array (this is done because a char array must be sent)
char* str = strdup(acInputRow.c_str());
oCopyData.dwData=(WPARAM)0; // Data to be passed (default 0)
oCopyData.lpData=str; // Pointer to data to be passed (Skype command char array)
oCopyData.cbData=(acInputRow.length() + 1); // Store length of Skype command string
if(!SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData))
{
MessageBox(hInit_MainWindowHandle, "Sendmessage failed!", "Focus...", MB_OK | MB_ICONINFORMATION);
}
fProcessed=true;
acInputRow = "#null";
}
// If string is a Skype command...
if( fProcessed==false && hGlobal_SkypeAPIWindowHandle!=NULL )
{
//
if( oCopyData.cbData!=1 )
{
// The following line sends the command to the Skype API
// usage: SendMessage( skype window handle, message to be sent, main window handle,
// address of oCopyData variable)
if(SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData) == FALSE )
// Display "disconnected" message if SendMessage function returns FALSE
{
//hGlobal_SkypeAPIWindowHandle=NULL;
MessageBox(hInit_MainWindowHandle, "SendMessage returned FALSE!", "Error!", MB_OK | MB_ICONINFORMATION);
}
ipFlag = false;
}
}
}
}
}
PostMessage( hInit_MainWindowHandle, WM_CLOSE, 0, 0);
// Set the event that will end the thread - this is being waited on by main() using WaitForSingleObject
SetEvent(hGlobal_ThreadShutdownEvent);
fGlobal_ThreadRunning=false;
}
int MessageLoop(void)
{
MSG Msg;
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
int iMsg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)&WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
uiGlobal_MsgID_SkypeControlAPIAttach=RegisterWindowMessage("SkypeControlAPIAttach");
uiGlobal_MsgID_SkypeControlAPIDiscover=RegisterWindowMessage("SkypeControlAPIDiscover");
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hInit_MainWindowHandle = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"skype API connect",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hInit_MainWindowHandle == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hInit_MainWindowHandle, nCmdShow);
UpdateWindow(hInit_MainWindowHandle);
////////////////////////////////////////////////////////////
// Begin thread to process incoming messages from Skype
////////////////////////////////////////////////////////////
//
// Create an event to handle the quit and exit commands
hGlobal_ThreadShutdownEvent=CreateEvent( NULL, TRUE, FALSE, NULL);
if( hGlobal_ThreadShutdownEvent!=NULL )
{
if( _beginthread( &Global_InputProcessingThread, 64*1024, NULL)!=(unsigned long)-1 )
{
iMsg = MessageLoop();
//WaitForSingleObject( hGlobal_ThreadShutdownEvent, INFINITE);
}
CloseHandle(hGlobal_ThreadShutdownEvent);
}
//
////////////////////////////////////////////////////////////
//return Msg.wParam;
return iMsg;
}
#include <string>
#include <process.h>
using namespace std;
#define ID_FILE_EXIT 9001
#define ID_TOOLS_CONNECT 9002
#define ID_TOOLS_DISCONNECT 9003
#define ID_TOOLS_FOCUS 9004
enum {
SKYPECONTROLAPI_ATTACH_SUCCESS=0, // Client is successfully attached and API window handle can be found in wParam parameter
SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION=1, // Skype has acknowledged connection request and is waiting for confirmation from the user.
// The client is not yet attached and should wait for SKYPECONTROLAPI_ATTACH_SUCCESS message
SKYPECONTROLAPI_ATTACH_REFUSED=2, // User has explicitly denied access to client
SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE=3, // API is not available at the moment. For example, this happens when no user is currently logged in.
// Client should wait for SKYPECONTROLAPI_ATTACH_API_AVAILABLE broadcast before making any further
// connection attempts.
SKYPECONTROLAPI_ATTACH_API_AVAILABLE=0x8001
};
const char g_szClassName[] = "skype api test";
HWND hInit_MainWindowHandle;
HWND hGlobal_SkypeAPIWindowHandle=NULL; // Variable to hold handle to Skype API window
HANDLE hGlobal_ThreadShutdownEvent;
UINT uiGlobal_MsgID_SkypeControlAPIAttach;
UINT uiGlobal_MsgID_SkypeControlAPIDiscover;
bool volatile fGlobal_ThreadRunning=true;
bool ipFlag = false;
string acInputRow = "#null";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
bool defaultEnd = false;
switch(Message)
{
case WM_CREATE:
{
// Create the menu
HMENU hMenu, hSubMenu;
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_CONNECT, "&Connect");
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_DISCONNECT, "&Disconnect");
AppendMenu(hSubMenu, MF_STRING, ID_TOOLS_FOCUS, "Focus &Skype");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Tools");
SetMenu(hwnd, hMenu);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
// Code to handle menu selections
case ID_FILE_EXIT:
hGlobal_SkypeAPIWindowHandle=NULL;
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_TOOLS_CONNECT:
{
}
break;
case ID_TOOLS_DISCONNECT:
break;
case ID_TOOLS_FOCUS:
{
acInputRow = "FOCUS";
}
break;
}
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_COPYDATA:
{
// Print response received from Skype
if( hGlobal_SkypeAPIWindowHandle==(HWND)wParam )
{
PCOPYDATASTRUCT poCopyData=(PCOPYDATASTRUCT)lParam;
MessageBox(hwnd, (char *)poCopyData->lpData, "Skype response:", MB_OK | MB_ICONINFORMATION);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
{
// If attempting to attach to the Skype API
if( Message==uiGlobal_MsgID_SkypeControlAPIAttach )
{
// Check the status code received from the Skype API
switch(lParam)
{
// Connection established
case SKYPECONTROLAPI_ATTACH_SUCCESS:
MessageBox(hwnd, "Connected!", "Alert!", MB_OK | MB_ICONINFORMATION);
hGlobal_SkypeAPIWindowHandle=(HWND)wParam;
break;
// Requires authorization from user
case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
MessageBox(hwnd, "Pending authorization", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// Connection refused
case SKYPECONTROLAPI_ATTACH_REFUSED:
MessageBox(hwnd, "Connection refused!", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// Skype not running / logged in
case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
MessageBox(hwnd, "Skype API not available!", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
// API is available for connection
case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:
MessageBox(hwnd, "Try connect now (API available)", "Alert!", MB_OK | MB_ICONINFORMATION);
break;
}
break;
}
return DefWindowProc( hwnd, Message, wParam, lParam);
}
break;
}
return 0;
}
void __cdecl Global_InputProcessingThread(void *)
{
bool fProcessed; // Processed? flag
// Send discover message to find Skype API...
if(SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0)!=0)
{ //
// Structure to hold data to be sent to Skype API
COPYDATASTRUCT oCopyData;
while(true)
{
if (!ipFlag)
{
// Compare user input from console
// Quit
if( acInputRow.compare("#quit")==0 ||
acInputRow.compare("#exit")==0 )
{
break;
}
fProcessed=false;
if( acInputRow.compare("#null")==0 )
fProcessed=true;
// Connect to Skype API
if( acInputRow.compare("#connect")==0 )
{
SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0);
fProcessed=true;
acInputRow = "#null";
}
// Disconnect from Skype API
if( acInputRow.compare("#disconnect")==0 )
{
hGlobal_SkypeAPIWindowHandle=NULL;
fProcessed=true;
acInputRow = "#null";
}
// Connect to Skype API
if( acInputRow.compare("FOCUS")==0 )
{
// Convert from CString to char array (this is done because a char array must be sent)
char* str = strdup(acInputRow.c_str());
oCopyData.dwData=(WPARAM)0; // Data to be passed (default 0)
oCopyData.lpData=str; // Pointer to data to be passed (Skype command char array)
oCopyData.cbData=(acInputRow.length() + 1); // Store length of Skype command string
if(!SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData))
{
MessageBox(hInit_MainWindowHandle, "Sendmessage failed!", "Focus...", MB_OK | MB_ICONINFORMATION);
}
fProcessed=true;
acInputRow = "#null";
}
// If string is a Skype command...
if( fProcessed==false && hGlobal_SkypeAPIWindowHandle!=NULL )
{
//
if( oCopyData.cbData!=1 )
{
// The following line sends the command to the Skype API
// usage: SendMessage( skype window handle, message to be sent, main window handle,
// address of oCopyData variable)
if(SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData) == FALSE )
// Display "disconnected" message if SendMessage function returns FALSE
{
//hGlobal_SkypeAPIWindowHandle=NULL;
MessageBox(hInit_MainWindowHandle, "SendMessage returned FALSE!", "Error!", MB_OK | MB_ICONINFORMATION);
}
ipFlag = false;
}
}
}
}
}
PostMessage( hInit_MainWindowHandle, WM_CLOSE, 0, 0);
// Set the event that will end the thread - this is being waited on by main() using WaitForSingleObject
SetEvent(hGlobal_ThreadShutdownEvent);
fGlobal_ThreadRunning=false;
}
int MessageLoop(void)
{
MSG Msg;
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
int iMsg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)&WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
uiGlobal_MsgID_SkypeControlAPIAttach=RegisterWindowMessage("SkypeControlAPIAttach");
uiGlobal_MsgID_SkypeControlAPIDiscover=RegisterWindowMessage("SkypeControlAPIDiscover");
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hInit_MainWindowHandle = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"skype API connect",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hInit_MainWindowHandle == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hInit_MainWindowHandle, nCmdShow);
UpdateWindow(hInit_MainWindowHandle);
////////////////////////////////////////////////////////////
// Begin thread to process incoming messages from Skype
////////////////////////////////////////////////////////////
//
// Create an event to handle the quit and exit commands
hGlobal_ThreadShutdownEvent=CreateEvent( NULL, TRUE, FALSE, NULL);
if( hGlobal_ThreadShutdownEvent!=NULL )
{
if( _beginthread( &Global_InputProcessingThread, 64*1024, NULL)!=(unsigned long)-1 )
{
iMsg = MessageLoop();
//WaitForSingleObject( hGlobal_ThreadShutdownEvent, INFINITE);
}
CloseHandle(hGlobal_ThreadShutdownEvent);
}
//
////////////////////////////////////////////////////////////
//return Msg.wParam;
return iMsg;
}
thanks in advance,
vinny