Loading the Right Runtime

I l @ ve RuBoard

It might surprise you to learn that two different runtimes are available to all .NET applications. The most commonly used version (and the default) is the workstation build of the runtime (which is contained in mscorwks.dll). The second version, which is optimized for server applications, is contained in mscorsvr.dll. These builds are designed to provide optimal performance for client applications and multiprocessor server applications. The server build of the runtime makes better use of multiple processors, enabling garbage collection to be done on all processors concurrently (in parallel).

Which runtime will your application use? All applications generated by Visual Basic .NET will use the workstation runtime, regardless of what system it is running on or what type of application (Windows Forms, Windows service, console application, and so forth). Only ASP.NET applications run under the server runtime (provided that the machine has four or more processors). Unfortunately, there is currently no way to tell Visual Basic .NET to use the server runtime instead of the default workstation runtime. The only way to tell it to use the server runtime is to host the CLR in your own wrapper. Unfortunately, this means you need to build a native Visual C++ skeleton application that does the work of hosting the CLR and launching your application with the setting you want.

CLR Hosting

Visual Basic .NET applications don't just "run" on a machine. First, the operating system has to look at the executable header. When you install the .NET runtime, the operating system learns to recognize managed applications. Then it invokes a default "wrapper" application that, among other things, creates an instance of the CLR ( essentially "hosting" it) and instructs the CLR to run the application you attempted to run. This wrapper loads the workstation runtime and sets other default runtime properties.

There are distinct advantages to creating your own CLR host other than just loading the server version of the runtime. You can tweak various properties of the CLR, including the number of worker threads (as mentioned in Chapter 3) and completion threads. Among other things, you can:

  • Specify the desired runtime version

  • Optimize how assemblies are loaded

  • Control the garbage collector behavior

    More Info

    To really see what's possible when you use your own CLR host, you should consult the .NET Framework documentation. Look for the CorBindToRuntimeEx function as a starting point for your search.


The CLR is available via a set of COM interfaces, which means you can also host the CLR in a Visual Basic 6.0 application. But I don't recommend doing that. The most efficient way to host the CLR is with a native application. Hosting it in Visual Basic 6.0 would mean you'd be hosting a runtime within a runtime. That would be ugly, and your performance would probably be awful .

To help illustrate how to host the CLR with a native application, I built a sample application called SvrLoader (one of the sample files for this chapter) in Visual C++ ”it's the only C++ example in this entire book. It's pretty simple and does not support passing command-line parameters to the .NET executable, but you can add that at your leisure.

 //SvrLoader.cpp:Loadsanapplicationusingtheserverruntime // #include "stdafx.h" #include "mscoree.h" #include "stdio.h" #import "mscorlib.tlb" named_guidsno_namespaceraw_interfaces_only no_implementationexclude("IID_IObjectHandle", "IObjectHandle") constWCHARAPPLICATION_NAME[]=L"test.exe"; constDWORDMAX_WORKER_THREADS=20; constDWORDMAX_COMPLETION_THREADS=30; ICorRuntimeHost*Init() { //InitializeCOM HRESULThrCOM=::CoInitialize(NULL); if(FAILED(hrCOM)) { printf("UnabletoinitializeCOM.\n"); returnNULL; } LPWSTRpszFlavor=L"svr";//usemscorsvr.dll //PointerfortheRuntimeInterface ICorRuntimeHost*pCorHost=NULL; //Weattempttoloadthe'svr'Runtimehere.Ifitisnotavailable, //inthecaseofaworkstationOS,thenthe'wks'Runtimewillbe //loadedbydefault. HRESULThr=CorBindToRuntimeEx(NULL, pszFlavor, NULL, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void**)&pCorHost); if(FAILED(hr)) { printf("UnabletocreatetheHostinginterface.\n"); returnNULL; } //TrytostarttheRuntime hr=pCorHost->Start(); if(FAILED(hr)) { pCorHost->Release();//ReleasetheRuntimeinterface printf("UnabletoinstantiateCOM+Runtime.\n"); returnNULL; } returnpCorHost; } voidShutdown(ICorRuntimeHost*pCorHost) { if(pCorHost!=NULL) pCorHost->Release(); //CleanupCOM ::CoUninitialize(); } BOOLSetMaxThreads() { //setmaxthreads ICorThreadpool*pTpool; HRESULThr; hr=CoCreateInstance(CLSID_CorRuntimeHost, NULL, CLSCTX_INPROC_SERVER, IID_ICorThreadpool, (void**)&pTpool); if(FAILED(hr)) { printf("Unabletoacquirethreadpoolinterface.\n"); returnFALSE; } hr=pTpool->CorSetMaxThreads(MAX_WORKER_THREADS, MAX_COMPLETION_THREADS); pTpool->Release(); if(FAILED(hr)) { printf("Unabletosetmaxthreadsforthreadpool.\n"); returnFALSE; } returnTRUE; } LONGExecuteAssembly(ICorRuntimeHost*pCorHost) { LONGretVal=0; //getthedefaultAppDomain IUnknown*pUnkAppDomain=NULL; HRESULThr=pCorHost->GetDefaultDomain(&pUnkAppDomain); if(FAILED(hr)) { printf("UnabletoacquireIUnknowninterfacefordefaultdomain.\n"); returnfalse; } //getthe_AppDomaininterface _AppDomain*pDomain=NULL; hr=pUnkAppDomain->QueryInterface(IID__AppDomain,(void**)&pDomain); if(FAILED(hr)) { printf("UnabletoacquireAppDomaininterface.\n"); pUnkAppDomain->Release(); return1; } //wenolongerneedpUnkAppDomain pUnkAppDomain->Release(); //executethespecifiedassembly BSTRbstrAssemblyName=SysAllocString(APPLICATION_NAME); hr=pDomain->ExecuteAssembly_2(bstrAssemblyName,&retVal); pDomain->Release(); //freeassemblyBSTR SysFreeString(bstrAssemblyName); if(FAILED(hr)) { if(hr==0x80070002) { printf("Unabletofindmanagedassembly:%s",APPLICATION_NAME); } else { printf("Errorexecutingassembly(hresult=0x%x).\n",hr); } returnretVal; } returnretVal; } // int_tmain(intargc,_TCHAR*argv[]) { ICorRuntimeHost*pCorHost=NULL; pCorHost=Init(); longretVal=1; if(pCorHost!=NULL) { if(SetMaxThreads()) { //Executetheassembly retVal=ExecuteAssembly(pCorHost); } //StoptheRuntime pCorHost->Stop(); } //Cleanupandexit Shutdown(pCorHost); returnretVal; } 

You can enhance this code to your heart's content. For example, you can

  • Create your own set of registry keys for your application's runtime hosting settings (which will allow you to tweak the application without rebuilding it)

  • Allow passing command line arguments to the .NET application

If this is too much for you, don't worry about it. For most systems, the workstation runtime will always be loaded, regardless of which runtime is requested . Essentially, the workstation runtime will always outperform the server runtime on systems with one or two processors, so it won't let you choose otherwise . Loading the server runtime is most critical for server applications on systems with four or more processors. I've included this discussion simply for the sake of completeness. After all, this is a book about enterprise development.

I l @ ve RuBoard


Designing Enterprise Applications with Microsoft Visual Basic .NET
Designing Enterprise Applications with Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 073561721X
EAN: 2147483647
Year: 2002
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net