Dynamics GP Addins and Visual Studio 2022 error adding new form

“The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file: DynamicsGPForm1—The base class ‘Microsoft.Dexterity.Shell.DexUIForm’ could not be loaded. Ensure the assembly has been referenced and that all projects have been built.”

When using the visual studio add in template extension for Dynamics GP with Visual Studio 2022, you may experience the above error. This is noted in the following community posts: 

Building an application with VS 2022 fails when attempting to add Dynamics GP form.

Microsoft.Dexterity.Shell.DexUIForm

 

 

There was a major change with the introduction of Visual Studio 2022, a departure from previous versions of Visual Studio. Visual Studio went fully 64bit in this release, now running as a 64bit application. This means when a user is working inside Visual Studio, everything in the IDE is running as a 64bit application, this is a push towards the general adoption of 64bit as the new standard normal. This is all great except for the fact that Dynamics GP is a 32bit application, and is not likely to become 64bit anytime soon. 

When developing an Add-In for Dynamics GP, the various Dynamics GP libraries that are referenced are Dynamics GP 32bit libraries. When a GP form is added to the solution the above error will occur as the GP form would normally be ran by Visual Studio, in design time in order to move controls and drop them onto the form visually (visual designer). However Visual Studio is running as 64bit and it is going to attempt to load 32bit code, this does not work. Hence the above error is raised by the designer. 

This issue does not just happen for GP users, developers wishing to consume any 32 bit library or ActiveX/COM/OCX components will get the same issue. There were a number of "bug" reports around this after the launch of Visual Studio 2022, and these have now been consolidated down onto the following bug report. To be fair on Microsoft this is not really a bug, as this is the intended behaviour. WinForms .NET Framework Projects can't display the designer for 32bit references I would highly recommend reading this thread to get an understanding of the change and see the desperation of other developers on other products for a solution to this issue. 

The "workaround"

In the thread WinForms .NET Framework Projects can't display the designer for 32bit references the work around is given, which is to make a project build target of It works for me by creating a separate build configuration for the solution and each project targeting Any CPU, then clean/rebuild. This will allow the designer to work, then before building the dll to deploy to GP, change the project target back to 32bit, after any form design work is complete (close any forms that are open). There is also the suggestion to simply not use Visual Studio 2022 for 32bit Winform design, instead keep using Visual Studio 2019. However 2019 tries to push you onto 2022, with messages like,  ‘Please update to Visual Studio 2022, we are not supporting Visual Studio 2019 any longer.’, so who knows how long this is going to be practical as a solution. 
There was also talk on the bug thread about using the Visual Studio Options>>Environment>>Preview Features>> Use the preview Windows Forms out-of-process designer for .NET apps option. I have had no success selecting this option and don't think this is applicable to Dynamics GP development. 

Using Build>> Configuration Manager in Visual Studio, Use the <New..> option to create a new configuration for x86 and Any CPU, Copy settings from Any CPU or x86. It should end up with two options under both "Debug" and "Release" solution configurations. One should be x86 and the other Any CPU, as shown below. 

Select Any CPU and clean build to do any design work, then before deployment or debugging with GP itself, it must be switched back to x86 so we get a 32bit application complied. 

Below is the guts of the matter from the referenced thread above, in case it should vanish from the internet... 

Visual Studio 2022 and WinForms 32-bit .NET Framework components

Visual Studio 2022 is the first Visual Studio that runs as a 64-bit application. We received lots of requests to make this change and now you can open, edit, run, and debug the biggest and most complex solutions without running out of memory. This switch required fundamental architectural changes and there were some scenarios related to .NET Framework 32-bit components that we could not make work in Windows Forms designer.

