This is a fundamental issue with VCL styles and how they style the menu. Styling is done with a wide-range hook. In particular, the CBT hook is set by calling SetWindowsHookEx from TCustomStyleEngine.CreateSysHook in the Vcl.Themes block. In fact, the hook only applies to the GUI thread, but it is a broad process in the sense that there is exactly one GUI thread in this process.
Since you have multiple VCL instances in your application (one in the DLL and one in the application), two hooks are installed. It's too much. A recently installed hook has been recently installed (a DLL, as it happens), and therefore the DLL menu style infects your executable. And why you are faced with a violation of access rights. The DLL is trying to work with a menu that belongs to an executable file. And so, in spite of all your efforts, you end up in a DLL code that accesses VCL objects from the host executable.
There is no easy way around this and fully support the styles in both modules. What we have here is a fundamental consequence of the design. The system was not designed to support multiple VCL instances. If you want to use VCL styles across multiple modules, designers expect you to use runtime packages.
I suggest that you could get some traction by controlling the DLL from a completely different thread. This involves loading the DLL from this other thread so that the VCL initializes in the thread. And all calls to the DLL must be from this thread. And you will need to start the message loop in this thread. You may be able to do this work, but I doubt it. Even with all the caveats mentioned, you still have to cope with the fact that you have two GUI threads that present all kinds of problems with processing the input queue.
Perhaps another approach is to remove the hook from the DLL. As long as your DLL does not display the menu, you can get away with removing this hook. This will disable the style for the menu displayed by the DLL, but perhaps this is acceptable.
This version of your DLL (after I simplified it also) removes the hook.
library VCLStyleDLL; {$R 'Style.res' 'Style.rc'} uses VCL.Styles, VCL.Themes, VCL.SysStyles; // to gain access to TSysPopupStyleHook {$R *.res} begin TStyleManager.TrySetStyle('Glossy', false); TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); end.
In this version of the DLL, the host executable does not suffer from the problems described in your question.