📜 ⬆️ ⬇️

Interaction of processes (applications) on WinApi

Now on the Internet you can meet many Hello Worlds on WinApi, but when a novice asks how to add a couple of necessary functions to this Hello World, they throw rotten apples on them and immediately send them to the notorious and powerful MSDN.

In this article from a beginner to beginners, I will tell you how to build two simple applications that will interact with each other - one will take the parameters of a geometric progression as input and pass it to the second one, the second application will calculate the nth member of the progression, write it to a file and pass the answer to the first application.

image

So, let's go (Gagarin).
')
With the fact that we need we have already decided in the introduction, we will develop in Visual Studio 2008, as it was the only one lying on the university server.

We create a project with an empty Application A project, and in it we will create a wrapper to simplify the creation of a window (this wrapper will be needed in another project, and you may also need it in the future).

----------- kWnd.h --------------------
#include <windows.h> class kWnd { public: kWnd(LPCTSTR windowName, HINSTANCE hInst, int cmdShow, LRESULT(WINAPI *pWndProc)(HWND, UINT, WPARAM, LPARAM), LPCTSTR menuName = NULL, int x = CW_USEDEFAULT, int y = 0, int width = CW_USEDEFAULT, int height = 0, UINT classStyle = CS_HREDRAW | CS_VREDRAW, DWORD windowStyle = WS_OVERLAPPEDWINDOW, HWND hParent = NULL); HWND GetHWnd() {return hWnd;} protected: HWND hWnd; WNDCLASSEX wc; }; 



----------- kWnd.cpp --------------------
 KWnd.cpp #include "KWnd.h" kWnd::kWnd(LPCTSTR windowName, HINSTANCE hInst, int cmdShow, LRESULT (WINAPI *pWndProc)(HWND,UINT,WPARAM,LPARAM), LPCTSTR menuName, int x, int y, int width, int height, UINT classStyle, DWORD windowStyle, HWND hParent) { char szClassName[] = "KWndClass"; wc.cbSize = sizeof(wc); wc.style = classStyle; wc.lpfnWndProc = pWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = menuName; wc.lpszClassName = szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); //    if (!RegisterClassEx(&wc)) { char msg[100] = "Cannot register class: "; strcat(msg, szClassName); MessageBox(NULL, msg, "Error", MB_OK); return; } //   hWnd = CreateWindow(szClassName, windowName, windowStyle, x, y, width, height, hParent, (HMENU)NULL, hInst, NULL); if (!hWnd) { char text[100] = "Cannot create window: "; strcat(text, windowName); MessageBox(NULL, text, "Error", MB_OK); return; } //   ShowWindow(hWnd, cmdShow); } 


Although the article is for beginners, we will not dwell on the description of the process of creating a window, since there is plenty of this information on the Internet.

Next, we need to add a dialog box to the resource file:

Resource Files-> Application A.rc -> Add Resource-> Dialog

It should look something like this:

image

Let's start coding.

