Hello,
I created a docker for X7 with two buttons.
It works fine. (Thanks to bonus630. Great project).
Please could you explain or point me to other previous topic about :
1. How to check from other application if the docker is installed?
2. How to start or close the docker from other application?
3. How to press one of the buttons from other application?
Thank you in advance
When you say 'other application' can it be any type of application?
For instance, in the next VBS code, you can see how to solve the first two issues. Of course, you must know the docker guide.... In the following example I use my docker guide.
If the guide does not belong to any installed docker the code does not return any error... You can find the guide in AppUI.xslt: (in bonus630 47 line): check="*Docker('f3f09ab3-a8b6-4400-9152-62ffbe93ecb5')"
dim drawApp, Found Set drawApp = CreateObject("CorelDraw.Application") drawApp.Framework.ShowDocker "f3f09ab3-a8b6-4400-9152-62ffbe93ecb5" if drawApp.FrameWork.IsDockerVisible("f3f09ab3-a8b6-4400-9152-62ffbe93ecb5") = true then msgbox "Docker installed" Found = true else msgbox "Docker not installed" end if if Found then drawApp.FrameWork.HideDocker "f3f09ab3-a8b6-4400-9152-62ffbe93ecb5" set drawApp = nothing
Pressing the buttons is a little more difficult...
Glad to see you figuring up 'scenario;..
if 'ServerFlagFileName' keeps only a flag I think is easier to use registry. The VBA for using it is simple:
MyFlag = GetSetting("MyMacroName", "Settings", "Flag", "Something to be returned when the registry key was not created, yet")
The flag is loaded: SaveSetting "MyMacroName", "Settings", "Flag", "1" or "0"
And you can use it from the helper application, too...
Yes I am interested in seeing your helper X# code. Any code is interesting at least for the sake of learning...
I am keeping the file as flag because it can be set from other machine easy.
The helper can be started from other machine too.
The main part of the helper code is:
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.IO;
using System.Diagnostics;
using System.Management;
using Microsoft.Win32;
using Corel.Interop.VGCore;
using System.Runtime.InteropServices.ComTypes;
namespace StartCorelWorker
{
partial class Program
//===========================================================================================================
static Boolean SetDefaultClientConfiguration()
CorelDRAW.Application app = new CorelDRAW.Application();
app.Visible = true;
String serverGUID = "533768c9-af16-4144-ba3e-520abed3fa47";
String clientGUID = "a2b2f5fc-defb-4371-88ab-7ce0ed8cb054";
app.FrameWork.HideDocker(serverGUID);
app.FrameWork.ShowDocker(clientGUID);
Boolean rt = app.FrameWork.IsDockerVisible(clientGUID);
app.Quit();
app = null;
GC.Collect();
GC.WaitForPendingFinalizers();
System.Windows.Forms.Application.DoEvents();
return rt;
}
//------------------------------------------------------------------------------------
static int KillAllCorelrProcess()
Process currentProcess = Process.GetCurrentProcess();
String oname = GetProcessOwner(currentProcess.Id);
try
for (int ntries = 0; ntries < 10; ntries++)
int sumproc = 0;
Process[] localByName = Process.GetProcessesByName("CorelDRW");
for (int i = 0; i < localByName.GetLength(0); i++)
String oname1 = GetProcessOwner(localByName[i].Id);
if (oname == oname1)
sumproc++;
localByName[i].Kill();
System.Threading.Thread.Sleep(100);
if (sumproc == 0)
AppendToLog("All proceses are killed");
return 0;
AppendToLog("Error in proceses killing");
catch (Win32Exception w)
AppendToLog(w.ToString());
return -1;
//===================== MAIN =============================================================
static void Main(string[] args)
KillAllCorelrProcess();
SetDefaultClientConfiguration();
Int32 numberworkers = Convert.ToInt32(args[0]);
Process curproc = Process.GetCurrentProcess();
Int32 ncorels = 0;
foreach (Process pr in localByName)
if (GetProcessOwner(curproc.Id) == GetProcessOwner(pr.Id))
ncorels++;
for (Int32 nc = ncorels; nc < numberworkers; nc++)
Process cpr = StartNewCorelWorker();
// Check for file existance flag to start server docker
String exitfile = "RunAsServer.txt";
if (File.Exists(exitfile))
SetDistributor();
//------------------------------------------------ SUBS ------------------------------------------------------------------------
static String GetProcessOwner(int processId)
String query = "Select * From Win32_Process Where ProcessID = " + processId;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
foreach (ManagementObject obj in processList)
String[] argList = new String[] { "", "" };
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
// return DOMAIN\user
return argList[1] + "\\" + argList[0];
catch (Exception e)
return "NO OWNER";
static Process StartNewCorelWorker()
IntPtr hwnd;
Process threads = new Process();
threads.StartInfo.FileName = "C:\\Program Files\\Corel\\CorelDRAW Graphics Suite X7\\Programs64\\Coreldrw.exe";
threads.StartInfo.Arguments = "";
// if (!System.IO.File.Exists(threads.StartInfo.Arguments))
// return null;
threads.StartInfo.UseShellExecute = false;
threads.StartInfo.RedirectStandardOutput = true;
threads.Start();
// wait for Corel to start different windows
int i;
for (i = 0; i < 2000; i++)
System.Threading.Thread.Sleep(10);
hwnd = FinddWindowByProcess("CorelDRAW17", threads.Id);
if (hwnd != IntPtr.Zero)
goto started;
threads.Kill();
// AppendToLog("error - could not start for 20 secs. Kill it.");
return null;
started:
//Guid("bde248ef-64f4-409d-a7c8-7157afa4eb7e")
//Menubar-f3016f3c-2847-4557-b61a-a2d05319cf18
IntPtr Menubar;
Menubar = FindChildWindow(hwnd, "Menubar-f3016f3c-2847-4557-b61a-a2d05319cf18");
if (Menubar != IntPtr.Zero)
goto started2;
started2:
IntPtr menuitem = FindChildWindow(hwnd, "3eaa9bbe-28fd-4672-9128-02974ee96332");
IntPtr Toolbar;
Toolbar = FindChildWindow(hwnd, "Toolbar-7c905e2a-cb64-4ba1-aff0-c306f392680c");
if (Toolbar != IntPtr.Zero)
goto started3;
started3:
//view+docker-a2b2f5fc-defb-4371-88ab-7ce0ed8cb054
//HwndWrapper[DefaultDomain;;cb384a41-6164-42cb-af02-31b6ffd8f2bf]
IntPtr workerwnd;
workerwnd = FindChildWindow(hwnd, "a2b2f5fc-defb-4371-88ab-7ce0ed8cb054");
if (workerwnd != IntPtr.Zero)
goto started4;
started4:
return threads;
There are not updated code parts but the idea can be understood. The code with common calls to WIN32 API is skipped too.
Thanks for share it!
But I must confess I do not understand too much...
I can not see the communication (client - server) part and I just try to suppose what it really does. When you name client (or server) docker should I understand that at a specific time the client docker and server docker will be connected? And they will send and receive packets for and from each other? Or you use only the helper application like communication interface?
I also did not understand too much about the real need/scope of this project... From what I (think I) understood, I would structure this project in the next way:
1. The helper should listen on a specific port and after connection it will only start corel application. At request it will check if corel application process is running and if not it will be started again... Besides that it will be able to show a specific docker of the running corell application, in case of all of them are hidden.
2. The client (server) docker will be a real client (server) able to make connections clients - server. The sequence of which docker will be firstly opened or closed will be handled inside corel by the docker itself helped only by corel built events. I mean if the docker needed to be secondly shown is by mistake made visible, it will commit suicide and a specific corel event will open (it, them) again in the right sequence. They will directly communicate changing packets between each other. In this way clicking the buttons you put in discussion in your initial post is easy and all the necessary information to be changed will be done without help of anything else. The docker status (hide, visible) is directly transmitted and directly controlled from one docker to the other (placed on different computers). The single need for helper is in the moment when any (client, server) docker is hidden and necessary to be shown. The docker must also be able to show one or both of them in the necessary sequence at the server request. The server already informed by the docker that it became hidden... If the helper is installed only on computers having client docker even simpler...
Am I missing something?
Corel is able to work with two parallel sessions or more (if computer has enough resources). Do you intend to use this corel facility? I mean I try to understand the ' static int KillAllCorelrProcess()' method... Killing corel process instead of quitting from inside corel is not good enough, I think. I just suppose that on computer with the client docker is there somebody working... Is all process automated and no need of computer operator? Otherwise all the changes in documents or VBA (if any) will be lost.
Without seeing the whole project it is difficult to understand and help more...
I wish you happy holidays!
1. Application.Quit works very well but from the moment of running the code in about 6-7 seconds Corel Grafic Interface is closed and corel works like background process for other 20 - 35 seconds according to your number of gms files. After doing whatever is necessary to start well next time the process is really closed. You cand catch this closing in the MacroStorage QueryQuit event and do there whatever you need... I do not know what GC from the next lines means... GC.Collect(); GC.WaitForPendingFinalizers();
2. Why starting of many sessions of CorelDraw would be a chalange?
3. Do you mean that Corel multiple sessions are hidden, working in background in order to allow to 'other logged user to work simultaneously'?
4. Why is that so useful? You are able to know when corel is loaded from its own events. Am I wrong?
5. Even like virtual question the problem could easily be solved between two connected client-server dockers. If communication between dockers is not so important why do you need client, respectively, server dockers? I have a problem now with my Visual Studioa 2013 installation and I'm trying to repair it. Repair operation is stacked in the same point... I will figure it up. Even if I will reinstall it, but like final solution because it takes a lot of time... I would like to look at your project if available. If you decide to send it please use my public email on my profile... Have a nice time! P.S. Are you from Bulgaria? I dared to guess looking to your login name... I'm asking that in order to know if a Good night is appropriate. I am from Romania...
1. Your code should definitely work. You only must take in consideration the necessary time for Corel to properly close. Working with many instances could also be a RAM loading behavior. Maybe you would take in consideration to clear memory later... Do you need stopping them all at once?
2. You may be right putting the problem in this way, but speaking about client-server application maybe it is just enough to run CorelDraw.exe and each docker could send back the instance handler on its Loaded event or even at constructor initialization (hWnd = app.AppWindow.Handle;)...
3. Not working in background processes, how could "user2" work there? I mean working in Corel... With all the other windows loosing focus? What resources do that computers have? In terms of RAM and CPU.
4. Events are easily understandable. For instance you are able to subscribe a QueryQuit event similar with the one from VBA:
//inside constructor: app.QueryQuit += doWhateverYouNeed; private void doWhateverYouNeed(ref bool Cancel) { //do whatever //if you wont to make corel wait until doing something you make //Cancel = true, do the job an after that cancel... MessageBox.Show("BY!"); }
All events of VBA are available in app (for documentNew, documentOpen, PageChange, etc...)
5. Use it in order to send information from inside Corel in order to simplify helper job...
Have a nice day Watson!
1. I still believe that the most 'controlled manner' is the native Quit of the application. On my taste, it is just a matter of being patient. But, de gustibus not discutando...
2. As you wont...
I think Windows allows creation of more than one instance... It depends on how the application has been built. If my application firstly check if another instance is already running and do something according to this check keeps from the application 'habit', I think. For instance, the next two VBScripts are basically written on the same idea, but works different because of Excel Application against Corel Application:
dim drawApp, drApp Set drawApp = CreateObject("CorelDraw.Application"): drawApp.Visible = true set drApp = CreateObject("CorelDraw.Application"): drApp.Visible = true msgbox drApp.appWindow.Handle msgbox drawApp.appWindow.Handle set drawApp = nothing: set drApp = nothing
You will receive the same Handle...
dim E, E1, E2 set E = CreateObject("Excel.Application"): E.Visible = true set E1 = CreateObject("Excel.Application"): E1.Visible = true set E2 = CreateObject("Excel.Application"): E1.Visible = true msgbox E.Hwnd msgbox E1.Hwnd msgbox E2.Hwnd
Here you will receive three apWindow Handles... Excel will really open three sessions! In order to find the open existing session (first time) you must use:
Set E = GetObject(, "Excel.Application")
This is what I firstly tried for Corel (on my first post) but it did not work. I am rather skilled in VBA Excel. I started playing with Corel VBA much more after Excel...
I am used to look for the simplest way of accessing. Now I still do not have VS and can play only with that toys... I am almost sure that this approach works the same in C#, too. Maybe for Corel nobody built a simple tool for simple task. The prove that Windows accept multiple instances is the fact that you manually can open such multiple instances running the exe file. We just must find the most convenient way to do that. For me the most convenient way looks to be just running the exe file, receiving back the corel Window handle and based on that controlling each docker. But it may be not the best solution since I do not know which is the use of that....
3. OK. Understood...