In order to support .NET Core 3.1 and above we had to create an out of process designer. For .NET Framework, the designer remained in-process. The reason for that decision was to minimize breaking changes for 3-rd party controls that interact with Visual Studio. Since Visual Studio is now 64-bit, the .NET Framework-based designer now also runs in 64-bit, which means 32-bit code cannot be loaded at design time any longer. At the same time, to load controls for .NET Core, we created a new designer that runs out of process. Since that process can run as either a 32-bit or 64-bit process, it can be used with 32-bit controls . . So, for .NET 6, .NET 5, and .NET Core applications you have full designer support . But if you have a .NET Framework application that is referencing a 32-bit component, this component cannot be loaded in Visual Studio 2022 Windows Forms designer, and you will see a white error screen instead. This will not affect your end users, as your application will run just fine, it only affects the designer experience inside of Visual Studio.

In the future, we plan to add support for .NET Framework projects to the out of process designer. Once that support is available, it will be possible to load forms that have 32-bit specific dependencies in the designer.

Meanwhile there are a few ways to make your Forms show in the designer:

  • You can simply keep using Visual Studio 2019 for forms that have references to 32-bit components until we add support for .NET Framework projects to the out of process designer.
  • If you are an author of the component you are using, rebuild it for ‘x64’ for native components or ‘Any CPU’ for managed code. For managed code, the procedure should be very straight forward.
  • If a 32-bit component cannot be rebuilt, you can create a “design” configuration of the project, which targets 64-bits and where the 32-bit component is replaced with a 64-bit placeholder. This particular component will not be available at design time but the rest of the UI will be.
  • If you are using a third-party component, reach out to the author and ask them to provide an ‘x64’ or ‘Any CPU’-version of it.
  • For some cases, such as Visual Basic 6, producing 64-bit is not an option because they are legacy controls that don’t have an implementation on 64-bit CPU. We would suggest finding a .NET substitute for the component that provides similar functionality.

Then...

We hear and understand your concerns regarding the 32-bit references. Due to the way the Framework WinForms Designer was created, the form you are designing runs in the same process as Visual Studio runs in. Unfortunately, with the move to 64bit it meant that references now must be of an architecture that x64 can work with (AnyCPU or 64-bit). If you have access to the source code of the original projects the key is to design them with the reference as AnyCPU, even if you ultimately build and release a 32bit version of the reference.

The only way for us to fix this in WinForms is a rearchitecting of the designer entirely to run out of the process of Visual Studio - and if it were to do that, you would be able to design with your references in whatever architecture suited your needs. Unfortunately moving the designer out of process is far more than a bug fix; it’s an entire re-architecting of how the design surface in one process communicates with the Visual Studio process and passes the information back and forth about control properties. We have been working on creating an out-of-process WinForms Designer for .NET applications, and we’re getting pretty happy with the user experience in this last VS release. That said, there is still more work to be done to support .NET Framework projects and it doesn’t preclude the need to do something with the references that are causing you trouble now. They may need to be built against this new architecture for full support in the out of process designer.

We’re working hard on investigating what it will take to move the Framework designer out of process like the .NET WinForms Designer, and I will circle back on this thread with more information as I have it. I’m unable to provide a timeline yet, but once we’ve completed our investigations and done some prototype work we should have a better idea about the timeline of the project. Stay tuned for a WinForms blog post early in the new year which will give you a little insight into how we got an out of process designer to work, and future blog posts about the details of the new architecture.

 

 

Dynamics GP 2015 email–”Word experienced an error trying to open the file error sending email” when using Word Templates

When attempting to send a document that utilises word templates, even using PDF format, the following error may occur, due to a tightening in security with in the Microsoft Office product, “Word experienced an error trying to open the file”.

Word experienced an error trying to open the file. Try these suggestions Check the file permissions for the doucment or drve


Information about this issue can be found here: Word Templates will not Email/Print after Office Update

As I understand it the XML generated by Dynamics GP is not compliant and causes office versions with the patch to fail to load it. This is true also if you send the word document as a word document to someone, that was generated in Dynamics GP. If they have patched office, the document will not open.  When Dynamics GP sends a PDF/Word email it saves the document into a temp directory first then sends it, turning it into a PDF as required. This is why even PDF documents are affected too.

Solution for GP versions after 2016

The solution is to update with the latest GP patches if you are on supported version of GP 2016 and above (at time of writing).