Application A.cpp
 #include <windows.h> #include <stdio.h> #include "resource.h" #include "kWnd.h" #define MYDISPLAY 1 char a1[100]; char razn[100]; char colvo[100]; int i; int n = 0; int summ = 0; typedef struct tagMYREC { char a1[100]; char razn[100]; char colvo[100]; char n[100]; char summ[100]; } MYREC; COPYDATASTRUCT MyCDS; MYREC MyRec; PCOPYDATASTRUCT pMyCDS; BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //======================================================================= int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; kWnd mainWnd("Application A", hInstance, nCmdShow, WndProc, MAKEINTRESOURCE(IDR_MENU1), 100, 100, 450, 150); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } //======================================================================= LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInst; switch(uMsg) { case WM_CREATE: DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DialogProc); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } BOOL CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND hwndServer; WIN32_FIND_DATA FindFileData; HANDLE hFile; switch(uMsg) { case WM_INITDIALOG: hwndServer = FindWindow(NULL, "Application B"); if(!hwndServer) { hFile = FindFirstFile("Application B.exe", &FindFileData); WinExec("Application B.exe", 1); FindClose(hFile); } break; case WM_COPYDATA: pMyCDS = (PCOPYDATASTRUCT) lParam; SetDlgItemText(hDlg, IDC_EDIT4, (LPCSTR)((MYREC *)(pMyCDS->lpData))->n); SetDlgItemText(hDlg, IDC_EDIT5, (LPCSTR)((MYREC *)(pMyCDS->lpData))->summ); return true; case WM_COMMAND: switch(LOWORD(wParam)) { case IDEXIT: EndDialog(hDlg, 0); PostQuitMessage(0); case IDOK: GetDlgItemText(hDlg, IDC_EDIT1, MyRec.a1, 22); GetDlgItemText(hDlg, IDC_EDIT2, MyRec.razn, 22); GetDlgItemText(hDlg, IDC_EDIT3, MyRec.colvo, 22); hwndServer = FindWindow(NULL, "Application B"); if(!hwndServer) { MessageBox(hDlg, " !", "Application A", MB_OK); break; } MyCDS.dwData = MYDISPLAY; MyCDS.cbData = sizeof( MyRec ); MyCDS.lpData = &MyRec; SendMessage( hwndServer, WM_COPYDATA, (WPARAM)(HWND) hDlg, (LPARAM) (LPVOID) &MyCDS ); break; return TRUE; } } return FALSE; } 



Interesting and interesting moments will be considered separately.

 typedef struct tagMYREC { char a1[100]; char razn[100]; char colvo[100]; char n[100]; char summ[100]; } MYREC; COPYDATASTRUCT MyCDS; MYREC MyRec; PCOPYDATASTRUCT pMyCDS; 


Here we declare the data structure that we send and the necessary structures:
  COPYDATASTRUCT MyCDS -  ,     . MYREC MyRec -     . PCOPYDATASTRUCT pMyCDS -  (  ). 


Next comes a check whether the second application is running, if not, then the program starts it.
  case WM_INITDIALOG: hwndServer = FindWindow(NULL, "Application B"); if(!hwndServer) { hFile = FindFirstFile("Application B.exe", &FindFileData); WinExec("Application B.exe", 1); FindClose(hFile); } 


Next, we pack the data into our structure.
  GetDlgItemText(hDlg, IDC_EDIT1, MyRec.a1, 22); GetDlgItemText(hDlg, IDC_EDIT2, MyRec.razn, 22); GetDlgItemText(hDlg, IDC_EDIT3, MyRec.colvo, 22); 


Correctly fill the structure of the transmitted data and send it to another application:
  MyCDS.dwData = MYDISPLAY; //  MyCDS.cbData = sizeof( MyRec ); //    MyCDS.lpData = &MyRec; //    SendMessage( hwndServer, WM_COPYDATA, //      //    (WPARAM)(HWND) hDlg, (LPARAM) (LPVOID) &MyCDS ); //   COPYDATASTRUCT  


That's all - not any checks on whether the fields are filled in and whether they are filled correctly, we will not do in this article.

Now let's proceed to Appendix B. The first two files, kWnd.h and kWnd.cpp, remain unchanged. The application itself, we will build no longer on the basis of the dialog box, but on the basis of pure hardcore.

