Semicolon is a new monthly column from Microsoft's Visual C++ .NET Product Manager - our very own Nick Hodapp. The column is intended to be a direct line to Microsoft for you to ask those questions that no-one else can answer. If you've ever wondered about the internal machinations of the VC++ compiler, or ever wanted to know why a particular design decision was made, or want the inside story on a curly Visual C++ question that has been stumping you then post your questions here. Each installment will cover the best or the most interesting question. The rules are simple: Make it interesting, make it about Visual C++, and don't ever mention Visual Basic.
I have some sad news and some glad news. As you certainly know by now, Microsoft is on the cusp of releasing Visual C++ .NET 2003 � a 10-year anniversary edition with lots of great new features including ISO C++ conformance and support for Windows Forms. The sad news is that we very recently discovered a bug in the product that we were unable to fix prior to release. While the bug doesn't affect every user, or even half our users, Microsoft is taking this concern seriously in order to address the needs of C++ developers. The glad news is that we found the bug and are delivering a temporary workaround fix until a permanent solution is available.
The �Loader Lock issue� only affects C++ developers using the mixed-mode assembly feature. It has the potential to cause application deadlock in very particular scenarios. It does not pertain to Visual C++ developers writing strictly MFC, ATL, or even traditional Win32 code. It does not pertain to C# or Visual Basic developers as they do not have such a feature available to them.
It is important to note that while Microsoft is taking this issue seriously, the bug actually surfaces quite infrequently and affects developers only in very specific scenarios. I want to tell you about the bug so that you can learn whether it will affect you and your programs. This text is not intended to be a complete technical breakdown of the problem. Rather, these words are an introduction. Microsoft is also releasing technical documentation to satiate your need as a developer for such information.
If you are a C++ programmer using Visual C++ .NET 2002 or the new Visual C++ .NET 2003 to build managed components (assembly DLLs) to run on the .NET Common Language Runtime (CLR), you are one of the customers whom this will affect. This bug manifests itself strictly in assemblies containing both native x86 and managed MSIL code, and it exists in both Visual C++ .NET versions 2002 and 2003. Presently, this is not a bug that could be addressed by a service-pack. Its existence is due to an architectural bug.
Very few customers external to Microsoft have notified us of being bitten by the bug. (We have provided these customers with the information required to work around the bug.) This is not surprising as the bug surfaces relatively infrequently. However, in the interest of creating robust applications we encourage you to familiarize yourselves with the recommended workaround procedure and determine whether it should be applied to your code.
Internally several Microsoft teams have now seen the bug manifest only under testing scenarios involving severe system stress, or in C++ mixed-mode assemblies that have been digitally signed. It took our team three years to both discover the issue and realize its seriousness and scope.
The bug is not a security-class bug. It causes application deadlock when it occurs.
Today the bug occurs rarely. It is serious because it could begin to occur more frequently as changes are made to the Common Language Runtime (CLR), to Windows, or as the mixed-mode assembly technology is more widely adopted. The bug occurs somewhat unpredictably.
If you are an experienced Win32 developer you are likely aware of the restrictions placed on the code you write in the DllMain entry-point function. DllMain is called by the Windows loader to initialize the DLL. Documentation in the Windows SDK has long prescribed that DllMain code shall not call API's outside of Kernel32, shall not launch threads, shall not load other DLLs, etc. However, in mixed-mode DLLs that have a DllMain entry point defined, it is likely that some action will provoke the CLR to execute some of these illicit APIs during DllMain. When this happens the potential exists for deadlock to occur.
Mixed-mode DLLs that link to the CRT or other libraries may have a "hidden" DllMain.
We have taken steps to enable the Visual C++ .NET 2003 compiler to alert developers that they may be susceptible to the problem. If you attempt to compile a mixed-mode assembly that has a DllMain defined, the compiler/linker will emit a warning saying this is an unsafe practice and that the assembly should be linked using the "/noentry" switch. Of course, if the assembly links to the C-runtime (a very common scenario), specifying "/noentry" will have the affect of a second warning being emitted. This circular set of warnings is designed and intended to point developers to documentation about this issue, and the steps required to correct it. The warning messages themselves will contain links to the appropriate documentation.
The workaround steps involve changes to your application's code. You will have to compile your assembly-DLL project with /noentry, and you will have to run your DLL initialization code in a function other than DllMain. The technical documentation for this bug describes the specific steps that need to be taken.
While this fix is relatively simple, the reason we were unable to implement a complete fix in Visual C++ .NET 2003 is because it involves architectural changes to several distinct technologies, including the C++ compiler and the CLR. Introducing such changes this late in our product cycle would have produced ripples that would potentially have destabilized other features in the release, and caused significant delays. Since this bug is localized to a subset of .NET developers, and further to a subset of C++ developers, we've decided to continue shipping with the issue. In our eyes these workaround steps aren't ideal, but should suffice in the pinch situation we're in. Here is the even better news: In the next major release of Visual C++ we intend to implement a more appetizing fix, which will involve disallowing any managed-code from ever executing during DllMain (enforced by the compiler and the CLR). This fix, with some additional details, will correct the problem completely. To prepare your applications now, the recommendation is never to architect or write explicitly managed-code in DllMain. A new �standard� entry point will be invented specifically to initialize managed code and data.
I�m sure by now many of you are wondering what sets this bug apart from any other bug you�ve ever encountered in a Microsoft product. Why wouldn�t Microsoft just quietly release the documentation about the bug and let developers figure it all out on their own? For one, this is truly a �compiler bug�. Some developers are quick to jump to the conclusion that a bug in their application is actually due to a �compiler bug�. Sometimes this turns out to be true, but most times it isn�t. But it is truly painful when there is a compiler bug, especially if you�re one of those developers who isn�t prone to suspecting the toolset. The Loader Lock issue is a compiler-level bug, and we don�t want you to lose any sleep over it. Fix your code to work around what is, admittedly, our issue, and move on.
Secondarily, I think this is a good chance to remind C++ developers about the often overlooked set of rules which pertain to writing code in DllMain. If Microsoft�s own architects and developers inadvertently overlooked these rules, then I�ll bet some of you have too.
That said, I want you all to spend 15 minutes to a) reread the documentation about what is permissible code in DllMain(), and b) inspect your own application�s DllMain() functions. If you find offending code, and if fixing it corrects a known bug in your application, let me know. Make the story interesting enough and I�ll send you a t-shirt.
The 2nd piece of homework, and the point of all this, is to a) read and understand the technical documentation about this bug, b) determine if it affects your code c) fix it if it does.
Given that you�ve read this far, I�d like to now make an about-turn and make a short appeal on behalf of continued and new usage of the mixed-mode assembly feature. As I�ve noted in the previous 1200 words, the feature does have a bug that requires special attention to avoid. Does that render the feature useless? Should you avoid creating native/managed assemblies in C++? The answer to both questions is �no�.
The primary impetus of this feature is to enable the integration of existing C++-based applications with fully managed applications and to enable existing C++ libraries to be callable from managed code. Secondarily it enables you to extend the life and functionality of existing C++ code by enabling seamless consumption of managed libraries � much in the way C++ developers 6 years ago began consuming COM and ActiveX components in purely Win32 applications. There are simply too many valuable pre-made classes and interfaces in the .NET Framework to ignore. If you�re up for a 3rd piece of homework (extra credit), I challenge you to scan through the .NET Framework documentation for an interesting class, then consume that class in a C++ program. Pretty powerful technology, eh?
I hope that you won�t write-off using this feature simply because it has a blemish.
Semicolon was on a 3 month hiatus this winter and I hope not to have it disappear for so long again. I�d love to have something more positive to talk about next time, so if you have any burning questions that you�d like me to write about, by all means send them my way.
| You must Sign In to use this message board. |
|
|
 |
