Friday, March 03, 2006

Inheriting Windows Forms in VS.Net 2003/2005 Problems

I recently had my first production use of inheriting windows forms in a C# Windows Application. For basic forms (where the base form has little/no logic) this is usually a snap. But I ran into problems when trying to open a derived form in VS.Net's design view. I would get a message like 'An error occurred while loading form' and/or 'Security Error'. It turns out that VS.Net not only creates an instance of your base form class during Design view of the derived Form, but also Loads the base form, so your Form_Load gets called. You may not intend any of this code to get executed during Design/Development. If you have any MessageBox calls, or any other code that assumes other code has executed first, you will run into problems, and the errors from the VS.Net IDE or not helpful. When running into design view problems with derived forms, start with your initialize and Form_Load methods in your base form. Good luck!

Tuesday, January 31, 2006

Firefox JavaScript window.navigate not supported

Wouldn't it be great for us developers, if the world used just one browser. Experienced HTML/JavaScript web developers have learned over time with browsers support certain functionality. I am not going to claim to be a browser difference (HTML, JavaScript, etc.) expert, but I do get to spend more time, than I want to, with these issues.

I recently ran into a problem where a call to window.navigate() on a web page in Firefox was not executing. I learned that I instead needed to use window.location.href = '' instead. Which does also seem to work in other browsers (like IE). I have not fully researched this. If anyone knows the history/reason as to the lack of support for window.navigate in Firefox, please let us know.

Wednesday, December 28, 2005

“Class Does Not Support Automation” Error (Problems creating C++ COM component from VBScript)

They say you don't appreciate what you have until it's gone, but with COM, I did not realize how crappy it was until I moved to .Net. Unfortunately COM is still in some of our lives. I have not had to deal with COM implementation details in a while, but here is a problem I ran into last night:

One of our clients provides Web Casting of sporting events (games), via a legacy ASP Web Site. The current implementation uses a both threaded COM component, developed in VC++. This COM component is dual interface (implements IDispatch), so it can be called from ASP/VBScript (a.k.a. Automation).

During an incremental upgrade of this site to ASP.Net 2005, I found that I was not able to create an instance of the exposed COM class in the VC++ component from Asp.Net (using .Net COM Interop), in my test environment. I then tested using a simple VBScript CreateObject() to create an instance of this class, but this returned the error: ‘Class does not support automation’. I had recompiled the VC++ component using VS.Net 2005, so I reverted back to the previous version compiled with VS.Net 2003, then even the old VS 6 version, and still the same problem existed!

This was surprising, since this same source code was used to compile the component currently running in production, being called from ASP/VBScript! So what was the difference?

I finally debugged the COM component during the attempted instantiation, (using VS.Net 2005) to see if I could determine where the root problem was. I noticed the error got raised after a call to the class factories QueryInterface method. I also noticed that the implementation of QueryInterface (in our VC++ source code) was ALWAYS returning E_NOINTERFACE, even if the IID being queried for (QI’d) was implemented (in this case the interface being asked for was IID_IClassFactory, which makes sense since it was CoGetClassObject making the call). Seemed like a pretty bad and basic bug (see code below):

STDMETHODIMP CGenericCF::QueryInterface( IN REFIID riid, OUT LPVOID FAR* ppvObj )

{
//Just Addref and return if it is supported
ASSERTND( NULL != ppvObj );

if( NULL == ppvObj )
return E_INVALIDARG;

*ppvObj = NULL;

if( IsEqualIID( IID_IClassFactory, riid )
IsEqualIID( IID_IUnknown, riid ) )
{
AddRef();
*ppvObj = (VOID*)this;
// NOTE THE MISSING RETURN OF S_OK HERE?!?
}

return E_NOINTERFACE; // ALWAYS RETURNING THIS..
}

So how the heck has this been working properly in production? I then got back in the debugger, and realized the following:

ole32!CoGetClassObject was making the QueryInterface call into the Class Factory (with the above buggy implementation). But ASP Server.CreateObject was not calling CoGetClassObject and not calling the QueryInterface on the class factory!

That is why it worked in production! The bug fix was required for .Net interoperability, since .Net also called CoGetClassObject.

COM programming allows you to use a components class factory or not, using the class factory requires a call to CoGetClassObject , as opposed to just calling CoCreateInstance for the class you want to create. (Check out the Related Links below for more information on this).

From my testing/debugging, this is what calls ole32!CoGetClassObject (uses class factory)
VBScript CreateObject: Yes
ASP Server.CreateObject: No
WScript.CreateObject (CScript): No
.Net COM Interop (New): Yes

Technologies
COM, VBScript, Legacy ASP, Windows Scripting Host, Visual Studio 6, VS.Net 2003, 2005

Note: For legacy ASP, you should ALWAYS be using Server.CreateObject.

Related Links

Please let me know if you have anything to add, hope this is helpful.

    Thursday, November 17, 2005

    “Service Unavailable (HTTP 503)” and Response.TransmitFile() problems on Windows Server 2003

    During QA testing of a new Asp.Net web site, in our customers production environment, we ran into the above 2 problems intermittently.

    When requesting the default page (or any page, even static htm files) from the site, the web browser would sometimes get “Service Unavailable” errors (both IE and FireFox). We were also seeing our C# code used to download files securely (see the Downloading Files Securely with Asp.Net post) not functioning properly; the web browser would just render a blank page, and never receive the file.

    These problems did not occur in our test environment, so initially we assumed it was some environmental / configuration issue.

    The Network/Web Administrator finally realized his configuration choice of ‘Throttle Bandwidth” for the IIS Site was the source of the problem.

    This option can be enabled/disabled and configured for the entire web server and/or individual sites (application pools). The site level configuration overrides the server setting for that site.

    I have a decent understanding of the implementation of Bandwidth Throttling in IIS 6 (relative to the HTTP.sys listener in kernel mode, content caching, and application pools). Documentation of this topic seemed poor from some initial Googling and MSDN Library searches. I am not going to attempt to explain my understanding of the implementation here…keeping it simple.

    This setting can affect both inbound and outboud network traffic! (Both your HTTP Request and Response streams)

    Technologies
    Visual Studio .Net 2003, SQL Server 2000, C#, Asp.Net, Windows Server 2003, IIS 6

    Related Links