#include #include #include #include using std::cerr; using std::cout; class BaseError { protected: std::string msg_; va_list ap_; public: BaseError(char *fmt, va_list ap) { int desired_length= _vsnprintf(NULL, 0, fmt, ap); msg_.resize(desired_length); int printedlength= _vsnprintf(&msg_[0], msg_.size(), fmt, ap); va_end(ap); if (printedlength!=-1) msg_.resize(printedlength); } friend std::ostream& operator << (std::ostream& os, const BaseError& e) { return os << e.msg_ << std::endl; } }; class SystemError : public BaseError { private: DWORD dwErrorCode; std::string err_; public: SystemError(char *fmt, ...) : BaseError(fmt, (va_start(ap_, fmt), ap_)) , dwErrorCode(GetLastError()) { char* msgbuf; int rc= FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, 0, (char*) &msgbuf, 0, NULL); if (rc) { err_= msgbuf; LocalFree(msgbuf); } } friend std::ostream& operator << (std::ostream& os, const SystemError& e) { os << e.msg_ << ": "; if (e.err_.empty()) os << std::hex << e.dwErrorCode << std::endl; else os << e.err_; return os; } }; class SkypeError : public BaseError { public: SkypeError(char *fmt, ...) : BaseError(fmt, (va_start(ap_, fmt), ap_)) { } }; std::ostream& operator << (std::ostream& os, HWND hWnd) { return os << (UINT)hWnd; } HWND g_hWndSkype; // window handle received in SkypeControlAPIAttach message HWND g_hWndClient; // our window handle bool g_bNotAvailable; // set by not-available msg from skype // windows messages registered by skype UINT SkypeControlAPIDiscover; UINT SkypeControlAPIAttach; // obtain the skype registered windows messages void SkypeRegisterMessages() { SkypeControlAPIDiscover =RegisterWindowMessage("SkypeControlAPIDiscover"); if (SkypeControlAPIDiscover==0) throw SystemError("RegisterWindowMessage"); //cout << boost::format("SkypeControlAPIDiscover=%04x\n") % SkypeControlAPIDiscover; SkypeControlAPIAttach =RegisterWindowMessage("SkypeControlAPIAttach"); if (SkypeControlAPIAttach==0) throw SystemError("RegisterWindowMessage"); //cout << boost::format("SkypeControlAPIAttach=%04x\n") % SkypeControlAPIAttach; } // handle skype api message, currently outputs the message to stdout. void HandleSkypeMessage(HWND hWndSkype, COPYDATASTRUCT* cds) { if (hWndSkype!=g_hWndSkype) cout << boost::format("msg: %08lx, global: %08lx\n") % hWndSkype % g_hWndSkype; cout << ">>" << (char*)cds->lpData << std::endl; } // initiate connnection with skype. void SkypeDiscover(HWND hWnd) { if (g_bNotAvailable) return; g_hWndSkype= NULL; LRESULT res= SendMessage(HWND_BROADCAST, SkypeControlAPIDiscover, (WPARAM)hWnd, 0); //cout << boost::format("discover result=%08lx\n") % res; } enum { SKYPECONTROLAPI_ATTACH_SUCCESS=0, SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION, SKYPECONTROLAPI_ATTACH_REFUSED, SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE, SKYPECONTROLAPI_ATTACH_API_AVAILABLE= 0x8001, }; // process SkypeControlAPIAttach message void HandleSkypeAttach(LPARAM lParam, WPARAM wParam) { switch(lParam) { case SKYPECONTROLAPI_ATTACH_SUCCESS: g_hWndSkype= (HWND)wParam; cout << boost::format("success: skypewnd= %08lx\n") % g_hWndSkype; break; case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION: cout << boost::format("pending authorization\n"); break; case SKYPECONTROLAPI_ATTACH_REFUSED: cout << boost::format("attach refused\n"); g_hWndSkype= NULL; break; case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE: cout << boost::format("skype api not available\n"); g_bNotAvailable= true; break; case SKYPECONTROLAPI_ATTACH_API_AVAILABLE: cout << boost::format("skype api available\n"); g_bNotAvailable= false; SkypeDiscover(g_hWndClient); break; default: cout << boost::format("UNKNOWN SKYPEMSG %08lx: %08lx\n") % lParam % wParam; } } // our windowsproc LRESULT CALLBACK SkypeWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg==WM_CREATE) { // lParam -> CREATESTRUCT -> lpCreateParams try { SkypeRegisterMessages(); SkypeDiscover(hWnd); return 0; } catch (BaseError e) { cerr << e; } catch (...) { cerr << "unknown exception\n"; } return -1; } else if (uMsg==WM_DESTROY) { return 0; } else if (uMsg==SkypeControlAPIAttach) { try { HandleSkypeAttach(lParam, wParam); } catch (BaseError e) { cerr << e; } catch (...) { cerr << "unknown exception in HandleSkypeAttach\n"; } return 0; } else if (uMsg==SkypeControlAPIDiscover) { HWND hWndOther= (HWND)wParam; if (hWndOther!=hWnd) cout << boost::format("detected other skype api client: %08lx\n") % hWndOther; return 0; } else if (uMsg==WM_COPYDATA) { try { HandleSkypeMessage((HWND)wParam, (COPYDATASTRUCT*)lParam); return TRUE; } catch (BaseError e) { cerr << e; } catch (...) { cerr << "unknown exception in HandleSkypeMessage\n"; } return FALSE; } else { //cout << boost::format("wnd %08lx msg %08lx %08lx %08lx\n") % hWnd % uMsg % wParam % lParam; return DefWindowProc(hWnd, uMsg, wParam, lParam); } } // creates our window, needed to communicate with skype. HWND MakeWindow() { //cout << "MakeWindow\n"; WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL wndcls.lpfnWndProc = SkypeWindowProc; wndcls.lpszClassName = "itsme skype window"; ATOM a= RegisterClass(&wndcls); if (a==0) throw SystemError("RegisterClass"); //cout << boost::format("windowclass: %04x\n") % a; HWND hWnd= CreateWindowEx(0, wndcls.lpszClassName, "itsme skype window", 0, -1, -1, 0, 0, (HWND)NULL, (HMENU)NULL, (HINSTANCE)NULL, NULL); if (hWnd==NULL) throw SystemError("CreateWindowEx"); return hWnd; } // destroy our window. void UnmakeWindow(HWND hWnd) { if (!DestroyWindow(hWnd)) cerr << SystemError("DestroyWindow"); if (!UnregisterClass("itsme skype window", NULL)) cerr << SystemError("UnregisterClass"); } // window thread, creates window, and runs messageloop. DWORD WINAPI SkypeWindowThread(LPVOID lpParameter) { //cout << "SkypeWindowThread\n"; g_hWndClient= MakeWindow(); //cout << boost::format("starting messageloop clientwnd=%08lx\n") % g_hWndClient; MSG msg; BOOL bRet; while ((bRet= GetMessage(&msg, NULL, 0, 0))!=0) { if (bRet==-1 || msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } //cout << "end thread\n"; return 0; } // creates window thread void MakeThread() { //cout << "MakeThread\n"; HANDLE hThread= CreateThread(NULL, 0, SkypeWindowThread, NULL, 0, NULL); if (hThread==NULL || hThread==INVALID_HANDLE_VALUE) { throw SystemError("CreateThread"); } //cout << boost::format("hThread=%08lx\n") % hThread; } // sends skype api message to skype void SkypeSendMessage(char *msg) { COPYDATASTRUCT cds; cds.dwData= 0; cds.lpData= msg; cds.cbData= strlen(msg)+1; if (!SendMessage(g_hWndSkype, WM_COPYDATA, (WPARAM)g_hWndClient, (LPARAM)&cds)) { cerr << "skypesendmessage failed\n"; SkypeDiscover(g_hWndClient); } } void run_skype_loop() { //cout << "run_skype_loop\n"; MakeThread(); cout << "ready\n"; char line[1024]; while (fgets(line, 1024, stdin)) { SkypeSendMessage(line); } UnmakeWindow(g_hWndClient); g_hWndClient= NULL; } int main(int argc, char **argv) { try { run_skype_loop(); } catch (BaseError e) { cerr << e; } catch (...) { cerr << "unknown exception\n"; } }