Those updates found here:

Microsoft Dynamics GP U.S. Year-End Update 2020 RELEASED!!


Bodge solution for GP version 2015 – maybe previous version too, I’ve not tested

If you are running unsupported GP2015, then you are stuck without a solution, other than the correct one, that you really should be upgrading to a supported version of GP f9or these exact kind of reasons). In the real world there are many reasons why this may not be possible quite yet and you don’t want to postpone rolling out office updates, as for security reasons, you really shouldn’t hold back on updates.

There is a totally unsupported bodge you can use that may give you some time to upgrade whilst still benefiting from the latest office updates.  Please note this action should be considered carefully as it has not been talked about by Microsoft as an option.


Fix Dynamics GP 2015 Word experienced an error issue

To fix this issue for Dynamics 2015, in a totally unsupported way – this is at your own risk!

Download GP2016, more importantly, Download the latest GP 2016 cumulative update and install the client only, obviously you don’t want to upgrade your GP install yet, and have no need for the database components, perhaps do this on another machine for peace of mind. You must have the release that contains the bug fix, follow the link above. It must be the 2016 version of GP, this will not work if you do this with the 2018 version!


Download for GP2016 patch


In the Dynamics GP Program files folder of the 2016 install locate the following two files :

Microsoft.Dynamics.GP.BusinessIntelligence.Office.dll

Microsoft.Dynamics.GP.BusinessIntelligence.Office.dll 
Microsoft.Dynamics.GP.BusinessIntelligence.TemplateProcessing.dll

  • Ensure Dynamics GP is closed on the machine that you are working on
  • Also find the same files in the GP2015 install folder, take a copy of them onto your desktop or somewhere safe, so you have a way to go back if you need to
  • Now replace only these two files in the Dynamics GP2015 folder with those from the GP2016 folder.

You may now launch GP2015. You should find that the ability to send emails of Word Template based reports has now been restored. Roll these two files out to your other workstations that use word template reports.

These were the version numbers on those files from the attempt I made:

version 16.0.865.0 Microsoft.Dynamics.Gp.BusinessIntelligence.TemplateProcessing.dll

version 16.0.865.0 Microsoft.Dynamics.Gp.BusinessIntelligence.TemplateProcessing.dll


Note: This is totally unsupported method and use it at your own risk. However with this just been a reporting and office library dlls, the risk to GP should be low in my opinion. Although this is an unsupported change, if you are such an old version of GP you are running unsupported already to some extent anyway! Also note that this will only work with version 2016->2015. When I tried it with a more modern version of the dll, GP failed to open.

Dynamics GP Web Client is not compatible with Docker due to the Session Central Service not starting

Back in 2017 I attended NAVTechDays and after seeing the benefits the Dynamics NAV community were getting from Docker containers with NAV, I could see similar benefits for Dynamics GP and was also seeing interest in some of the conversations going on out of public within the GP community. I decided to see if I could get a good selection of Dynamics GP versions into Docker. Word of that work spread and brought out more people interested in containers for GP.

I spent a lot of hours attempting to learn Docker and to containerise Dynamics GP. I could build Docker images for the GP server database and add in various of the GP components like eConnect and oData. Sadly I was unable to get the Dynamics GP Web Client working – I really was just a cat's whisker away from success too. I was defeated by the Domain Account the Web Client runs under and its use of System.DirectoryServices.AccountManagement .  The following is a record of what I found when investigating that issue.

Although I can create a Docker container for the database and test company and even things like eConnect, there is a big problem. You see, there is no GUI with Docker containers, you can’t just remote desktop into one, you really need the Web Client running in order to make a self contained system to allow the host to interact with the Dynamics GP application in the container. If you can't access it from a browser, then you end up having to install the GP client on a non-docker machine (host) and connect using it to the running Docker container. Although this works its not really in the spirit of what I was trying to achieve, which was a fully self contained container for GP to allow multiple versions of GP to be easily spun up for testing and demo purposes. 

Why I failed?

