ChangeClipboardChain() fails when called from console CtrlHandler() - winapi

I know, this method is outdated, just curious.
When I call ChangeClipboardChain() from atexit handler, it succeeds. When precc Ctrl-C, it fails. I know it, because other clipboard viewers don't receive WM_CHANGECBCHAIN.
This sample program exits when something is copied to clipboard 4 times:
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
static void pWin32Error(const char* fmt, ...);
static int counter=0;
static HWND nextWnd = NULL;
static
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg) {
case WM_CHANGECBCHAIN:
{
HWND wndRemove = (HWND)wParam;
HWND wndNextNext = (HWND)lParam;
printf("WM_CHANGECBCHAIN %p %p\n", (void*)wndRemove, (void*)wndNextNext);
if (nextWnd == wndRemove) {
printf("saving next window %p\n", (void*)wndNextNext);
nextWnd = wndNextNext;
} else if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
}
break;
case WM_DRAWCLIPBOARD:
counter++;
if (counter > 4) exit(0);
printf("WM_DRAWCLIPBOARD\n");
if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
break;
default:
return DefWindowProc( hwnd,uMsg,wParam,lParam);
}
return 0;
}
static volatile HWND global_hwnd = NULL;
WNDCLASS wndclass = {
0,/* UINT style;*/
WindowProc,/* WNDPROC lpfnWndProc;*/
0,/* int cbClsExtra;*/
0,/* int cbWndExtra;*/
NULL,/* HINSTANCE hInstance;*/
NULL,/* HICON hIcon;*/
NULL,/* HCURSOR hCursor;*/
NULL,/* HBRUSH hbrBackground;*/
NULL,/* LPCWSTR lpszMenuName;*/
_T("myclipmonitor")/* LPCWSTR lpszClassName;*/
};
static void unreg() {
HWND hwnd;
hwnd = (HWND)InterlockedExchangePointer(&global_hwnd, NULL); /* ignore the "cast to greater size" warning */
if (hwnd) {
printf("Removing self from chain: %p <- %p\n", (void*)hwnd, (void*)nextWnd);
if (!ChangeClipboardChain(hwnd, nextWnd) && GetLastError() != 0) {
pWin32Error("ChangeClipboardChain() failed");
}
}
}
static void exitproc() {
fprintf(stderr, "exitproc()\n");
unreg();
}
static
BOOL WINAPI CtrlHandler( DWORD fdwCtrlType )
{
fprintf(stderr, "CtrlHandler()\n");
unreg();
switch ( fdwCtrlType ) {
case CTRL_C_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-C.\n" );
break;
case CTRL_CLOSE_EVENT:
fprintf(stderr, "\n\n Stopping due to closing the window.\n" );
break;
case CTRL_BREAK_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-Break.\n" );
break;
// Pass other signals to the next handler - ret = FALSE
case CTRL_LOGOFF_EVENT:
fprintf(stderr, "\n\n Stopping due to logoff.\n" );
break;
case CTRL_SHUTDOWN_EVENT:
fprintf(stderr, "\n\n Stopping due to system shutdown.\n" );
break;
default:
fprintf(stderr, "\n\n Stopping due to unknown event.\n" );
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
ATOM classatom;
HINSTANCE hinst = GetModuleHandle(NULL);
MSG msg;
wndclass.hInstance = hinst;
classatom = RegisterClass(&wndclass);
if (classatom == 0) {
pWin32Error("RegisterClass() failed");
return -1;
}
global_hwnd = CreateWindowEx(0, (LPCTSTR)classatom, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
if (!global_hwnd) {
pWin32Error("CreateWindowEx() failed");
return -1;
}
printf("hwnd = %p\n", (void*)global_hwnd);
nextWnd = SetClipboardViewer(global_hwnd);
if (!nextWnd && GetLastError() != 0) {
pWin32Error("SetClipboardViewer() failed");
return -1;
}
printf("nextWnd = %p\n", (void*)nextWnd);
atexit(exitproc);
if (0 == SetConsoleCtrlHandler( CtrlHandler, TRUE )) {
pWin32Error("SetConsoleCtrlHandler() failed");
return -1;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
static char *cleanstr(char *s)
{
while(*s) {
switch((int)*s){
case 13:
case 10:
*s=' ';
break;
}
s++;
}
return s;
}
static void __pWin32Error(int level, DWORD eNum, const char* fmt, va_list args)
{
char emsg[1024];
char *pend = emsg + sizeof(emsg);
size_t count = sizeof(emsg);
unsigned u;
do {
u = (unsigned)_vsnprintf(pend - count, count, fmt, args);
if (u >= count) break;
count -= u;
u = (unsigned)_snprintf(pend - count, count, ": ");
if (u >= count) break;
count -= u;
u = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
pend - count, (DWORD)count, NULL );
if (u == 0) {
u = (unsigned)_snprintf(pend - count, count, "0x%08x (%d)", eNum, eNum);
}
} while(0);
emsg[sizeof(emsg)-1] = '\0';
pend = cleanstr(emsg);
if (pend < emsg + sizeof(emsg)-1) {
pend++;
*pend = '\0';
}
pend[-1] = '\n';
puts(emsg);
}
static void pWin32Error(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
__pWin32Error(0, GetLastError(), fmt, args);
va_end(args);
}

Related

winsock time loop send message does not work

Using winsock, I got a client and a server, when connect is done and i send a message the first time i can recv it in the server but after that when I do a time loop i can not show them on the screen. the send message inside the time loop does not return an error. I know this is a weird problem but if you take a look at timerCb that's where the send function is, it does not return an error but in my server i cannot print it. I have also tried making a new while loop with a parameter of recv it still did not work.
This is my client,
char receivingMessage[1000];
char messageInitiation[90] = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
//main
SetTimer(NULL, 0, 3600, timerCb);
if(WSAStartup(MAKEWORD(2, 2), &ws) != 0){
printf("WSA err %d \n", GetLastError());
}else{
}
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){
printf("Invalid Socket \n");
}else{
printf("socket binded \n");
}
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
rmtServer.sin_family = AF_INET;
if((connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in))) != 0){
printf("\n err %d", GetLastError());
}else{
printf("\n connected");
send(s, messageInitiation, strlen(messageInitiation), 0);
recv(s, receivingMessage, 1000, 0);
printf("\n %s", receivingMessage);
int liop;
liop = strcmp(receivingMessage, "I got you!!");
if(liop == 0){
connectedYet = TRUE;
}
printf("\n is it true: ? %d\n", connectedYet);
}
while(GetMessage(&message, NULL, 0, 0) > 0){
TranslateMessage(&message);
DispatchMessage(&message);
}
//outside main
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
char *msgg = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
printf("\n%s\n", "timing");
if(send(s, msgg, strlen(msgg), 0) == SOCKET_ERROR){
printf("err :%d\n", GetLastError());
}
}
And this is my server
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) {
MSG message;
WSADATA ws;
SOCKET s, incomingSocket;
struct sockaddr_in server, client;
char incomingMessage[1800];
int recvState;
WSAStartup(MAKEWORD(2, 2), &ws);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(4743);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
bind(s, (struct sockaddr *)&server, sizeof(server));
listen(s, 1300);
int g = sizeof(struct sockaddr_in);
while((incomingSocket = accept(s, (struct sockaddr *)&client, &g)) != INVALID_SOCKET){
printf("%s\n", inet_ntoa(client.sin_addr));
printf("conn\n");
if((recvState = recv(incomingSocket, incomingMessage, 2500, 0)) == SOCKET_ERROR){
}else{
int as;
if((as = strcmp(incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89")) == 0){
printf("\n identical");
send(incomingSocket, "I got you!!", 11, 0);
}
printf("\n :%s\n", incomingMessage);
}
}
if(incomingSocket == INVALID_SOCKET){
printf("invalid socket");
}
return 0;
}
UPDATE
I have added this in my server code, before return 0 it does not display anything at all.
while((recvState = recv(incomingSocket, incomingMessage, 50, 0)) > 0) {
printf("\n new msg %s\n", incomingMessage);
}
TCP is a byte stream, not message-oriented like you are expecting.
recv() is not guaranteed to return complete messages. It could return as little as 1 byte, or it could return partial bytes from a message, or even bytes from multiple messages. You have to handle buffering and message framing in your code logic. And pay attention to its return value so you know how much it actually read. If you are expecting more data than is read, you have to call recv() again to read the rest, potentially many times. So use a loop.
So, either:
Have the sender send a string's length as a fixed-length value before then sending the actual characters. Then have the receiver read the length to know how many characters to read.
Have the sender send a unique terminator after each string, like a nul character or even a CRLF, then the receiver can keep reading until it encounters the terminator.
As for send(), it is not guaranteed to send complete data, either. It could send as few as 1 byte, or at least less than what you requested. So you have to pay attention to its return value, too, to know how much it actually sent. If it doesn't send everything in one go, you have to call it again to send any remaining data, potentially many times. So use a loop.
For example, try something more like this:
Client:
const char messageInitiation* = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
char* readStr(SOCKET s)
{
char *str = NULL;
char buffer[100], ch;
int buf_len = 0, str_len = 0, ret;
do
{
ret = recv(s, &ch, 1, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
if (ch == '\0')
break;
if (buf_len == sizeof(buffer))
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str + str_len, buffer, buf_len);
str_len += buf_len;
buf_len = 0;
}
buffer[buf_len++] = ch;
}
while (true);
if (buf_len > 0)
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str, buffer, buf_len);
str_len += buf_len;
}
str[str_len] = '\0';
return str;
}
int sendStr(SOCKET s, const char *str)
{
const unsigned char *pstr = (const unsigned char*) str;
int len = strlen(str) + 1, ret;
do
{
ret = send(s, pstr, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pstr += ret;
len -= ret;
}
while (len > 0);
return 0;
}
/* alternatively:
int readAll(SOCKET s, void *data, int len)
{
unsigned char *pdata = (unsigned char *) data;
int ret;
while (len > 0)
{
ret = recv(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int readStr(SOCKET s)
{
int32_t len = 0;
if (readAll(s, &len, sizeof(len)) == SOCKET_ERROR)
return NULL;
char *str = (char*) malloc(len + 1);
if (!str)
{
printf("memory err\n");
return NULL;
}
if (readAll(s, str, len) == SOCKET_ERROR)
{
free(str);
return NULL;
}
str[len] = '\0';
return str;
}
int sendAll(SOCKET s, const void *data, int len)
{
const unsigned char *pdata = (const unsigned char*) data;
int ret;
while (len > 0)
{
ret = send(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int sendStr(SOCKET s, const char *str)
{
int32_t len = strlen(str) + 1;
int ret = sendAll(s, &len, sizeof(len));
if (ret == 0)
ret = sendAll(s, str, len);
return ret;
}
*/
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
printf("\n%s\n", "timing");
if (!sendStr(s, messageInitiation))
PostQuitMessage(0);
}
int main()
{
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket created\n");
struct sockaddr_in rmtServer = {};
rmtServer.sin_family = AF_INET;
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
if (connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
printf("connect err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("connected\n");
if (sendStr(s, messageInitiation) != 0)
{
closesocket(s);
WSACleanup();
return -1;
}
char *receivingMessage = recvStr(s);
if (!receivingMessage)
{
closesocket(s);
WSACleanup();
return -1;
}
printf("%s\n", receivingMessage);
BOOL connectedYet = (strcmp(receivingMessage, "I got you!!") == 0);
printf("is it true: ? %d\n", connectedYet);
free(receivingMessage);
SetTimer(NULL, 0, 3600, timerCb);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
closesocket(s);
WSACleanup();
return 0;
}
Server:
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// see client code above
char* readStr(SOCKET s);
int sendStr(SOCKET s, const char *str);
int main()
{
struct sockaddr_in server = {0}, client;
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLasatError());
WSACleanup();
return -1;
}
struct sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(4743);
ret = bind(s, (struct sockaddr *)&server, sizeof(server));
if (ret == SOCKET_ERROR)
{
printf("bind err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
if (listen(s, 10) == SOCKET_ERROR)
{
printf("listen err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
int g, iResult;
struct sockaddr_in client;
do
{
g = sizeof(client);
SOCKET incomingSocket = accept(s, (struct sockaddr *)&client, &g);
if (incomingSocket == INVALID_SOCKET)
{
printf("accept err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("%s conn\n", inet_ntoa(client.sin_addr));
char *incomingMessage = recvStr(incomingSocket);
if (incomingMessage)
{
printf("%s\n", incomingMessage);
if (incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89") == 0)
{
printf("identical\n");
sendStr(incomingSocket, "I got you!!");
}
}
closesocket(incomingSocket);
}
while (true);
return 0;
}

Migrating Winsock console application to Windows subsystem - stack overflow

Hey there wonderful community!
I'm back with a question regarding a console server application I've made with winsock. It's finally reaching a stage where I would need a to add a GUI, and to do so, I need it to be using the Windows subsystem.
And so I started the migration.
Yet I'm hitting a stack overflow somewhere in my application, and for the life of me I can't figure out where. Perhaps it has to do with WIN being a non-blocking subsystem (hope I used my vocab correctly).
Anyway, I hope to enlist you all as helpers. Many thanks :)
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <conio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
int minitialize();
int msend(char msendbuf[512]);
char* mrecv(bool show);
int mshutdown();
void GoToXY(int column, int line);
int scroll(void);
int printm(char *inp);
int printm(char *inp, DWORD color);
int mexit();
char *vir = "true";
int clientnumber=0;
int currentclient=0;
int lastclient=0;
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "10150"
struct _client
{
bool con;
sockaddr_in addr; //Client info like ip address
SOCKET cs; //Client socket
fd_set set; //used to check if there is data in the socket
std::string ip;
std::string name;
int i; //any piece of additional info
} client[100];
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
DWORD WINAPI recvfunc(LPVOID randparam)
{
while (true) {
ClientSocket=client[currentclient].cs;
if (mrecv(true)=="1") {
client[currentclient].con=false;
ClientSocket=client[lastclient].cs;
break;
}
}
return 0;
}
DWORD WINAPI headerfunc(LPVOID randparam)
{
Sleep(500);
while (true) {
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &SBInfo);
int xx = SBInfo.dwCursorPosition.X;
int yy = SBInfo.dwCursorPosition.Y;
GoToXY(0,0);
HANDLE hHeaderColor;
hHeaderColor = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hHeaderColor, FOREGROUND_GREEN);
std::cout<<"Server Started. Current Client:"<<currentclient<<" Clients connected: "<<clientnumber<<" ("<<xx<<","<<yy<<") "<<lastclient;
SetConsoleTextAttribute(hHeaderColor, 0 |
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
GoToXY(xx,yy);
Sleep(2000);
}
return 0;
}
DWORD WINAPI sendfunc(LPVOID randparam)
{
while (true) {
char mmessage[512];
std::cin.getline(mmessage, 512);
if (strlen(mmessage)<2) {
GoToXY(0,23);
sendfunc("1");
}
char msendbuf[512]="Server> ";
strcat(msendbuf,mmessage);
if (msend(msendbuf)==1) {
"Client must have disconnected. Please select a new client.";
sendfunc("1");
}
if ((strncmp(msendbuf,"Server> /",9)) != 0) {
printm(msendbuf,FOREGROUND_INTENSITY);
}
GoToXY(0,23);
for (int sp=0; sp<72; sp++) {
std::cout<<" ";
}
GoToXY(0,23);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
minitialize();
HANDLE hRecvThread;
HANDLE hSendThread;
HANDLE hHeaderThread;
DWORD dwRecvThreadId;
DWORD dwSendThreadId;
DWORD dwHeaderThreadId;
hHeaderThread = CreateThread(NULL,0,headerfunc,"1",0,&dwHeaderThreadId);
for (int mf=2; mf<25; mf++) {
std::cout<<"\n";
}
hSendThread = CreateThread(NULL,0,sendfunc,"1",0,&dwSendThreadId);
// Accept a client socket
for (int sock=1; sock<100; sock++) {
ClientSocket = accept(ListenSocket, NULL, NULL);
char sockprint[80];
char sockchar[4];
itoa(sock,sockchar,10);
strcpy(sockprint,"Client ");
strcat(sockprint,sockchar);
strcat(sockprint," connected.");
printm(sockprint);
GoToXY(0,23);
if (ClientSocket == INVALID_SOCKET) {
printm("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
client[sock].cs=ClientSocket;
client[sock].con=true;
lastclient=clientnumber;
clientnumber++;
currentclient=clientnumber;
hRecvThread = CreateThread(NULL,0,recvfunc,"1",0,&dwRecvThreadId);
}
// shutdown the connection since we're done
mshutdown();
std::cin.ignore();
return 0;
}
int printm(char *inp, DWORD color) {
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hOut,
color);
printm(inp);
SetConsoleTextAttribute(hOut, 0 |
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
return 0;
}
int printm(char *inp) {
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &SBInfo);
int xx = SBInfo.dwCursorPosition.X;
int yy = SBInfo.dwCursorPosition.Y;
GoToXY(0,22);
std::cout<<inp<<"\n";
scroll();
GoToXY(xx,yy);
return 1;
}
int msend(char msendbuf[512]) // Send a message
{
if (strncmp(msendbuf,"Server> /exit",(strlen(msendbuf))) == 0) {
mexit();
}
if (strncmp(msendbuf,"Server> /set_client",19) == 0) {
int nm=atoi(&msendbuf[20]);
currentclient=nm;
ClientSocket=client[nm].cs;
char sockchar[4];
itoa(ClientSocket,sockchar,10);
char sockprint[80];
strcpy(sockprint,"New Socket: ");
strcat(sockprint,sockchar);
printm(sockprint);
char clientprint[80];
strcpy(clientprint,"Client: ");
strcat(clientprint,&msendbuf[20]);
printm(clientprint);
}
if (strncmp(msendbuf,"Server> /list_clients",(strlen(msendbuf))) == 0) {
printm("Clients:",FOREGROUND_RED);
for (int cm=1; cm < 100; cm++) {
int cn=client[cm].cs;
if (cn>0) {
char cli[80];
char cmchar[4];
char cnchar[80];
itoa(cn,cnchar,10);
itoa(cm,cmchar,10);
strcpy(cli,cmchar);
strcat(cli," ");
strcat(cli,cnchar);
strcat(cli," ");
strcat(cli,client[cm].ip.c_str());
strcat(cli," ");
strcat(cli,client[cm].name.c_str());
printm(cli,FOREGROUND_RED);
}
else {
break;
}
}
}
if (strncmp(msendbuf,"Server> /test",(strlen(msendbuf))) == 0) {
char ipcon[500];
*ipcon=(system("ipconfig"));
}
if (strncmp(msendbuf,"Server> /help",(strlen(msendbuf))) == 0) {
printm("Type /help for help or:");
printm("/set_client [client number]");
printm("/list_clients");
}
int iResult3 = send( ClientSocket, msendbuf, 512, 0 );
if (iResult3 == SOCKET_ERROR) {
printm("send failed with error: %d\n", WSAGetLastError());
return 1;
}
}
char* mrecv(bool show) //Recieve a message
{
int iResult2 = recv(ClientSocket, recvbuf, 512, 0);
if (iResult2 > 0) {
if ((strncmp(recvbuf,"/",1)) != 0) {
printm(recvbuf);
}
if (strncmp(recvbuf,"/ip",3) == 0) {
client[clientnumber].ip=&recvbuf[4];
char prin[80];
strcpy(prin,"client[clientnumber].ip: ");
strcat(prin,client[clientnumber].ip.c_str());
printm(prin,FOREGROUND_BLUE);
}
if (strncmp(recvbuf,"/name",5) == 0) {
client[clientnumber].name=&recvbuf[6];
char prin2[80];
strcpy(prin2,"client[clientnumber].name: ");
strcat(prin2,client[clientnumber].name.c_str());
printm(prin2,FOREGROUND_GREEN | FOREGROUND_BLUE);
}
if (strncmp(recvbuf,"/alert",5) == 0) {
char *message=&recvbuf[7];
char prin2[80];
strcpy(prin2,client[clientnumber].name.c_str());
strcat(prin2,": ");
strcat(prin2, message);
printm(prin2,FOREGROUND_RED);
}
if (strncmp(recvbuf,"Client> /alert",14) == 0) {
char *message=&recvbuf[15];
char prin2[80];
strcpy(prin2,client[clientnumber].name.c_str());
strcat(prin2,": ");
strcat(prin2, message);
printm(prin2,FOREGROUND_RED);
}
}
else if (iResult2 == 0) {
printf("Connection closing...\n");
closesocket(ClientSocket);
WSACleanup();
return "1";
}
else {
printm("recv failed with error: %d\n", WSAGetLastError());
printm("Client must have disconnected. Please select a new client.");
return "1";
}
return recvbuf;
}
int minitialize() //initialize the winsock server
{
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printm("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printm("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printm("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printm("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printm("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
unsigned long b=1;
ioctlsocket(ClientSocket,FIONBIO,&b);
}
int mshutdown() //shutdown the server
{
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printm("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
void GoToXY(int column, int line)
{
// Create a COORD structure and fill in its members.
// This specifies the new position of the cursor that we will set.
COORD coord;
coord.X = column;
coord.Y = line;
// Obtain a handle to the console screen buffer.
// (You're just using the standard console, so you can use STD_OUTPUT_HANDLE
// in conjunction with the GetStdHandle() to retrieve the handle.)
// Note that because it is a standard handle, we don't need to close it.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Finally, call the SetConsoleCursorPosition function.
if (!SetConsoleCursorPosition(hConsole, coord))
{
// Uh-oh! The function call failed, so you need to handle the error.
// You can call GetLastError() to get a more specific error code.
// ...
return;
}
}
int scroll( void )
{
HANDLE hStdout;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
SMALL_RECT srctScrollRect, srctClipRect;
CHAR_INFO chiFill;
COORD coordDest;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdout == INVALID_HANDLE_VALUE)
{
printf("GetStdHandle failed with %d\n", GetLastError());
return 1;
}
// Get the screen buffer size.
if (!GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
{
printf("GetConsoleScreenBufferInfo failed %d\n", GetLastError());
return 1;
}
// The scrolling rectangle
srctScrollRect.Top = 1;
srctScrollRect.Bottom = 22;
srctScrollRect.Left = 0;
srctScrollRect.Right = csbiInfo.dwSize.X - 1;
// The destination for the scroll rectangle is one row up.
coordDest.X = 0;
coordDest.Y = 0;
// The clipping rectangle
srctClipRect.Top = 2;
srctClipRect.Bottom = 22;
srctClipRect.Left = 0;
srctClipRect.Right = csbiInfo.dwSize.X - 1;
// Fill the bottom row with blanks.
chiFill.Attributes = FOREGROUND_RED;
chiFill.Char.AsciiChar = (char)' ';
// Scroll up one line.
if(!ScrollConsoleScreenBuffer(
hStdout, // screen buffer handle
&srctScrollRect, // scrolling rectangle
&srctClipRect, // clipping rectangle
coordDest, // top left destination cell
&chiFill)) // fill character and color
{
printf("ScrollConsoleScreenBuffer failed %d\n", GetLastError());
return 1;
}
return 0;
}
int mexit()
{
msend("/server_closed");
mshutdown();
exit(0);
}
Turns out it was the recursive calling in my "sendfunc" thread that tripped me up.
Specifically,
if (msend(msendbuf)==1) {
"Client must have disconnected. Please select a new client.";
sendfunc("1");
}
Because I continued to call "sendfunc" from itself, it caused the stack overflow.
So, for anyone else having these problems, watch for overkill recursive function calls.
I simply removed my sending function and I was good to go.

computing hashValue of a file

Small piece of code I wrote to list files in a dummy directory and then calculate the hash values.
But when I pass the filename to the calc_hash function , program terminates after computing the hash of two files... with error Unhandled exception at 0x77406850 in hashtest3-cpp.exe: 0xC0000005: Access violation writing location 0x64333782.
Can someone please point out the error ....
code snippet::
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <strsafe.h>
#include <string.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#define BUFSIZE 1024
#define MD5LEN 16
//======================================================VARIABLE INITIALIZATION
DWORD Status = 0;
BOOL bResult = FALSE;
ULONG_PTR hProv = 0;
ULONG_PTR hHash = 0;
HANDLE hFile = NULL;
DWORD i;
DWORD j=0;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
LPTSTR filename;
CHAR resultstream[33];
HANDLE hFind;
WIN32_FIND_DATA data;
TCHAR filepath[260] = _T("");
LPWSTR FNAME;
LPWSTR FULLPATH = L"c:\\test\\";
LPWSTR dir = L"c:\\test\\*.*";
LPWSTR DEFAULt = L"";
CHAR rgbDigits[] = "0123456789abcdef";
//=====================================================FUNCTION DECLARATION
void list_files(void);
void calc_hash(void);
//======================================================MAIN START
int main()
{
list_files();
//calc_hash();
getchar();
return 0;
}
//======================================================LISTING FILES IN A DIRECTORY
void list_files()
{
hFind = FindFirstFile(dir, &data);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
StringCchCopy(filepath, 260, DEFAULt);
resultstream[33] = '\0';
DWORD j=0;
FNAME = data.cFileName;
StringCchCat(filepath, 260, FULLPATH);
StringCchCat(filepath, 260, FNAME);
filename = (LPTSTR)filepath;
printf("\n%ws", filename);
/*calc_hash();
getchar();*/
continue;
}while (FindNextFile(hFind, &data));
}
getchar();
}
//======================================================HASH OF A FILE
void calc_hash()
{
hFile = CreateFile(
filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (INVALID_HANDLE_VALUE == hFile)
{
Status = GetLastError();
//printf("\nerror opening file::%d", Status);
goto end;
}
// Get handle to the crypto provider
if (!CryptAcquireContext(
&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
Status = GetLastError();
printf("CryptAcquireContext error:: %d\n", Status);
CloseHandle(hFile);
getchar();
goto end;
}
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
Status = GetLastError();
printf("CryptAcquireContext error:: %d\n", Status);
CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
getchar();
goto end;
}
while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if (0 == cbRead)
{
break;
}
if (!CryptHashData(hHash, rgbFile, cbRead, 0))
{
Status = GetLastError();
printf("CryptHashData error:: %d\n", Status);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
getchar();
goto end;
}
}
//================================GENERATING RESULT=============================
if (!bResult)
{
Status = GetLastError();
printf("ReadFile error:%S:: %d\n",filename, Status);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
getchar();
goto end;
}
cbHash = MD5LEN;
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
printf("MD5 hash of file %ws is:- ", filename);
for (i = 0; i < cbHash; i++)
{
resultstream[j]=rgbDigits[rgbHash[i] >> 4];
j++;
resultstream[j]=rgbDigits[rgbHash[i] & 0xf];
j++;
}
resultstream[j] = '\0';
printf("\n%s", resultstream );
printf("\n");
}
else
{
Status = GetLastError();
printf("CryptGetHashParam error:: %d\n", Status);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CloseHandle(hFile);
end:;
//getchar();
}
The problem is you declare resultstream as
CHAR resultstream[33];
but then you use in your code
resultstream[33] = '\0';
The resultstream array is 0 indexed so valid values are 0-32, you are accessing memory not allocated for that array (hence the "Access violation")

'myfunc' : local function definitions are illegal

i have the following code that works well if it is an win32 console application
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
if( !InitBoard() )
{
return 1;
}
HWND hDialog = 0;
hDialog = CreateDialog (hInst,
MAKEINTRESOURCE (IDD_MAIN),
0,
DialogProc);
if (!hDialog)
{
char buf [100];
wsprintf (buf, "Error x%x", GetLastError ());
MessageBox (0, buf, "CreateDialog", MB_ICONEXCLAMATION | MB_OK);
return 1;
}
#if !defined (_WRITE_MPEG_ )
InitBufferHandling();
StartRTPProcess();
// give vlc some time to get started before shoving buffers at it...
#endif
Sleep(250);
if( !StartAcquisition() )
return 1;
g_hWnd = hDialog;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hDialog, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
BOOL CALLBACK DialogProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
switch (uMessage)
{
case WM_CLOSE:
PostQuitMessage(0);
return FALSE;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
ShutDownAcquisition();
PostQuitMessage(1);
return FALSE;
case IDC_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About);
return TRUE;
default:
break;
}
default:
return FALSE;
}
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
int SelectBoard()
{
DialogBox(hInst, MAKEINTRESOURCE(IDD_SELECT_BOARD), g_hWnd, SelectBoardProc);
return g_SelectedBoard;
}
BOOL CALLBACK SelectBoardProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
switch (uMessage)
{
case WM_INITDIALOG:
{
int nBoards = GetBoardCount();
SelBoard BoardInfo;
char ButtonCaption[64];
int nButtonHeight = 17;
for( int i = 0; i < nBoards; i++ )
{
GetBoardSelection( i, &BoardInfo );
wsprintf( ButtonCaption, "%s %s %s", BoardInfo.szBoardName, BoardInfo.szSerialNumber,
BoardInfo.bClaimed ? "(Busy)" : " " );
CreateWindowEx( 0, TEXT("BUTTON"), ButtonCaption, WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
7, 7 + i*nButtonHeight, 282, nButtonHeight, hDlg, (HMENU)(BOARD_RADIO_1 + i), hInst, 0 );
}
g_SelectedBoard = 0;
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
{
switch (LOWORD(wParam))
{
case BOARD_RADIO_1:
case BOARD_RADIO_1 + 1:
case BOARD_RADIO_1 + 2:
case BOARD_RADIO_1 + 3:
case BOARD_RADIO_1 + 4:
case BOARD_RADIO_1 + 5:
g_SelectedBoard = LOWORD(wParam) - BOARD_RADIO_1;
return TRUE;
break;
case IDOK:
EndDialog(hDlg, LOWORD(wParam));
return FALSE;
}
}
}
return FALSE;
}
i want to convert the above code into an window service so when i does:-
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
StartServiceCtrlDispatcher(ServiceTable);
}
// Service initialization
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
void ServiceMain(int argc, char** argv)
{
int error;
MEMORYSTATUS memory;
char buffer[16];
int result;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
// Initialize Service
error = InitService();
if (error)
{
// Initialization failed
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
// The worker loop of a service
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{void myfunc(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
if( !InitBoard() )
{
return 1;
}
HWND hDialog = 0;
hDialog = CreateDialog (hInst,
MAKEINTRESOURCE (IDD_MAIN),
0,
DialogProc);
if (!hDialog)
{
char buf [100];
wsprintf (buf, "Error x%x", GetLastError ());
MessageBox (0, buf, "CreateDialog", MB_ICONEXCLAMATION | MB_OK);
return 1;
}
#if !defined (_WRITE_MPEG_ )
InitBufferHandling();
StartRTPProcess();
// give vlc some time to get started before shoving buffers at it...
#endif
Sleep(250);
if( !StartAcquisition() )
return 1;
g_hWnd = hDialog;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hDialog, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//return (int) msg.wParam;
if (eventchecking)
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
Sleep(SLEEP_TIME);
}
// return;
}
return;
}
it gives me an error of error C2601: 'myfunc' : local function definitions are illegal
From your second code block:
// The worker loop of a service
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{void myfunc(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
You appear to have suffered a significan cut & paste error, pasting the definition of myfunc into the middle of ServiceMain.
Also look at the end of the code as well:
Sleep(SLEEP_TIME);
}
// return;
}
return;
}
That indenting is a sign of something wrong.
Comment out the following lines from the while loop -
void myfunc(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)

How to inject a DLL into Adobe Reader X

I need to inject a DLL into Adobe Reader X that reads the events sent to the scrollbar (even if it is hidden). I need to do this to be able to find out what page of the document i am on.
I have tried hooking a dll using the win32 hooking API, i give a CBT hook to all processes on the desktop and listen for the creation of the Adobe Reader X window, then hooking this window with my scrollbar hook.
The problem is that i never get the scrollbar hook placed on Adobe Reader X, i dont get the create window or window activate messages for these windows when they are created. How do i get these messages and how do i hook into Adobe Reader X?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "pdfviewlib.h"
#include <sstream>
#pragma data_seg(".PDFVIEWLIB")
PDFVIEWOBJ pdfviewobj[MAX_PDFOBJS] = {NULL};
HHOOK globalhook = NULL;
BOOL debug = TRUE;
INT sSlide = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.PDFVIEWLIB,RWS")
#define DEBUG(...) if(debug) printf(__VA_ARGS__)
HINSTANCE hInstance = NULL;
static int tAttach = 0;
static int tDetach = 0;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
hInstance = (HINSTANCE)hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DEBUG("PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
DEBUG("THREAD_ATTACH %i\n",tAttach++);
break;
case DLL_THREAD_DETACH:
DEBUG("THREAD_DETACH %i\n", tDetach++);
break;
case DLL_PROCESS_DETACH:
// Clean up... hopefully there is only the one process attached?
DEBUG("PROCESS_DETACH\n");
for(int i = 0; i<MAX_PDFOBJS; i++)
ClosePDF(i);
break;
}
return TRUE;
}
DllExport void SetDebug(BOOL onoff)
{
printf("SetDebug\n");
debug = onoff;
DEBUG("enabled\n");
}
//Check if Acrobat Reader is installed
DllExport BOOL CheckInstalled()
{
DEBUG("CheckInstalled\n");
char cmdline[MAX_PATH * 2];
return GetPDFViewerPath(cmdline, sizeof(cmdline));
}
// Open the PDF
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide)
{
STARTUPINFO * si = (STARTUPINFO *) malloc(sizeof(STARTUPINFO));
PROCESS_INFORMATION * pi = (PROCESS_INFORMATION*) malloc(sizeof(PROCESS_INFORMATION));
char cmdline[MAX_PATH * 2];
int id;
sSlide = startSlide;
DEBUG("OpenPDF start: %u", hParentWnd);
//First check if Acrobat Reader is installed before continuing
if(GetPDFViewerPath(cmdline, sizeof(cmdline))==FALSE)
{
DEBUG("OpenPDF: GetPDFTViewerPath failed\n");
return -1;
}
id = -1;
for(int i = 0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].state==PDF_CLOSED)
{
id=i;
break;
}
}
if(id<0)
{
DEBUG("OpenPDF: Too many PDFs\n");
return -1;
}
if (pdfviewobj[id].state == PDF_STARTED)
{
DEBUG("RERUN WHEN PDF_STARTED\n");
return -1;
}
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
strcpy_s(pdfviewobj[id].filename, MAX_PATH, filename);
pdfviewobj[id].state = PDF_CLOSED;
pdfviewobj[id].currentSlide = 0;
pdfviewobj[id].hParentWnd = hParentWnd;
pdfviewobj[id].hWnd = NULL;
pdfviewobj[id].hWnd2 = NULL;
strcat_s(cmdline, MAX_PATH * 2, "\\AcroRd32.exe /n /s /o");
strcat_s(cmdline, MAX_PATH * 2, " \"");
strcat_s(cmdline, MAX_PATH * 2, filename);
strcat_s(cmdline, MAX_PATH * 2, "\"");
si = (STARTUPINFO *)memset(si, 0, sizeof(STARTUPINFO));
pi = (PROCESS_INFORMATION *)memset(pi, 0, sizeof(PROCESS_INFORMATION));
if(globalhook!=NULL){
UnhookWindowsHookEx(globalhook);
DEBUG("Global unhooked\n");
globalhook = NULL;
}
//Set the global hook listening for Window Create/Window Activate messages
globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
if(globalhook==NULL)
{
DEBUG("OpenPDF: Global SetWindowsHookEx failed\n");
DEBUG("ERROR: %X\n", GetLastError());
globalhook = NULL;
ClosePDF(id);
return -1;
}
else DEBUG("GLOBAL HOOKED %X\n", globalhook);
pdfviewobj[id].state = PDF_STARTED;
Sleep(10);
DEBUG(cmdline);
//Run Acrobat Reader, PDF STATE SET TO STARTED
if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, si, pi))
{
DEBUG("OpenPDF: CreateProcess failed\n");
ClosePDF(id);
return -1;
}
pdfviewobj[id].dwProcessId = pi->dwProcessId;
pdfviewobj[id].dwThreadId = pi->dwThreadId;
pdfviewobj[id].hThread = pi->hThread;
pdfviewobj[id].hProcess = pi->hProcess;
//WAIT FOR GLOBAL HOOK TO DETECT Acrobat Windows and set PDF STATE TO PDF_OPENED
//For some reason the loops exits and PDFSTATE is PDF_CLOSED...
while(pdfviewobj[id].state==PDF_STARTED)
Sleep(50);
DEBUG("PDFSTATE == CLOSED = %i \n", pdfviewobj[id].state==PDF_CLOSED);
DEBUG("PDFSTATE == STARTED = %i \n", pdfviewobj[id].state==PDF_STARTED);
DEBUG("PDFSTATE == OPENED = %i \n", pdfviewobj[id].state==PDF_OPENED);
DEBUG("PDFSTATE == LOADED = %i \n", pdfviewobj[id].state==PDF_LOADED);
if (sSlide > 0){
GotoSlide(id, sSlide+1);
}
pdfviewobj[id].state = PDF_LOADED;
DEBUG("OpenPDF Done: id=%i\n", id);
return id;
}
// Get the path of Acrobat Reader X from the registry
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize)
{
HKEY hkey;
DWORD dwtype, dwsize;
LRESULT lresult;
DEBUG("GetPDFViewerPath: start\n");
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Adobe\\Acrobat Reader\\9.0\\InstallPath", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
return FALSE;
dwtype = REG_SZ;
dwsize = (DWORD)strsize;
lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pdfviewerpath, &dwsize );
RegCloseKey(hkey);
if(lresult!=ERROR_SUCCESS)
return FALSE;
DEBUG("GetPDFViewerPath: exit ok \n");
return TRUE;
}
// Unhook the Windows hook
void Unhook(int id)
{
DEBUG("Unhook: start %i\n", id);
if(pdfviewobj[id].hook!=NULL)
UnhookWindowsHookEx(pdfviewobj[id].hook);
pdfviewobj[id].hook = NULL;
DEBUG("Unhook: exit ok\n");
}
// Close the Acrobat Reader, release resources
DllExport void ClosePDF(int id)
{
DEBUG("ClosePDF: start %i\n", id);
if (globalhook != NULL) {
DEBUG("GLOBAL UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook = NULL;
}
else DEBUG("GLOBAL NOT UNHOOKED\n");
pdfviewobj[id].state = PDF_CLOSED;
Unhook(id);
if(pdfviewobj[id].hWnd==0)
TerminateThread(pdfviewobj[id].hThread, 0);
else
PostMessage(pdfviewobj[id].hWnd, WM_CLOSE, 0, 0);
CloseHandle(pdfviewobj[id].hThread);
CloseHandle(pdfviewobj[id].hProcess);
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
DEBUG("ClosePDF: exit ok\n");
return;
}
// Return the number of the slide currently viewing
DllExport int GetCurrentSlide(int id)
{
DEBUG("GetCurrentSlide:%d\n", id);
if(pdfviewobj[id].state==0)
return -1;
else
return pdfviewobj[id].currentSlide;
}
// Take a step forwards through the show
DllExport void NextStep(int id)
{
DEBUG("NextStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
}
// Take a step backwards through the show
DllExport void PrevStep(int id)
{
DEBUG("PrevStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
}
// Go directly to a slide
DllExport void GotoSlide(int id, int slideno)
{
//TODO: USE SETSCROLLINFO
}
// This hook is started with the AcroRd32.EXE process and waits for the WM_CREATEWND message.
// Release the hook as soon as we're complete to free up resources
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HHOOK hook = globalhook;
DEBUG("HOOK: %X\n", hook);
if (nCode < 0) {
return CallNextHookEx(hook, nCode, wParam, lParam);
}
else if(nCode==HCBT_CREATEWND)
{
DEBUG("CREATE WINDOW \n");
char csClassName[16];
char csCaptionName[16];
HWND hCurrWnd = (HWND)wParam;
DWORD retProcId = NULL;
GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
GetWindowText(hCurrWnd, csCaptionName, sizeof(csCaptionName));
if((strcmp(csClassName, "AcrobatSDIWindow")==0)
||(strcmp(csClassName, "AVL_AVView")==0))
{
DEBUG("%s found \n", csClassName);
int id=-1;
DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
break;
}
}
if(id>=0)
{
DEBUG("Matched threadid!\n");
if(strcmp(csClassName, "AVL_AVView")==0){
if (strcmp(csCaptionName, "AVPageView")==0){
pdfviewobj[id].hWnd2=hCurrWnd;
}
}
else
{
pdfviewobj[id].hWnd=hCurrWnd;
CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
if(pdfviewobj[id].hParentWnd!=NULL)
cw->lpcs->hwndParent = pdfviewobj[id].hParentWnd;
}
if((pdfviewobj[id].hWnd!=NULL)&&(pdfviewobj[id].hWnd2!=NULL))
{
pdfviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pdfviewobj[id].dwThreadId);
if (pdfviewobj[id].hook != NULL) {
DEBUG("Global UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook=NULL;
pdfviewobj[id].state = PDF_OPENED;
}
Sleep(10);
}
}
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
CWPSTRUCT *cwp;
cwp = (CWPSTRUCT *)lParam;
HHOOK hook = NULL;
DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
int id=-1;
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
hook = pdfviewobj[id].hook;
break;
}
}
if((id>=0)&&(nCode==HC_ACTION))
{
DEBUG("CBT HC_ACTION\n");
if(cwp->message==SBM_SETSCROLLINFO)
{
DEBUG("CBT SBM_SETSCROLLINFO\n");
SCROLLINFO *scrInf;
scrInf = (SCROLLINFO *)cwp->lParam;
pdfviewobj[id].currentSlide = scrInf->nPos;
}
if((pdfviewobj[id].state != PDF_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT)){
pdfviewobj[id].state = PDF_CLOSING;
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
heres the header if you need it
#define DllExport extern "C" __declspec( dllexport )
enum PDFVIEWSTATE { PDF_CLOSED, PDF_STARTED, PDF_OPENED, PDF_LOADED, PDF_CLOSING};
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide);
DllExport BOOL CheckInstalled();
DllExport void ClosePDF(int id);
DllExport int GetCurrentSlide(int id);
DllExport void NextStep(int id);
DllExport void PrevStep(int id);
DllExport void GotoSlide(int id, int slideno);
DllExport void SetDebug(BOOL onoff);
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize);
void Unhook(int id);
//MAXUMUM NUMBER OF PDF-PROCESSES CURRENTLY SET TO ONE
#define MAX_PDFOBJS 1
struct PDFVIEWOBJ
{
HHOOK hook;
HWND hWnd;
HWND hWnd2;
HWND hParentWnd;
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
int currentSlide;
char filename[MAX_PATH];
PDFVIEWSTATE state;
};
Adobe Reader typically runs in protected mode. (See Edit/Preferences/Security (Enhanced). Un-check the "Enable Protected Mode at startup" checkbox.
Relaunch reader and see if you get your messages. You should. The issue is that the User Interface Privilege Isolation (UIPI) disallows many windows messages from crossing process boundaries between processes running at a different integrity level (low/medium/high). You are supposed to be able to change the windows message filter via ChangeWindowMessageFilterEx().
I am currently experiencing issues with Adobe Reader Xi where the ChangeWindowsMessageFilter and ChangeWindowMessageFilterEx do not seem to change the behavior of Adobe reader sending messages to the global hook receiver in the hooking process. I have copied noteapad.exe to notepad2.exe and lowered its integrity level to low via: icacls notepad2.exe /setintegritylevel low
(run from an elevated cmd prompt (i.e. run as admin)). When I do this my hooking works fine (using ChangeWindowMessageFilterEx()) but still does not get hooked messages from Adobe.
Also, Reader is 32-bit so make sure you are hooking it from a 32-bit hooking process otherwise you won't see messages either).

Resources