|
 |
I think I have a good question that warrants a "Semicolon" article. Let me give you some background first. The question is in the last paragraph. I know this isn't considered "good writing practice" but you really need background before it will make sense.
I work for a large healthcare company. We had/have quite a few disparate applications that we have been bringing together under one application (The Host). This Host implements a custom interface to provide common functionality that all separate applications use. Each custom app must also implement a Client interface to allow wire-up into the Host. The process goes something like this.
1) The Host launches. 2) The Host looks in a "Client" subdirectory for all dlls and exes with embedded typelibs. 3) The Host CoCreates any coclass it finds and queries for the Client interface. 4) If the Client interface exists, the Host calls a wireup method passing it's Host interface to the Client. 5) Client and Host can now talk to each other.
Once the Client has been loaded into the Host, the Client can call a set of methods to add MS Access-like toolbars and buttons to the Host. This is implemented with WTL's CPaneContainer class and some custom template classes for the Access-like vertical tabstrip. This tabstrip exists down the left side of the frame and is separated from the right side of the frame by a splitter control. The Host then passes click events from the newly added buttons back to the client for processing. The Client can also gain access to a set of common Interfaces implementing common business logic, provided by the Host.
The Host also implements the In-Place Activation interfaces to allow ActiveX Controls to run inside of it. The client can tell the Host to CoCreate an ActiveX Control and add it to a Visual Studio-like tab strip along the top of the right side of the splitter. The ActiveX Control can add shared menus and toolbars to the Host using the IOleInPlace*** interfaces. 
For the most part, the Clients create sliding tabstrips down the left side of the Host, and add toolbars to them. When a button on the toolbar is clicked, the Client tells the Host to load and In-Place Activate a particular ActiveX Control that contains the application functionality. All three; Host/Frame, Client, and ActiveX Control all work together to provide the user with their experience.
This has been working quite well, but I would like to be able to add the ability to run .NET Controls in the Host as well. I've posted several questions about how .NET deals with In-Place Activation and the only answer I've received is that it can't be done. If Internet Explorer can do it though, then I can. Basically, all I want to do is add the ability to run .NET Controls in place of the ActiveX Controls in my Host/Frame. How should I go about tackling this one?
Brian
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Hello,
you forgot to mention that even the workaround is not an 100% solution to this bug...
For more info see:
http://msdn.microsoft.com/library/en-us/dv_vstechart/html/vcconMixedDLLLoadingProblem.asp[^]Mixed DLL Loading Problem-Article:
"Furthermore, even DLLs linked with the /noentry option may deadlock on versions 1.0 and 1.1 of the common language runtime. "
Consequently, due to the way the loader works in version 1.0 and 1.1 of the common language runtime, deadlock situations are always possible with mixed DLLs, even though they are often quite rare in practice. The worst part of this is that mixed DLLs that happen to work on most systems can begin deadlocking if the system is stressed, the image is signed (since the security functionality require more managed code to run during assembly load), hooks are installed into the system, or the behavior of the runtime changes through service packs or new releases. In summary, this is a serious problem that must be addressed for all mixed DLLs.
Moreover, the implementation of versions 1.0 and 1.1 of the common language runtime loader can encounter deadlock situations, even when the /noentry linker option is specified, such as when unmanaged DLL exports or unmanaged VTable Fixups (VTFixups) are part of a mixed DLL. These problems should be fixed in the next version of the runtime, but there is currently nothing that can be done to completely eliminate the deadlock risks on versions 1.0 and 1.1 of the common language runtime associated with unmanaged exports and unmanaged VTFixups with Visual C++ .NET 2002 or Visual C++ .NET 2003. These specific deadlock risks should not exist when running the same images on the next version of the runtime. Consequently, Microsoft recommends that unmanaged exports and unmanaged VTFixups not be unnecessarily removed from images unless a deadlock situation is experienced.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Does this problem also affect IL code with exports? That is, a library compiled purely in IL but with vtable entries for IL exports?
- RS
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
In a DOS application, you can bring up the properties, and change font size, fonts, etc, and apply this to the current window. The changes are made on the fly.
Now, I have a DOS application written in C++ that needs to change its font when a certain menu option is selected. How can I do this, and apply the changes on the fly?
I previously posted this same question elsewhere, and was told I had to use PostMessage and simulate the user hitting all the buttons (which still brings up the dialog)... Basically a messy solution I'm not willing to follow. There must be another way~~~?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
Static objects that have ctor/dtor will cause that you will have some sort of DllMain. (Don't get me started about how bad the C Runtime does that) Do I need to assume that every project that have static objects (+ .NET Mix mode) can have a bug?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
When your mixed DLL is loaded because of these static objects have to get linked in, and the CLR is not loaded, the CLR dll's are also loaded in. This causes the bug, because managed code is run on DllMain.
You have to ensure that the CLR is running when your mixed DLL is loaded, and the first entry point of your mixed DLL should be managed. From that managed call you can use IJW to initialise you static objects.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
This isn't correct. It is never safe to have an entry point in your mixed DLL. It doesn't matter whether or not the CLR has already been loaded.
Since the initializers of statics and globals are called by the DLL entry point function (__DLLMainCRTStartup), simply adding statics or globals to your mixed DLL project is a potential problem
Every DLL that has static objects and is compiled with the /clr compiler option should use the workaround described in the KB article. Otherwise, the DLL may encounter deadlock scenarios.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Although this bug will probably not effect me. (famous last words) I think its great that you guys are admitting it and trying to take responsibility for it. Also the steps via the compiler warnings make a lot of sense to me, and are a good approach to take.
Regardz Colin J Davies
Sonork ID 100.9197:Colin
I'm guessing the concept of a 2 hour movie showing two guys eating a meal and talking struck them as 'foreign' Rob Manderson wrote:
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have a question regarding the use of managed C++ as a bridge between unmanaged C++ and .NET.
I am in the process of updating an aging production software infrastructure with .NET solutions. I've slowly been converting and replacing software within the production workflow. However, in several instances I have had to integrate .NET assemblies with existing VC++ 6 code. In many cases I have been using managed C++ as a bridge to C# or VB.NET assemblies. I simply export a function from a managed C++ dll which I call from my existing VC++ 6 code. From the managed C++ dll I can then of course gain access to my .NET assemblies. I have found though that I am unable to use a Release version of the existing VC++ 6 code when calling the managed C++ dll. I get an error indicating that mscorwks.dll could not be loaded. If I use the debug version of the legacy code, which has been my solution, then all is well. It isn't a particularly urgent issue, but any suggestions as to why this is happening?
Thanks in advance, Michael Combs
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Isn't it because the release mode managed dll is missing in the cache, whereas it's expected to be there and strongly named? Recently, such issues have been raised (and solved) by some people. Look here for more info[^].
-- modified at 9:54 Tuesday 11th October, 2005
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Chris Maunder wrote: Hmmm. methinks I might be borrowing the design of that emoticon
Can't wait to see some new emoticons, you really despise sleep don't you.
-Nick Parker
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Is it required to be in the GAC under the circumstances in which I described? The managed dll references C# and VB assemblies locally rather than through the GAC, and the managed dll is simply called through an exported function by the unmanaged executable.
Thanks for the help, Michael Combs
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hmmmm
Being a guy who uses MFC, MC++ and sometimes both together I guess I belong to that small miniroty of affected people this article talks about. I remember several months ago how I had some weird trouble with a global hook dll that used managed extensions. I dont recollect the exact problem, but I am now wondering if that was related to this bug.
Thanks anyway Nick.
Regards, Nish
p.s. I'll be sorta tied up till April-end with some other work, so I am sorta safe till then. After that I intend to dive deep back into all this stuff Then maybe you'll get more decent feedback from me. This is all I can manage right now
Author of the romantic comedy
Summer Love and Some more Cricket [New Win]
Review by Shog9 Click here for review[NW]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
You bet, Nish. I'd love to see you post an article showing how you applied the procedure we're prescribing to one of your previous efforts. We'll be posting some samples on MSDN, but I really think it'd be great to see a CP article with your insights on the process...
Nick
This posting is provided “AS IS” with no warranties, and confers no rights. You assume all risk for your use. © 2003 Microsoft Corporation. All rights reserved.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
That's what you get for being one of the six people worldwide silly enough to pursue MC++ :P
Christian
NO MATTER HOW MUCH BIG IS THE WORD SIZE ,THE DATA MUCT BE TRANSPORTED INTO THE CPU. - Vinod Sharma
Anonymous wrote: OK. I read a c++ book. Or...a bit of it anyway. I'm sick of that evil looking console window.
I think you are a good candidate for Visual Basic. - Nemanja Trifunovic
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
I'm glad that Microsoft has come straight out and said 'we made a mistake'. I've had a very, very crappy time this last couple of weeks with Microsoft server and desktop apps and it's so easy to point the finger at Microsoft, yet so often the case that it's a bad driver, or faulty hardware, or user issues that were the culprit. At least this way Microsoft are standing up and saying 'Our Bad!' so you know you can either discount one issue or pinpoint it immediately.
The thing that would be interesting to hear about is how the bug was actually nailed down. The bug only manifests when you write a DLL that contains win32 and managed code in the same module, and (from what I read) mainly when you don't specify /noentry or under high stress situations (which comes first - the bug or the stress? ). It doesn't affect native DLLs or fully managed DLLs, it doesn't affect mixed mode exe's at all, it doesn't affect C# or VB.NET or anything else.
Mixing managed and unmanaged in a single image and then calling that from (potentially) a completely different language with the code running under both .NET and win32 must introduce an insane number of issues to check. Three years to have this bug make itself known? I bet there was some serious hair lossage going on somewhere
cheers, Chris Maunder
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
I suffered from this bug and contacted Microsoft about it a while ago. In my project I had a mixed mode IJW DLL with Managed C++ and native C++. The DLL exported both native and managed types!
In a normal situation the bug occured very rare. Changing the load order of the mixed mode DLL got me some relief [using #pragma comment(lib, "mixedmode.lib") instead of specifying the lib file on the linker commandline].
But when my application was loaded over a network share the bug was back and crashed the application at different places in System DLL's, all before WinMain was called. And all the work of changing the DLL loadorder now was unhelpfull.
The only way I got my code working right was:
1. An IJW DLL cannot export native types. 2. An IJW DLL cannot have a native entry point.
An example were I could reproduce the bug is this code from Netmaster:
http://dnetmaster.net/NETMasterMCpp.zip
Ferdinand.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for the update. Good to know that we are being alerted to these kind of issues.
For you next article though, how about an update on the new sexy features!! (Not just the ISO compliance though it very good to have)
Quote from a clever bloke :
"I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|