After the Docker image has installed GP and the the web client product features are installed, one of these, the Session Central Service fails to start within the container. The Session Central Service is the component of the Dynamics GP web client installation that creates and tracks individual web client sessions as users connect and disconnect via web browsers. It is essential to getting web client to work.

At this point let me jump tight to the core issue, essentially the problem is that the “Lanman” windows service can’t be started in a Windows container. The Lanman service provides things like SMB file share services and is also referred to as the “Sever Service”, as that is how it appears, named in the services control panel list of services.

Containers are supposed to be stateless isolated single-app process groups, not mini virtual machines, so running Lanman would break that philosophy, hence it is not appropriate for it to be supported in Windows Docker containers as it doesn't make sense. Containers are supposed to be created and torn down at the drop of a hat, participating in active directory goes against the grain. This is why, along with a few other Windows features that are inappropriate for containers, we find the Lanman service just isn’t supported in a Windows Container.

So why is this a problem?

You find that the session central service, checks for the user running, see (2) in the following screenshot, and it does this using a call to the following method:

Dynamics.GP.Web.Foundation.DirectoryServices.PrincipalManager.GetPrincipal

This method in turn calls .NET method:

System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext  context, Type principalType, IdentityType identityType, String identityValue)

It is the above call that fails, and looking in the event log we see it reporting as indicated by (1) in the screenshot below that:

Exception message:
                      The Server service is not started.

Possible Root cause sml

Hey? - "The Server service is not started" – a confusing message as it means that the Lanman Service (aka server service) is not started. Yes this was super confusing error at the start of this investigation, not realising there was a "server service", so I assumed it was just a poor error message that wasn't telling me the service that had failed. So once I realised what it meant, I found out that, indeed if you go into the Docker container with Power Shell you can check that the Server Service is not started and even try to start it, however it will not start,  and this is due to the lack of support in windows containers, as previously stated. Lanman service can't be run on a windows container, thus preventing the use of .NETs System.DirectoryServices.AccountManagement. Microsoft in the past also confirm there are no plans for this to ever change, as it is fundamentally at odds with container philosophy to have this service running.

Without a small change to the Session Central Service code I was not going to get anywhere with this until…

Docker and Group Managed Service Account (gMSAs)

Hope then followed when I then discovered about the existence of Group Managed Service Account (gMSA), that I thought may provide a route to get around the lack of Lanman support. Using it we can authenticate to Active Directory resources from Windows container which is not part of your domain (remember the container is not part of domain), using gMSA. gMSA is a special account that can be used to (over simplifying it) allow passing over a domain account for the purposes of running a service. This could be perfect for replacing the user running the session central service, instead it can ran using a gMSA account for authentication. That in turn would bypass Lanman. When you run a container with a gMSA, the container host retrieves the gMSA password from an Active Directory domain controller and gives it to the container instance. The container will use the gMSA credentials whenever its computer account (SYSTEM) needs to access network resources. In our case, when building the Docker container we can use Power Shell to change the Session Central service to use the SYSTEM account having prepared the plumbing required for gMSA to authenticate against AD. SYSTEM become a kind of proxy for the AD account behind the gMSA account. For this to work certain prerequisites needs to be met, there is quite a bit of learning that is more than I want to get into here. I built this up in Docker to test.

Sadly on testing this thoroughly for a few days, it turns out there is another a problem. A docker container can access AD using the gMSAsaccount, allowing FindByIdentity to work WHEN the constructor for PrincipalContext is created with “ContextType.Domain” and specifying an accessible AD. The group managed service account technique does not work when the context type of “ContextType.Machine” is used to create the PrincipalContext.  

If we look at what is going on in the class in the screen shot– we find that the class is created with a constructor specifying machine as the context, stumping our attempts to use the gMSA to get around the lack of Lanman. This is due to no user name getting passed to the isMachineContext function (see last screen shot). I'm guessing that using the built in NETWORK user means no user name is passed into this method thus resulting in the highlighted code (1) being ran in the following screen shot.  This was upsetting to find as I thought I had it cracked at this point.

