📜 ⬆️ ⬇️

Using the KOMPAS-3D API → Lesson 3 → Correct connection to KOMPAS

In previous lessons on the API KOMPAS (We remind you that C ++ Builder is used as the medium) Basics and Drawing Design, we assumed that KOMPAS was not running, and started it ourselves using the CreateInstance method. But what if at the time of calling this method, KOMPAS is already running? Then another copy of this program will be created. In principle, nothing terrible, but sloppy. Why produce copies of the program when you can get by with one copy?



Today we will talk about how to connect to an already running KOMPAS, so as not to create a picture similar to the one shown in the figure below.


Several copies of KOMPAS-3D launched
')

Connection to COMPASS


To connect to the KOMPAS program, use the ActiveInstance method. Below is an example of a program connecting to KOMPAS.

KompasObjectPtr kompas; kompas.ActiveInstance(L"KOMPAS.Application.5"); //   kompas->Visible = true; kompas.Unbind(); 

The only parameter of the ActiveInstance method is the string name of the interface to which we are connecting, in Unicode encoding.

And what will happen if at the moment of calling this method KOMPAS is not running? An error will occur. And the user will be shown immediately two windows with expletives.


The first error window


Second error window

The format of these windows depends on the development environment used and may differ from the above. Wrapping a call to the ActiveInstance method in a try / catch block , unfortunately, does not solve the problem.

 try{ KompasObjectPtr kompas; kompas.ActiveInstance(L"KOMPAS.Application.5"); //   kompas->Visible = true; kompas.Unbind(); }catch(...){} 

We get rid of only one error window. It turns out that you can call the ActiveInstance method only when KOMPAS is running. And here we come to the main question: how to determine whether COMPASS is launched or not? There are several methods for this.

By main window


The most common way is to find the main program window using the FindWindow function. The FindWindow function searches for a window by its title or by the name of its window class. Unfortunately, it requires exact match strings. She does not know how to search by part of the string
We cannot use the window title, since it includes a version of KOMPAS, which is unknown to us in advance, and additional information, for example, the name of the open document. Therefore, we can not know for sure the exact line in the window title. Let's try on the name of the window class.

You can find it using Spy ++ . The figure below shows approximate information about the window class (the name is circled in a red rectangle).


Window Properties Window

The names of the window class are not only not very illustrative, they are also different in different versions of KOMPAS. Therefore, a search by the name of the window class also does not suit us.

The only thing we can somehow rely on is the presence of the KOMPAS-3D substring in the header of the main window. But the FindWindow function cannot search by substring. The only thing left for us to do is to go through all the top-level windows and check if the title of any of them contains the substring “COMPASS-3D”. Below is the source code of the procedure that performs this check.

 //      bool CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { //    unsigned int size; size = GetWindowTextLength(hwnd); if(!size) return true; //     wchar_t* pbuffer; pbuffer = (wchar_t*)malloc(sizeof(wchar_t)*(size+1)); //   GetWindowTextW(hwnd, pbuffer, size-1); //  wchar_t *p; p = wcsstr(pbuffer, L"-3D"); //  free(pbuffer); if(!p) return true; // ,      bool *pres; pres = (bool*)lParam; *pres = true; return false; } //    ? bool IsKOMPASRun() { bool res = false; EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)(&res)); return res; } 

To list the windows, use the EnumWindows function, which is part of the Windows API. This function prepares a list of top-level windows and for each found window calls the custom function EnumWindowsProc . In this function, we read the title of the found window and check if it contains the substring "KOMPAS-3D". If it does, then the window is found and stop the search, if not - go to the next window. The following is an example of using this procedure.

 if(IsKOMPASRun()) ShowMessage(" "); else ShowMessage("  "); 

Unfortunately, this method is very unreliable. The fact is that there may be other windows in the system containing the substring "COMPAS-3D" in its header. An example of such a window is shown in Figure 4. This is clearly not the window that we want to find.


Help window

According to the process


Another option is to search for the KOMPAS process. The program KOMPAS executable file is usually referred to as "kompas.exe" (in different versions may differ in case). What if, instead of a window, to look for a process with such an executable file name? Below is the source code of the program that implements this method.

 bool IsKOMPASRun() { //  ,    char ExeName[] = "kompas.exe"; size_t lenName = strlen(ExeName); //   HANDLE hSnapshot; hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //  PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); Process32First(hSnapshot, &entry); size_t len; bool res = false; do{ //    len = strlen(entry.szExeFile); if(len != lenName) continue; if(!strnicmp(entry.szExeFile, ExeName, len)) { res = true; break; } }while(Process32Next(hSnapshot, &entry)); CloseHandle(hSnapshot); return res; } 

This example uses the CreateToolhelp32Snapshot , Process32First , Process32Next functions included in the Windows API to list the processes. To use them, you must connect the header file tlhelp32.h . This is not the only way to list processes, but one of the easiest. To compare strings, use the strnicmp function, which compares case-insensitive strings.

The process based on searching processes is more reliable than searching windows. It gives significantly fewer false positives, but does not exclude them. What if a program with exactly the same name of the executable file is running on the user's computer? Or in future versions of KOMPAS, the executable file will be called differently? In all these cases, this method does not work.

Using COM technology


All the methods described above are cumbersome and unreliable. Therefore, their use is undesirable. There is a more reliable way to check the fact of launching the KOMPAS program. It is based on the functions of the library ole32.dll , which is part of Windows and implements COM technology. Below is the source code of the procedure that checks with these functions whether KOMPAS is running.

 bool IsKOMPASRun() { wchar_t ObjectName[] = L"KOMPAS.Application.5"; //  Ole32.dll CoInitialize(NULL); CLSID clsid; // clsid  CLSIDFromProgID(ObjectName, &clsid); //  HRESULT res; IUnknown *pIUnknown; res = GetActiveObject(clsid, NULL, &pIUnknown); if(res == S_OK) { pIUnknown->Release(); return true; } return false; } 

The main work is performed by the GetActiveObject function. With her help, we are trying to connect to KOMPAS. If this succeeds, then KOMPAS is running. The CLSIDFromProgID function is used to convert a string representation of an object into its CLSID (a unique 128-bit identifier ). It can be used to check whether KOMPAS is installed on the user's computer or not. Below is an example of a program that implements such a test.

 bool IsKOMPASInstalled() { wchar_t ObjectName[] = L"KOMPAS.Application.5"; //  Ole32.dll CoInitialize(NULL); CLSID clsid; // clsid  HRESULT res; res = CLSIDFromProgID(ObjectName, &clsid); return (res == S_OK); } 

Correct connection


Below is the source code of the program that implements the correct connection to KOMPAS.

 wchar_t ObjectName[] = L"KOMPAS.Application.5"; …………………………………………………………… if(! IsKOMPASInstalled()) { ShowMessage("  "); return; } KompasObjectPtr kompas; if(IsKOMPASRun()) kompas.ActiveInstance(ObjectName); else kompas.CreateInstance(ObjectName); kompas->Visible = true; kompas.Unbind(); 

The ObjectName variable is declared global to avoid its duplication in different functions.

Conclusion
This article examined various methods for determining whether KOMPAS is running or not. You can use any of these methods or a combination of them. Or maybe invent your method. The most reliable method is based on the GetActiveObject function.

At the end of the article there is an example of a program implementing a connection to KOMPAS with a check for its presence in the system and operation at the time of launching the program.

The fourth part .

Sergey Norseev, author of the book “Development of applications for KOMPAS in Delphi”.

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


All Articles