Application B.cpp
 #include <windows.h> #include <stdio.h> #include "kWnd.h" #include "resource.h" #define MYDISPLAY 1 PCOPYDATASTRUCT pMyCDS; //    int i; int a1; int razn; int colvo; int n = 0; int summ = 0; char str[100], str1[100], str2[100], str3[100], str4[100]; //     DWORD dwSize; HANDLE File; //   typedef struct tagMYREC //   { char a1[100]; char razn[100]; char colvo[100]; char n[100]; char summ[100]; } MYREC; COPYDATASTRUCT MyCDS; MYREC MyRec; //=============== =================== LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //===================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { MSG msg; //   kWnd mainWnd("Application B", hInstance, nShowCmd, WndProc, NULL, 100, 100, 450, 220); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } //===================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInst; HDC hdc; //   PAINTSTRUCT ps; //   //        HWND hwndServer; static HANDLE hThreadA; ThreadManager* pTm; WIN32_FIND_DATA FindFileData; HANDLE hFile; HWND edit; char buff[260]; switch(uMsg) { case WM_CREATE: hwndServer = FindWindow(NULL, "Application A"); if(!hwndServer) { hFile = FindFirstFile("Application A.exe", &FindFileData); WinExec("Application B.exe", 1); FindClose(hFile); } edit = CreateWindow("EDIT","text.txt", //  WS_CHILD | WS_VISIBLE |WS_BORDER, 10, 10, 50, 20, hWnd, (HMENU) 123, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE), NULL); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 100, 50, " :", sizeof(" :")); TextOut(hdc, 120, 80, str1, sizeof(str1)); TextOut(hdc, 120, 100, str2, sizeof(str2)); TextOut(hdc, 120, 120, str3, sizeof(str3)); TextOut(hdc, 50, 140, str4, sizeof(str4)); EndPaint(hWnd, &ps); break; case WM_COPYDATA: pMyCDS = (PCOPYDATASTRUCT) lParam; //  n-    a1 = atol(((MYREC *)(pMyCDS->lpData))->a1); razn = atol(((MYREC *)(pMyCDS->lpData))->razn); colvo = atol(((MYREC *)(pMyCDS->lpData))->colvo); n = a1; summ = a1; for(int i = 0; i<colvo-1; i++) { n = n * razn; summ = n + summ; } sprintf(((MYREC *)(pMyCDS->lpData))->n, "%d", n); sprintf(((MYREC *)(pMyCDS->lpData))->summ, "%d", summ); hwndServer = FindWindow(NULL, "Application A"); if(!hwndServer) { MessageBox(hWnd, " !", "Application B", MB_OK); break; } strcpy(MyRec.n, ((MYREC *)(pMyCDS->lpData))->n); strcpy(MyRec.summ, ((MYREC *)(pMyCDS->lpData))->summ); MyCDS.dwData = MYDISPLAY; MyCDS.cbData = sizeof( MyRec ); // size of data MyCDS.lpData = &MyRec; // data structure SendMessage( hwndServer, WM_COPYDATA, (WPARAM)(HWND) hWnd, (LPARAM) (LPVOID) &MyCDS ); sprintf(str1, "  : %s", ((MYREC *)(pMyCDS->lpData))->a1); sprintf(str2, " : %s", ((MYREC *)(pMyCDS->lpData))->razn); sprintf(str3, "   : %s", ((MYREC *)(pMyCDS->lpData))->colvo); //       edit = FindWindowEx(hWnd, NULL, "Edit", NULL); SendMessage(edit, WM_GETTEXT, (WPARAM)260, (LPARAM)buff); sprintf(str, "  = %s,  = %s, n = %s,   = %s,  = %s\n\r", ((MYREC *)(pMyCDS->lpData))->a1, ((MYREC *)(pMyCDS->lpData))->razn, ((MYREC *)(pMyCDS->lpData))->colvo, MyRec.n, MyRec.summ); //      File=CreateFile(buff, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); SetFilePointer(File, 0, 0, FILE_END); //     WriteFile(File,&str,sizeof(str),&dwSize,NULL); sprintf(str4, "   : %s", buff); InvalidateRect(hWnd, NULL, TRUE); break; case UM_THREAD_DONE: pTm = (ThreadManager*)wParam; sprintf(str1, "%s: count = %d", pTm->name, pTm->nValue); InvalidateRect(hWnd, NULL, FALSE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } //===================================================== 


Vooot, this long file does all the hard work - accepts a message, calculates (in multithreaded mode (not surprised, it was one of the items of the task)), writes, sends back.

Here from the interesting points worth noting the reception of data in the event:
  pMyCDS = (PCOPYDATASTRUCT) lParam; //       

Further to the received data you can reach for example like this:
  a1 = atol(((MYREC *)(pMyCDS->lpData))->a1) 


The rest of the techniques of this file are not interesting and boring for us, then there follows a calculation of the progression and sending it by the same method to the first process.

And that's what happened with us:

image

image

I really hope that my article was useful to someone and I apologize very much to those who did not like it. Waiting for comments on the code (govnokod).

Source: https://habr.com/ru/post/149299/


All Articles