Not all that learning is a loss as it was interesting to learn about gMSA as it is an important container and enterprise computing concept to understand.

The following screenshot shows the code causing our issue (1) in the Microsoft.Dynamics.GP.Web.Foundation.DirectoryServices.PrincipalManager.

 

GetPrincipal2

 

User name being blank when calling the following IsMachineContext method then means the split in the logic in the above screen shot causes it to create the PrincipalContext using the wrong context type to use gMSA.

ismachinecontext

Finally


We can create containers with the database and test company but sadly we end up having to install the GP client on the host to access the container, that was not really my objective.

 Would be amazing if the code could be updated by Microsoft but I don’t see this happening. I need to refresh myself on the exact details of this issue and check again that nothing has changed in the years since I was trying as Docker is getting constantly improved with new features. 

Dynamics GP will not remove hold or why timestamp format in GP matters

If Dynamics GP will not let a SOP module, transaction process hold be removed in the user interface, it may be due to formatting of time stamps. Check no integrating applications have created that hold incorrectly. 

The issue is that GP is real fussy about formats of timestamps, one place time stamps can cause problems is in use with the SOP Transaction Hold table, the following query illustrates what you need to know about this. 

SELECT [PRCHLDID], [HOLDDATE], [TIME1]
FROM SOP10104
WHERE SOPNUMBE='YourDocumentNumber' AND SOPTYPE=2

This query gives us some data to look at, that is if some holds exist for that document supplied to the SQL query...

The first thing to notice is that GP often splits/spreads the Time and the Date components of the point in time over two fields, in this case the point in time is represented by HOLDDATE and TIME1. These two fields are of the sql data type "datetime", something that can catch out people when new to GP databases as it may not be totally obvious what is going on. 

Lets look at the first row, it is for the hold type "CREDIT" and represents the point in time, 3rd of May 2020 at eleven minutes past three and 31 seconds

  • It is interesting and important to note that for the HOLDDATE field, it has a date but see how the date has zeros for all the time elements of that HOLDDATE datetime value. To fill up the unused time component, the time has been defaulted to midnight. A default time of zero (midnight) is used, as the unused half of the datetime sql data type may not be set to null (we need all those bytes). 
  • Now also note how the TIME1 field value has a time component, but the date has been defaulted to a "default" of the 1st of January 1900. This date by convention is used to fill the date component of the time, as the unused half of a datetime data type may not null. 
  • Further, it is vital to note that the milliseconds of the time has been zeroed too

Now if you disobey these format rules, the GP user interface will do weird things. More often than not, it just doesn't do anything, that can be really perplexing as a problem solve because the records to the untrained eye look fine and similar to other records right next to them. It may be as simple as including milliseconds (not zeroing them) that can prevent a user from removing a hold in the GP user interface!

These time stamps are used in this way for many tables, where the same rules apply. It is very important to provide a correctly formatted time and date field if integrating or manually scripting against the GP database. This is a really common rookie mistake for developers working with GP, its easy to get lazy or not notice the formatting to be wrong. It can also change behaviour and totals, as time span calculations may not result in the same outcome if time components are left in date fields etc. Imagine the impact when totalling values over time spans, urgh.  

So to save some head scratching, and to make a GP compatible timestamp for the current time field in .NET use the following code snippet:

DateTime now = new DateTime(1900, 1, 1).Add(DateTime.Now.TimeOfDay);
DateTime ForFieldUse= now - new TimeSpan(0, 0, 0, 0, now.TimeOfDay.Milliseconds);

Don't be tempted to simplify this and try to access the .now in two places on the same statement as you may find the times have shifted enough between calls to cause the milliseconds not to zero correctly as two different values would be returned and be subtracted, not resulting in zero! Date times are immutable so you can't simply zero the milliseconds component either.

To get the date only value for use in GP date fields, you may simply use the in build .NET method ".Today" as shown in this snippet;Snippet

DateTime.Today;

 

 Hopefully this will help get back up and running after Googling the problem you've just encountered! - If so do comment, it keeps me motivated to blog more.