Roland Weigelt

Born to Code

  • Emaroo: How to Get Visual Studio Code’s New Icon

    Emaroo is a free utility for browsing most recently used (MRU) file lists of programs like Visual Studio, Word, Excel, PowerPoint and more. Quickly open files, jump to their folder in Windows Explorer, copy them (and their path) to the clipboard - or run your own tools on the MRU items! And all this with just a few keystrokes or mouse clicks.

    Emaroo vs. Icons

    The May 2019 update for Visual Studio Code (version 1.35) features a new application icon. After installing the update, Emaroo will continue to use the old icon, though.

    20190606_VSCodeBefore

    This is because Emaroo caches the icons of executables (as well as those of MRU files and folders) for a faster startup.

    To get the new icon, switch to the “settings” page…

    20190606_Settings

    …and click “Refresh icons” in the bottom right corner:

    20190606_RefreshIcons

    Confirm you want to restart Emaroo…

    20190606_Restart

    …and the new icon (which is not exactly dramatically different) will appear after Emaroo has refreshed the icons:

    20190606_VSCodeAfter

  • Interesting Read: The future UWP

    Morton Nielsen wrote an article called “The future UWP” about the situation for desktop UI development in the Microsoft technology stack which I found very interesting.

    The main takeaways (not actually surprising):

    • A lot is happening/changing/developing and it will take some time until the future really becomes clear.
    • Quote: “Whether you do WPF, WinForms or UWP, if it works for you now, continue the course you’re on”

    Personally, I’ll stay with WPF for my desktop UIs. When .NET Core 3 comes out, I’ll dip a toe into porting my applications.

  • Emaroo 4.4 – Support for Visual Studio 2019

    Emaroo is a free utility for browsing most recently used (MRU) file lists of programs like Visual Studio, VS Code, Word, Excel, PowerPoint, Photoshop, Illustrator and more. Quickly open files, jump to their folder in Windows Explorer, copy them (and their path) to the clipboard - or run your own tools on files and folders with custom actions!

    About this Release

    • Added: Support for Visual Studio 2019.
    • Added: The “run or read” feature (Ctrl+R) now also supports “.lnk” files.
      Fixed: Single files not appearing in Visual Studio Code’s MRU list.
  • Design/UI/UX-Praxiswissen für Entwickler in Köln und Nürnberg

    Am 10. Mai 2019 halte ich auf der dotnet Cologne 2019 einen Vortrag mit dem Namen “Kochrezepte für pragmatisches GUI-Design”.

    Am 26. und 27. Juni bin ich in Nürnberg auf der Developer Week 2019. Am 26. Juni ebenfalls mit “Kochrezepte für pragmatisches GUI-Design”, am Tag darauf folgt dann der ganztägige Workshop “Von Null auf GUI – Design/UI/UX-Praxiswissen für Entwickler”.

    Abstracts

    Kochrezepte für pragmatisches GUI-Design

    • Wie entscheidet man, was man sich von anderen GUIs abschauen sollte - und was nicht?
    • Wie stellt man Daten in Formularen und Detailansichten geeignet dar, wenn man von der Fachlichkeit eigentlich keine Ahnung hat?
    • Wie bändigt man GUIs mit vielen Funktionen?
    • Wie sorgt man dafür, dass Anwender sich nicht von der GUI "ausgebremst" fühlen?

    Diese und weitere Fragen beantwortet Roland Weigelt in seinem Vortrag. Am Beispiel konkreter Lösungsansätze bietet er einen generellen Einstieg in eine abstrakte und doch praxisorientierte Denkweise in "User Interface Patterns". Roland greift dabei auf seine langjährige Erfahrung in der Produktentwicklung zurück, wo Pragmatismus und Weitsicht gleichermaßen gefragt sind.

    Von Null auf GUI – Design/UI/UX-Praxiswissen für Entwickler

    Überall dort, wo kein ausgewiesener UI-/UX-Spezialist zur Verfügung steht, ist es umso wichtiger, dass auch Software-Entwickler grundlegende Kenntnisse in diesem Thema haben. Sei es, um die UI einer typischen Business-Anwendung von "schlimm" nach "brauchbar" zu verbessern. Oder auch, um eine informierte Entscheidung treffen zu können, was man sich von anderen UIs abschaut.

    In diesem Workshop vermittelt Roland Weigelt Entwicklern ohne jegliche UI/UX-Vorkenntnisse Gestaltungsprinzipien des visuelles Designs, User Experience-Grundlagen sowie das Denken in User Interface Patterns. Und das stets mit einem Blick darauf, was in der Praxis mit begrenztem Budget machbar und tatsächlich hilfreich ist.

    Vortragsteile und praktische Übungen wechseln sich ab, um das Erlernte in Einzel- und Gruppenarbeiten direkt vertiefen zu können.

    Für diesen Workshop sind von Teilnehmerseite her keine Vorbereitungen notwendig. Einfach hinkommen, zuhören, mitmachen, Spaß haben und viel lernen.

    Anmeldung

    • dotnet Cologne 2019: Die Anmeldung startet am 20. März um 12:00. Die Kölner Community-Konferenz wird wie in den letzten Jahren wohl wieder in wenigen Minuten ausgebucht sein – kein Wunder bei Preisen von 35,- bis 65,- Euro für Privatpersonen bzw. 139,- Euro für Firmentickets.
    • Developer Week 2019: Die Anmeldung ist bereits möglich, bis zum 9. April gelten noch Frühbucherpreise.
  • Emaroo 4.3.2 – Support for VS Code 1.32

    Emaroo is a free utility for browsing most recently used (MRU) file lists of programs like Visual Studio, VS Code, Word, Excel, PowerPoint, Photoshop, Illustrator and more. Quickly open files, jump to their folder in Windows Explorer, copy them (and their path) to the clipboard - or run your own tools on files and folders with custom actions!

    About this Release

    • Updated: Support for Visual Studio Code 1.32 (changes regarding of most recently used folders/workspaces). Previous versions of Visual Studio Code are still supported.
      Fixed: The MRU list for Notepad++ remained empty if the configuration file config.xml is not a valid XML file. This problem was already (kind of) addressed in 4.0.0, but now Emaroo performs a more thorough cleanup of the XML file. To be clear: Emaroo only reads the file, it does not write to it at any point. The file corruption is caused by Notepad+++ itself, which doesn't seem to have problems with it.
      Fixed: Custom actions without any file or directory macros for the currently selected MRU item did not work if the MRU list was empty.
  • How to Approach Problems in Development (and Pretty Much Everywhere Else)

    When you plan a feature, write some code, design a user interface, etc., and a non-trivial problem comes your way, you have more or less the following options:

    • Attack – invest time and effort, give it all to make it happen, no matter what!
    • Sneak around – identify alternative options, or find a way to drastically limit the scope to reduce the amount of work.
    • Postpone – do nothing and wait until a later point in time; if the problem hasn’t become irrelevant by then, you know that it’s worth to be dealt with.
    • Don’t do it – sometimes you have to make the hard decision to not do something.

    As obvious as this seems to me now that these options exist: When I look back at my younger self more than twenty years ago, fresh from university, I was all about attacking problems head-on, because problem-solving was fun! Which sometimes lead to me spending too much energy at the wrong location, at the wrong time. In this blog post I try to write down some words of wisdom which my younger self may have found useful – maybe it helps somebody else out there.

    Do a minimum of research

    You want to work on the problem, you are eager to write code, but hold on for a second. Don’t dive into it head first. Always imagine a meeting in the future where one of the following questions is asked:

    • “What exactly do you know about the problem?”
    • “What have other people done so far?”
    • “Are there samples/libraries/frameworks? What can we at least learn from them?”
    • And of course the killer question: ”Why didn’t you think for a second about X?” (with “X” being super-obvious in your context)

    You definitely want to know as early as possible about critical obstacles, e.g.

    • the only choice for an algorithm for your envisioned approach has exponential complexity,
    • you require hardware performance that your target system simply cannot provide,
    • you have nowhere near enough pixel space in your user interface to display an envisioned feature, or
    • your application only makes sense if your users behave in a completely unrealistic way in the actual usage context.

    if you don’t do anything else, gain at least a basic understanding what you don’t know. You can deal with a “known unknown” on a meta-level, prioritize it, think of possible risks, talk to other people about it. An “unknown unknown”, on the other hand, can sneak up to you and hit you at the worst possible moment.

    Do not confuse means and ends

    As developers, we’re problem solvers – that is a good thing. But it sometimes makes us concentrate on the means (i.e. the technical solution to the problem) instead of the ends (what exactly do we want to achieve?). We all know these situations in meetings where no progress is made until somebody broadens the focus.

    Be that somebody and ask: In which way does solving that one specific problem contribute to the overall goal? And: Is this the easiest way to achieve the desired result?

    Think of the (in)famous “sword fight” scene from Raiders of the Lost Ark: Indiana Jones is facing a bad guy with a sword. Indy, on the other hand, does not have sword. With a narrow focus on the problem of not being able to participate in a (deadly) sword-fighting competition, finding a sword would be the next step. But the actual goal, though, is to get rid of the attacker as quickly and with as little risk as possible – which can be achieved by shooting the bad guy with a gun.

    Here’s a real-life example that I often present in my UI/UX talks:

    My software for the LED advertising system in the local sports arena uses pixel shaders for controlling the brightness of the displayed images and videos. The UI consists of a slider (0-100%) which I move until the apparent LED brightness looks right for the lighting in the arena (which is not constant due to necessary warm-up/down-down phases of the old lamps).

    It was very easy to modify the pixel shaders to influence opacity or displacement of pixels, which gave me the idea for smooth transitions between different content sources for the LEDs. My first choice for the UI: the same as for the brightness, a slider. Copy/paste, simple as that. And from a UI point of view, using a slider promised full flexibility in regard to timing and dynamics of the transition. But what was the actual goal? Perform a smooth transition to the next image or video to be shown. For that, flexibility was much less of a concern than consistency and reliability. And that could be achieved with a simple “Next” button that triggered a transition with a fixed duration of 0.5 seconds.

    Tackle problems as early as necessary, as late as possible

    How do you decide which problem to be solved first? Of course, if one problem depends on a solution for another, that dictates a specific order. Often enough, tough, you have a certain freedom to choose.

    If that is the case, ask yourself whether you have to solve a specific problem now. If you postpone working on something that is more or less isolated, there’s always a chance that priorities change. Something that was essential to reaching a specific goal suddenly becomes obsolete because the goal no longer exists.

    On the other hand, be careful when delaying work, especially if you don’t know much about possible challenges. If part “A” of a system depends on part “B”, young developers like to work “bottom up”, first building “B” into a nice foundation that will make things easier when it comes to working on “A” (I have been there, too). But you definitely want to avoid a situation where the thing that was supposed to use your framework has known or unknown “unknowns“ that turn out to be insurmountable obstacles. So better make sure to have a working proof of concept and work from there.

    This is related to the conflict between the (deliberately) very narrow scope of work items, tasks, user stories, etc. on one hand, and the question when the broader architecture of a system should be planned and implemented. Possible approaches range from BDUF (big design up front) in an almost “waterfall” fashion up to doing only the absolute minimum at a given time combined with continuous refactoring whenever needed. The truth is somewhere in between.

    The secret is to find the right balance between…

    • You ain’t gonna need it (YAGNI): Do not implement things when you just foresee that you need them. For example: extension points in your software that later are never used (but have to be maintained nevertheless). Or architectures with swappable components on a fine-grained level – if you’re not 100% sure that this is vital for the success of the software.

    …and…

    • Do it or get bitten in the end (DOGBITE): While you can get away with not doing something for a long time (all in with the best intentions of delivering value to the user of your application), postponing some work items can really come at a high cost. For example, if you want to have an undo-redo feature in your finished product. In theory, you could add that with a refactoring at a later time. In practice, good luck with getting the budget for stopping all feature work for weeks of refactoring late in the development.

    In my experience, consider YAGNI as the rule, but don’t use it as “kill all”. Missing a DOGBITE situation is bad and will haunt you for years.

    Ask yourself:

    • Do you have a rough idea how you would add a feature at a certain point? If yes, that’s good enough, don’t add code as a preparation.
    • Are you doing things now that actively prevent adding a feature in the future, or at least make that very expensive? Try to avoid that whenever possible.
    • If you consider something DOGBITE, would you be able to defend it if somebody would grill you on that? You better be, because that’s what will happen at some point.

    Heed the universal truths

    • Everything is more complicated than it appears at first sight. If it doesn’t, you haven’t asked the right questions yet.
    • Truly generic, reusable solutions are hard. First get the job done, then (maybe) think about reuse.
    • “Good enough” is perfectly fine most of the time.
    • Leaving things out is usually the better choice than adding too much up front. Once something (an API, a feature or some UI) is in your software, removing it will make somebody unhappy.

    One more thing…

    The Wikipedia article comparing the Amundsen and Scott Expeditions is very interesting. You’ll quickly understand why I mention it here.

  • WPF with Web API and SignalR – Why and How I Use It

    Preface: This blog post is less about going deep into the technical aspects of ASP.NET Core Web API and SignalR. Instead it’s a beginner’s story about why and how I started using ASP.NET Core. Maybe it contains bits of inspiration here and there for others in a similar situation.

    The why

    Years ago, I wrote a WPF application that manages media files, organizes them in playlists and displays the media on a second screen. Which is a bit of an understatement, because that “second screen” is in fact mapped onto the LED modules of a perimeter advertising system in a Basketball arena for 6000 people.

    Unfortunately, video playback in WPF has both performance and reliability problems, and a rewrite in UWP didn’t go as planned (as mentioned in previous blog posts). Experiments with HTML video playback, on the other hand, went really well.

    At this point, I decided against simply replacing the display part of the old application with a hosted browser control. Because my plans for the future (e.g. synchronizing the advertising system with other LED screens in the arena) already involved networking, I planned the new software to have three separate parts right from the beginning:

    1. A server process written in C#/ASP.NET Core for managing files and playlists. For quick results, I chose to do this as a command line program using Kestrel (with the option to move to a Windows service later).
    2. A (non-interactive) media playback display written in TypeScript/HTML, without any framework. By using a browser in kiosk mode, I didn’t have to write an actual “display application” – but I still have the option to do this at a later time.
    3. A C#/WPF application for creating and editing playlists, starting and stopping media playback, which I call the cockpit. I chose WPF because I had a lot of existing code and custom controls from the old application that I could reuse.

    The how: Communication between server, cockpit and display

    For communication, I use Web API and SignalR.

    Not having much prior experience, I started with the “Use ASP.NET Core SignalR with TypeScript and Webpack” sample and read the accompanying documentation. Then I added app.UseMvc() in Startup.Configure and services.AddMvc in Startup.ConfigureServices to enable Web API. I mention this detail because that was a positive surprise for me. When learning new technologies, I sometimes was in situations where I had created an example project A and struggled to incorporate parts of a separate example project B.

    For quick tests of the Web API controllers, PostMan turned out to be a valuable tool.

    Before working on “the real thing”, I read up on best practices on the web and tried to follow them to my best knowledge.

    Web API

    I use Web API to

    • create, read, update or delete (“CRUD”) lists of “things”
    • create, read, update or delete a single “thing”

    In my case, the “things” are both meta data (playlists, information about a media file, etc.) as well as the actual media files.

    Side note: I wrote about my experiences serving video files in my post “ASP.Net Core: Slow Start of File (Video) Download in Internet Explorer 11 and Edge”.

    SignalR

    While I use Web API to deal with “things”, I use SignalR for “actions”:

    • I want something to happen
    • I want to be notified when something happens.

    Currently the server distinguishes between “display” and “cockpit” roles for the communication. In the future, it’s likely I will have more than one “cockpit” (e.g. a “remote control” on a mobile device) – and more roles when the application grows beyond simple media playback only one display. Using the SignalR feature of groups, the clients of the server receive only those SignalR messages they are interested in as part of their role(s).

    Example

    When I select a video file in the “cockpit”, I want the “display” to preload the video. This means:

    • The cockpit tells the server via SignalR that a video file with a specific ID should be be preloaded in the display.
    • The server tells* the display (again, via SignalR) that the video file should be preloaded.
    • The display creates an HTML video tag and sets the source to a Web API URL that serves the media file.
    • When the video tag has been created and added to the browser DOM, the display tells the server to – in turn – tell the cockpit that a video with the specified is ready to be played.

    *) When I write “the server tells X”, this actually means that the server sends a message to all connections in group “X”.

    The cockpit

    In my WPF applications, I use the model-view-view model (MVVM) and the application service pattern.

    Using application services, view models can “do stuff” in an abstracted fashion. For example, when the code in a view model requires a confirmation from the user. In this case, I don’t want to open a WPF dialog box directly from a view model. Instead, my code tells a “user interaction service” to get a confirmation. The view model does not see the application service directly, only an interface. This means that the view model does not know (and does not care) whether the response really comes from a dialog shown to the user or some unit test code (that may just confirm everything).

    Application services can also offer events that view models can subscribe to, so the view models are notified when something interesting happens.

    Back to Web API and SignalR: I don’t let any view model use a SignalR connection or call a Web API URL directly. Instead I hide the communication completely behind the abstraction of an application service:

    • Web API calls and outgoing SignalR communication are encapsulated using async methods.
    • Incoming SignalR communication triggers events that view models (and other application services) can subscribe to.

    Minor pitfall: When a SignalR hub method is invoked and the handler is called in the WPF program, that code does not run on the UI thread. Getting around this threading issue (using the Post() method of SynchronizationContext.Current) is a good example of an implementation detail that an application service can encapsulate. The application service makes sure that the offered event is raised on the UI thread, and if a view model subscribes to this event, things “just work”.

  • Looking Back at 2018

    The end of the year is typically a time to look back – here’s my personal list of programs and technologies that played an important role for me in 2018.

    Visual Studio Code: It keeps getting better and better

    This editor-becoming-an-IDE needs no introduction. I have included it in this list because 2018 was the year where I started doing meaningful work beyond editing HTML/[S]CSS files in Visual Studio Code.

    For my purposes, it does not replace “classic” Visual Studio, but complements it. It’s not uncommon for me to debug ASP.NET Core and TypeScript code in Visual Studio Code as well as WPF code in Visual Studio 2018 at the same time (in a project where SignalR is used for Desktop Client <-> Server <-> Web Client communication).

    I’m extremely impressed by the ecosystem of extensions (e.g. Live Sass Compiler, Live Server) as well as the ongoing development with its monthly releases.

    Linea Sketch on iPad Pro: So good, it’s almost worth buying the hardware for

    I love Linea Sketch, which is an iPad app for (as the name implies) sketching. When I tried out various graphics applications for my 2018 iPad Pro, I was looking for something that would allow me to quickly draw UI sketches and illustrations for presentations without much overhead. Linea Sketch caught my attention because of the combination of simplicity and power. Two highlight features of the app are “ZipLine” and “ZipShape”, which let you quickly draw straight lines, circles and polygons without breaking your flow of work with the pen.

    Take a look at the Linea Sketch website to learn more about this fantastic app.

    UWP: I wanted to like it, but what a disappointment…

    I already wrote a bit about my frustration with the Universal Windows Platform (UWP) in the introduction to my previous blog post.

    Obviously, each new platform comes with a learning curve. If you have a clear vision of what you want to develop and are learning how to do it along the way, you are bound to take longer than expected. What happened with UWP, though, was that I encountered problems that too often became roadblocks for hours or sometimes days. If you get silent crashes or low-level exceptions with an HRESULT that basically says, “something went wrong”, the only thing you can do is to comment out code you have just written up to a point where the program is working again. That reminded me very much of the early Silverlight days (version 2 and 3), Back then, error messages only became helpful in later versions (I remember version 4 and 5 as being good enough).

    Web searches showed me that I wasn’t alone. Every so often, a question on a forum would made me go “yeah, I’d like to know an answer to that, too”. Unfortunately, often only reply would clearly indicate that the original post was only scanned for keywords, not actually read, let alone understood. Obviously, this is not a specific UWP problem. It’s just that other technologies seem to have reached a critical mass of users, so that e.g. on StackOverflow, additional comments and answers appear quicker and in larger numbers.

    The final straw for me were silent crashes of the Windows App Cert Kit, which had worked on my machine earlier. Searching for a solution, I came across Microsoft forum threads reporting WACK problems that went on for months, with no real solution in sight.

    I don’t know whether the WACK problem has been solved now, or whether UWP in general has become friendlier in terms of developer experience. But frankly, I have stopped caring. After all, we’re talking about programming as a hobby. Maybe I’ll revisit UWP in a few years – but for now, I have moved on.

    And by the way: I actually do like UWP APIs. They make e.g. creating a thumbnail of a media file or determining the length of a video file super-easy. But I can use these APIs from a WPF program as well, so that’s exactly what I’m doing now.

    ASP.NET Core (Web API, SignalR): A positive surprise

    While working with UWP was hard work for every step along the path, ASP.NET Core was clearly the opposite experience for me. Whenever I ran into a problem, I found a sample or some forum or StackOverflow post that helped me find a solution. And unlike with UWP, where I came from a WPF and Silverlight background, I didn’t have much prior knowledge.

    To put things in perspective:

    • I started with version 2.1, i.e. I surely skipped a lot of the problems of the 1.x days.
    • I found a great starting point with the SignalR with TypeScript and WebPack sample.
    • I use ASP.NET for non-UI, server-related functionality that is limited in scope.

    So, your mileage may vary. For me, the positive initial experience was a great motivation to learn more about the platform and to overcome the small problems that are simply a natural part of software development.

  • How to Make Chrome Kiosk Mode “just Work”

    There’s a reason why I haven’t blogged about UWP lately: The overall development experience (slow turnaround cycles, silent crashes, HRESULTs instead of error messages, you name it) drove me mad up to the point I scrapped my whole project, a digital signage solution, in early summer. Instead, I now use Chrome as my “render engine” and things are working pretty well. Without prior experience in using ASP.Net Core, WebAPI and SignalR, I have been able to whip something up to be ready for the 2018/19 Basketball season.

    During development, I had to figure out

    1. how to use Chrome without any… chrome (i.e. no title, adress or tool bars),
    2. how to move the Chrome window to the secondary screen,
    3. how to close Chrome from code and
    4. how to still be able to use Chrome for browsing during development.

    tl;dr: On https://github.com/RWeigelt/ChromeKioskModeDemo you find a small demo project (C#/WinForms for simplicity) that’s pretty self-explanatory.

    Problems #1 and #2 are easy: Chrome has a so-called kiosk mode (command line parameter --kiosk http://www.example.com) that will display the specified web page in full-screen mode. Another command line parameter deals with with positioning (--window-position=top,left). In the demo code you’ll see other parameters, they force the window size for a cleaner startup.

    Problems #3 and #4 turned out to be connected to each other.

    One might wonder what’s so hard about closing Chrome from code. Don’t you just start a process with Process.Start and remember the returned Process instance, to later call its CloseMainWindow method? What could possibly go wrong?

    Well, for starters, that Process instance may live shorter than expected. If you have a couple of Chrome windows and/or tabs open, Chrome will do a lot of process management behind the scenes – and “your” process may not be the one displaying the requested web page.

    On the other hand, if you go from zero Chrome windows to one window with a single tab, things are nice and easy. Now while you could force yourself to use a different browser during development, you never now whether there isn’t some Chrome window open later in production.

    Fortunately, if you specify a different “user data directory” (--user-data-dir=directory) when starting Chrome, you can achieve this “one window, one tab, one process” scenario even if you have many windows and tabs open.

    For details, take a look at the code on https://github.com/RWeigelt/ChromeKioskModeDemo. This C#/WinForms project shows a form with two buttons:

    • “Open Chrome” will open http://www.example.com in full-screen mode on the second monitor (sorry, you have to have a second monitor for the demo).
    • “Close Chrome” closes the Chrome window without affecting any other Chrome windows.

    Note that this is not a library, just some code I have taken from my solution (stripped down for clarity). You’ll want to adapt it to your needs anyway. Have fun with it!

  • Emaroo 4.3 – Support for Adobe CC 2019 / VS Code 1.28

    Emaroo is a free utility for browsing most recently used (MRU) file lists of programs like Visual Studio, VS Code, Word, Excel, PowerPoint, Photoshop, Illustrator and more. Quickly open files, jump to their folder in Windows Explorer, copy them (and their path) to the clipboard - or run your own tools on files and folders with custom actions!

    About this Release

    • Added: Support for Photoshop/Illustrator/InDesign CC 2019.
    • Updated: Support for Visual Studio Code 1.28 (changes regarding of most recently used files). Previous versions of Visual Studio Code are still supported.
    • Changed: Emaroo no longer looks for Photoshop/Illustrator CC versions prior to 2018 by default. This does not affect support for CS6 versions (which some users keep for compatibility reasons).

      If you still need support for older CC versions, you can enable it as follows:

      • Close Emaroo
      • Start Notepad as Administrator
      • Open the file Emaroo.exe.config in the installation directory (usually C:\Program Files (x86)\Weigelt\Emaroo)
      • Set SearchForOldAdobeCCApplications option to True
      • Save the config file and start Emaroo.