Created
November 10, 2016 21:46
-
-
Save TheVice/3aae5d453bc79fde13c844e0877e6575 to your computer and use it in GitHub Desktop.
Instance limiter (WIN32) - threre was a task to make library that control count of app count on local PC and via local network. As reference used https://msdn.microsoft.com/en-us/library/windows/desktop/ms686701(v=vs.85).aspx (local PC) and https://web.archive.org/web/20140131015856/http://www.xakep.ru/magazine/xa/048/087/1.asp (work with sockec…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 2.8.12) | |
project("test_task") | |
# library | |
set(library_root ${CMAKE_CURRENT_SOURCE_DIR}/library) | |
file(GLOB_RECURSE SRC_Files ${library_root}/*.h ${library_root}/*.c ${library_root}/*.cpp) | |
add_library(library SHARED ${SRC_Files}) | |
# demo_stand-alone | |
set(demo_stand-alone_root ${CMAKE_CURRENT_SOURCE_DIR}/demo_stand-alone) | |
file(GLOB_RECURSE SRC_Files ${demo_stand-alone_root}/*.h ${demo_stand-alone_root}/*.c ${demo_stand-alone_root}/*.cpp) | |
add_executable(demo_stand-alone WIN32 ${SRC_Files}) | |
target_link_libraries(demo_stand-alone library) | |
# demo_network | |
set(demo_network_root ${CMAKE_CURRENT_SOURCE_DIR}/demo_network) | |
file(GLOB_RECURSE SRC_Files ${demo_network_root}/*.h ${demo_network_root}/*.c ${demo_network_root}/*.cpp) | |
add_executable(demo_network ${SRC_Files}) | |
target_link_libraries(demo_network library) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "../library/library.h" | |
#include <tchar.h> | |
int _tmain(int argc, _TCHAR *argv[]) | |
{ | |
if (argc > 1) | |
{ | |
onThreadCreateAtNetwork(argv[1]); | |
} | |
else | |
{ | |
onThreadCreateAtNetwork(nullptr); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "../library/library.h" | |
#include <windows.h> | |
#include <tchar.h> | |
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) | |
{ | |
(void)hInstance; | |
(void)hPrevInstance; | |
(void)lpCmdLine; | |
(void)nCmdShow; | |
// | |
onThreadCreate(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "library.h" | |
#include <windows.h> | |
#include <TlHelp32.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
#pragma comment(lib, "WSock32") | |
static const long gMaxInstanceCount = 2; | |
static long gInstanceCount = 0; | |
static char gModulePath[MAX_MODULE_NAME32 + 1]; | |
bool isModulesLoadByProcess(DWORD pid) | |
{ | |
HANDLE processSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); | |
if (processSnap == INVALID_HANDLE_VALUE) | |
{ | |
return false; | |
} | |
MODULEENTRY32 me32; | |
memset(&me32, 0, sizeof(me32)); | |
me32.dwSize = sizeof(me32); | |
if (!Module32First(processSnap, &me32)) | |
{ | |
CloseHandle(processSnap); | |
return false; | |
} | |
do | |
{ | |
if (!lstrcmpA(gModulePath, me32.szExePath)) | |
{ | |
CloseHandle(processSnap); | |
return true; | |
} | |
} while (Module32Next(processSnap, &me32)); | |
CloseHandle(processSnap); | |
return false; | |
} | |
void listProcess() | |
{ | |
HANDLE processSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); | |
if (processSnap == INVALID_HANDLE_VALUE) | |
{ | |
return; | |
} | |
PROCESSENTRY32 pe32; | |
memset(&pe32, 0, sizeof(pe32)); | |
pe32.dwSize = sizeof(pe32); | |
if (!Process32First(processSnap, &pe32)) | |
{ | |
CloseHandle(processSnap); | |
return; | |
} | |
do | |
{ | |
if (pe32.th32ProcessID == 0) | |
{ | |
continue; | |
} | |
gInstanceCount += isModulesLoadByProcess(pe32.th32ProcessID) ? 1 : 0; | |
} while (Process32Next(processSnap, &pe32)); | |
CloseHandle(processSnap); | |
} | |
void fillModulePath() | |
{ | |
STARTUPINFO startupInfo; | |
memset(&startupInfo, 0, sizeof(startupInfo)); | |
startupInfo.cb = sizeof(startupInfo); | |
GetStartupInfo(&startupInfo); | |
char* lastSlash = strrchr(startupInfo.lpTitle, '\\'); | |
if (lastSlash) | |
{ | |
size_t length = lastSlash - startupInfo.lpTitle + 1; | |
strncpy(gModulePath, startupInfo.lpTitle, length); | |
strcat(gModulePath, "library.dll"); | |
} | |
else | |
{ | |
sprintf(gModulePath, "%s\\library.dll", startupInfo.lpTitle); | |
} | |
} | |
__declspec(dllexport) void __stdcall onThreadCreate() | |
{ | |
fillModulePath(); | |
listProcess(); | |
TCHAR message[MAX_PATH]; | |
if (gInstanceCount <= gMaxInstanceCount) | |
{ | |
_stprintf(message, TEXT("There is a %ld hinstance of a program.\r\nTo stop current hinstance press OK button below."), gInstanceCount); | |
MessageBox(HWND_DESKTOP, message, TEXT("demo_stand-alone"), MB_OK); | |
} | |
else | |
{ | |
_stprintf(message, TEXT("Reached maximum count of application instances - %ld.\r\nPress OK to exit."), gMaxInstanceCount); | |
MessageBox(HWND_DESKTOP, message, TEXT("demo_stand-alone"), MB_ICONWARNING); | |
} | |
} | |
//#define PRINT_NET_STATIC 1 | |
void client(const char* address, char command) | |
{ | |
BOOL allow = -1; | |
int err = 0; | |
WSADATA wsaData; | |
if (!(err = WSAStartup(MAKEWORD(2, 0), &wsaData))) | |
{ | |
SOCKADDR_IN rmaddr; | |
memset(&rmaddr, 0, sizeof(rmaddr)); | |
rmaddr.sin_addr.s_addr = inet_addr(address); | |
rmaddr.sin_family = AF_INET; | |
rmaddr.sin_port = htons(7766); | |
SOCKET send_sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (INVALID_SOCKET != send_sock) | |
{ | |
err = connect(send_sock, (struct sockaddr *)&rmaddr, sizeof(rmaddr)); | |
if (SOCKET_ERROR != err) | |
{ | |
char message[2 + sizeof(long)]; | |
int length = sizeof(message) / sizeof(*message); | |
if ('a' == command) | |
{ | |
sprintf(message, "a%d", gInstanceCount + 1); | |
err = send(send_sock, message, length, 0); | |
if (SOCKET_ERROR != err) | |
{ | |
err = recv(send_sock, message, length, 0); | |
if (SOCKET_ERROR != err) | |
{ | |
if ('1' == message[0]) | |
{ | |
#ifdef PRINT_NET_STATIC | |
fprintf(stdout, "Allow"); | |
#endif | |
gInstanceCount = atol(&message[1]); | |
allow = TRUE; | |
} | |
else | |
{ | |
#ifdef PRINT_NET_STATIC | |
fprintf(stdout, "Not allow"); | |
#endif | |
allow = FALSE; | |
} | |
} | |
else | |
{ | |
fprintf(stderr, "recv failed with error: %d\n", err); | |
} | |
} | |
else | |
{ | |
fprintf(stderr, "send failed with error: %d\n", err); | |
} | |
} | |
else if ('-' == command) | |
{ | |
sprintf(message, "-"); | |
err = send(send_sock, message, length, 0); | |
if (SOCKET_ERROR == err) | |
{ | |
fprintf(stderr, "send failed with error: %d\n", err); | |
} | |
Sleep(500); | |
} | |
} | |
else | |
{ | |
fprintf(stderr, "Unable to established connection with: %s (error %i)\n", address, err); | |
} | |
} | |
else | |
{ | |
fprintf(stderr, "socket failed with error: %lld\n", send_sock); | |
} | |
WSACleanup(); | |
} | |
else | |
{ | |
fprintf(stderr, "WSAStartup failed with error: %d\n", err); | |
} | |
TCHAR message[MAX_PATH]; | |
if (TRUE == allow) | |
{ | |
_stprintf(message, TEXT("There is a %d hinstance of a program.\r\nTo stop current hinstance press OK button below."), gInstanceCount); | |
MessageBox(HWND_DESKTOP, message, TEXT("demo_stand-alone"), MB_OK); | |
Sleep(500); | |
client(address, '-'); | |
} | |
else if (!allow) | |
{ | |
_stprintf(message, TEXT("Reached maximum count of application instances - %d.\r\nPress OK to exit."), gMaxInstanceCount); | |
MessageBox(HWND_DESKTOP, message, TEXT("demo_stand-alone"), MB_ICONWARNING); | |
} | |
} | |
void server() | |
{ | |
int err = 0; | |
WSADATA wsaData; | |
if (!(err = WSAStartup(MAKEWORD(2, 2), &wsaData))) | |
{ | |
SOCKET listet_sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (INVALID_SOCKET != listet_sock) | |
{ | |
SOCKADDR_IN addr_sock; | |
memset(&addr_sock, 0, sizeof(addr_sock)); | |
addr_sock.sin_family = AF_INET; | |
addr_sock.sin_addr.s_addr = htonl(INADDR_ANY); | |
addr_sock.sin_port = htons(7766); | |
if (bind(listet_sock, (LPSOCKADDR)&addr_sock, sizeof(struct sockaddr))) | |
{ | |
fprintf(stderr, "Unable to bind to socket"); | |
return; | |
} | |
if (listen(listet_sock, 1)) | |
{ | |
fprintf(stderr, "Unable to listen socket"); | |
return; | |
} | |
while (true) | |
{ | |
SOCKET send_sock = accept(listet_sock, nullptr, nullptr); | |
if (INVALID_SOCKET == send_sock) | |
{ | |
fprintf(stderr, "socket failed with error: %lld\n", send_sock); | |
break; | |
} | |
while (true) | |
{ | |
char message[2 + sizeof(long)]; | |
int length = sizeof(message) / sizeof(*message); | |
err = recv(send_sock, message, length, 0); | |
if ((SOCKET_ERROR == err) || (0 == err)) | |
{ | |
err = WSAGetLastError(); | |
break; | |
} | |
if ('a' == message[0]) | |
{ | |
#ifdef PRINT_NET_STATIC | |
sockaddr s; | |
length = sizeof(s); | |
if (SOCKET_ERROR != getpeername(send_sock, &s, &length)) | |
{ | |
fprintf(stdout, "%s have %s\n", inet_ntoa(((sockaddr_in*)(&s))->sin_addr), &message[1]); | |
} | |
#endif | |
long lMessage = atol(&message[1]); | |
if (gInstanceCount + lMessage <= gMaxInstanceCount) | |
{ | |
sprintf(message, "1%d", gInstanceCount + lMessage); | |
} | |
else | |
{ | |
sprintf(message, "0"); | |
} | |
err = send(send_sock, message, length, 0); | |
if (SOCKET_ERROR == err) | |
{ | |
fprintf(stderr, "send failed with error: %d\n", err); | |
} | |
else | |
{ | |
if (gInstanceCount + lMessage <= gMaxInstanceCount) | |
{ | |
gInstanceCount += lMessage; | |
} | |
} | |
} | |
else if ('-' == message[0]) | |
{ | |
if (gInstanceCount > 0) | |
{ | |
--gInstanceCount; | |
} | |
} | |
} | |
shutdown(send_sock, 1); | |
closesocket(send_sock); | |
} | |
} | |
else | |
{ | |
fprintf(stderr, "socket failed with error: %lld\n", listet_sock); | |
} | |
WSACleanup(); | |
} | |
else | |
{ | |
fprintf(stderr, "WSAStartup failed with error: %d\n", err); | |
} | |
} | |
__declspec(dllexport) void __stdcall onThreadCreateAtNetwork(const char* server_address) | |
{ | |
if (nullptr == server_address) | |
{ | |
server(); | |
} | |
else | |
{ | |
client(server_address, 'a'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __LIBRARY_H__ | |
#define __LIBRARY_H__ | |
__declspec(dllexport) void __stdcall onThreadCreate(); | |
__declspec(dllexport) void __stdcall onThreadCreateAtNetwork(const char* server_address); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment