1

I apologize for the length of the question, but I believe it is difficult to understand the “why” without the background.

Background: I have two applications running in a Windows Embedded Standard 7 environment. They should be the only two applications running on the machine. One, called “Controller”, is written in C++ the other, “DBconnector”, is written in c#. This is not new code. It has been in active use and development for almost 20 years.

The purpose of the software is to run a manufacturing machine for producing parts. These machines are big and dangerous if the program crashes. Long ago, I discovered that if the network went down for some reason, all the threads in the application would stall – not just the network thread. This was disastrous since leaving the controller in a state with the wrong relays on in extremely rare circumstances could cause the machine to literally explode. Note: Several things have been added to the software and hardware to prevent this now. While this danger doesn’t really exist anymore, stability is still extremely important. I never want the operator to be stuck in a state where they can’t hit the reset button. My solution at the time was to move the networking tasks into a separate application. The OS was windows XP based at the time. I have no idea if the problem still exists in windows 10 since I really don’t want to rewrite hundreds of thousands of lines of code to try and merge the two programs now.

The development of the two programs diverged such that the one that controlled the machine, Controller, was designed for extreme stability and the other, DBconnector, was where dangerous things like networking and most file I/O happened. Communication between the two programs is facilitated using a memory mapped file that they both can access. I have no problem sharing window handles or process id’s or any other data that might be needed between the two programs.

Here is my question. How can I make the Controller application display the GUI of DBconnector? For example, I have started to add functionality to Controller that requires DBconnector to display the quality control sheets that are held on a web site on company servers. I want for an operator to be able to pull up the quality control sheet directly on the machine. The operator currently only interacts with the Controller application. I don’t want Controller to be able to access the network. Also, C# has some tools to make displaying a web page easy. It seems to me that the place to do this is DBconnector. The problem is that DBconnector runs in the background and cannot currently be seen or accessed by a user. So, the question is how to solve this.

First option I have tried is to tell DBconnector to come forward and put Controller in the background. Then, when the user is done, Controller comes back to the front. I have made this to work using some hacks, but it is inconsistent. The trick I used was to minimize and then maximize DBconnector which seems to bring it to the front most of the time and try to hold focus on one or the other. There still might be a way to do it this way, but it needs to be something that is consistent.

The second option is to run the DBconnector application inside of one of Controller’s windows. I have no idea how to do this. I thought about using ATL or COM, but I think these run as threads within Controllers process rather than as a separate application.

The third option I’ve considered is to create a window inside Controller that intercepts and passes all user input messages directly to Dbconnector using a windows message handle and takes a screenshot of DBconnector whenever the it is invalidated and passes it through the memory mapped file. Currently, this is what I am swaying towards.

Are there any suggestions on how to do the first and last option better, or how to do the second option at all, or another solution that I have missed? Keep in mind that our current hardware is running Windows Embedded Standard 7. The project is currently in visual studio 2015. The C++ window technology is MFC implemented using libraries originally from around 2003 I think. DBconnector is in .NET framework 4 in C#.

acronos
  • 11
  • 2
  • "“Controller”, is written in C++" Native C++ or C++ .NET? I asume the former, but it is best never to asume. Wich of the half dozen frontend technologies have you used for teh C# programm? WinForms, WPF/UWP, ASP.Net, Console, other? – Christopher Sep 19 '19 at 19:31
  • 1
    My best advise is to partially rewrite this whole thing. Maybe you can fold them into one programm? Maybe you can create a a seperate UI-only programm, that the other two communicate with via another approach of IPC? You can still keep their own UI for emergency reasons. Sockets/Pipes are pretty common these days and allow you to bridge any language barrier. Even Java/Assembler, if you ever need to. – Christopher Sep 19 '19 at 19:35
  • Beyond that I can only point you to those two articles on proper exception handling, that might help you with such a big project/point out some issues you might have overlooked: https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/ | https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET – Christopher Sep 19 '19 at 19:36
  • Christopher - Yes Controller is Native C++. Sorry I was not more specific. DBconnector is WinForms. Controller is close to just UI already. The bug in communicating with sockets was why I split the program in the first place. I really should go back and check if that bug still exists. I have just enjoyed the ability of dbconnector to crash if it needs to and restart or just die and controller just keeps on going. The two articles were interesting. At first I thought they were unrelated, but then I saw how they were really about design principles. Thanks – acronos Sep 20 '19 at 15:59
  • "I have just enjoyed the ability of dbconnector to crash if it needs to and restart or just die and controller just keeps on going." I never heard of DBConnector "crashing". At worst it could throw out a exogenous exception, wich is one of the few you are actually supposed to handle. But my normal advise is to use "Create, Use, Dipose - all in the same piece of code." Ideally in a using block. That way the code never has much room to mess up, time out, etc. – Christopher Sep 20 '19 at 16:09
  • I guess I should clarify that it has been a long time since DBconnector "crashed". However, there are situations where I request it to restart when the network goes down and that sometimes puts it in an unstable state. This pretty much only happens during stress testing. – acronos Sep 20 '19 at 17:23
  • My goal is to make this system self maintaining running 24 hrs a day for years without any user intervention. And the ability of one part to fail without bringing the rest down makes the system even more stable from the users perspective. Then, for instance, when the network comes back on the system automatically recovers and uploads the data that was stored during the event. The user never even knows. I can't account for everything, but there are currently many ways the system can fail gracefully without interfering with the core functionality. – acronos Sep 20 '19 at 17:29
  • If a DBConnector class locks up, just dispose it and re-create it. That is if you even kept it open in the first place (wich again, you should not do). Create. Use. Dispose. All in the same piece of code, ideally using a using block. If there is any connection pooling and similar performance work to be done, the class has to do that Automagically. – Christopher Sep 23 '19 at 10:24
  • I believe you have a misconception. DBconnector is an application. It is running in a separate process not a separate thread. It is not a class in Controller. Controller must not stall or have anything happen to it since it directly controls the machine. The point of DBconnector is to place things that can stall, think network connections and disk I/O, into its own application so these actions cannot affect Controller. Reread my background section for why it didn't work just to put it in a different thread. – acronos Sep 24 '19 at 14:58
  • I believe I may have made the question too broad. I probably should have only asked about option 2 since it is the only one I don't know how to implement. There are already posts here on how to do option 1. The question was this broad because I really wanted the communities opinion on better ways to do this - ideally without starting over. – acronos Sep 24 '19 at 15:06
  • I think this is a case where there is just too much acreted Technical Debt, to avoid a rework. https://www.youtube.com/watch?v=L5NfbpLmMHI – Christopher Sep 24 '19 at 15:57
  • Maybe. But, I think the design decisions were made for good reasons that are still valid. The separation has been valuable and continues to be valuable. I would rather not add features that increase functionality if the price of those features is stability. This is not a desktop app. It is an appliance. The existing software is not bug ridden. It is extremely stable. I have not had a single bug in controller in literally years. That is not true for DBconnector, and that is the point. I get what you are saying. I just don't agree in this case. – acronos Sep 24 '19 at 20:00
  • I guess what I am saying is that the design may restrict future features, but that is a worthwhile trade off to me if the core functionality of running the machine is perfect. I appreciate your advise. I truly do, and I understand your position. Think of my code like a service or server with a separate client application. That is what I've build except the client can run completely stand alone if the server is unavailable. For now, I will scrap the new features until or unless I can make option 3 or 1 work perfectly. – acronos Sep 24 '19 at 20:11

0 Answers0