Rupreet's Weblog

Looking deep inside under the hood

  Home  |   Contact  |   Syndication    |   Login
  11 Posts | 0 Stories | 22 Comments | 74 Trackbacks

News

Archives

Post Categories

Saturday, June 24, 2006 #

Assembly folder in windows directory is a special folder which shows files in a different manner. To view this folder in a normal view – with all files and directory structure in it, just a tweak in registry needs to be done.

 

Add “DisableCacheViewer” DWord key and set its value to 1 at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion


Wednesday, November 02, 2005 #

            There are some scenarios where need to check programmatically if the given file is a .NET assembly or not. How do we do that? One way is to use reflection and try to load that file (assembly). If the assembly gets loaded, and doesn’t throw any exception, then yes, it’s a valid .NET assembly. If it’s not a valid file, then it’ll throw a “BadImageFormatException”. The idea of checking weather a file is assembly or not by loading it and checking if exception is thrown or not; doesn’t seem to be too clean way at least to me. So I was trying some other way with which I can get to know if the file is an assembly or not. Here is the solution I got;

 

            .NET assemblies are regular Win32 PE files. Operating System doesn’t differentiate between .NET assemblies and Win32 executable binaries; for it, they are same normal PE files. So how does system get to know if this file is a managed assembly and if yes, how to load CLR? How OS loads CLR is a separate discussion, I’ll just talk about how to check this header for validating the file if it’s a managed assembly or not. Well if we go through the ECMA Specifications Partition II – Metadata which is shipped along with .NET SDK, we see that we have a separate CLI Header in the PE Format. It is the 15th data directory in the PE Optional Headers. So, in simple terms, if we have value in this data directory, then it means that this is a valid .NET assembly, otherwise it is not.

 

Here is the code sample that does the same:

 

private void GetHeaders()

{

    uint peHeader;

    uint peHeaderSignature;

    ushort machine;

    ushort sections;

    uint timestamp;

    uint pSymbolTable;

    uint noOfSymbol;

    ushort optionalHeaderSize;

    ushort characteristics;

    ushort dataDictionaryStart;

    uint[] dataDictionaryRVA = new uint[16] ;

    uint[] dataDictionarySize = new uint[16];

 

 

    Stream fs = new FileStream(@"D:\Test.exe", FileMode.Open,

FileAccess.Read);

          BinaryReader reader = new BinaryReader(fs);

 

          //PE Header starts @ 0x3C (60). Its a 4 byte header.

          fs.Position = 0x3C;

              

          peHeader = reader.ReadUInt32();

 

          //Moving to PE Header start location...

          fs.Position = peHeader;

          peHeaderSignature = reader.ReadUInt32();

               

    //We can also show all these value, but we will be       

          //limiting to the CLI header test.

               

    machine = reader.ReadUInt16();

          sections = reader.ReadUInt16();

          timestamp = reader.ReadUInt32();

          pSymbolTable = reader.ReadUInt32();

          noOfSymbol = reader.ReadUInt32(); 

          optionalHeaderSize = reader.ReadUInt16();

          characteristics = reader.ReadUInt16();

           

          /*

Now we are at the end of the PE Header and from here, the

            PE Optional Headers starts...

      To go directly to the datadictionary, we'll increase the      

      stream’s current position to with 96 (0x60). 96 because,

            28 for Standard fields

            68 for NT-specific fields

From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,

doing simple maths 128/16 = 8.

So each directory is of 8 bytes.

            In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.

           

btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)

            */

dataDictionaryStart = Convert.ToUInt16 (Convert.ToUInt16

(fs.Position) + 0x60);               

fs.Position = dataDictionaryStart;

            for (int i = 0; i < 15; i++)

            {

                dataDictionaryRVA[i] = reader.ReadUInt32();

                dataDictionarySize[i] = reader.ReadUInt32(); 

            }

            if (dataDictionaryRVA[14] == 0)

            {

                Console.WriteLine("This is NOT a valid CLR File!!");

            }

            else

            {

                Console.WriteLine("This is a valid CLR File..");

            }

            fs.Close();

}

 

To simplify more, you can directly move your stream position to the 15th Data Directory location and check the first 8 bytes (4 bytes for RVA and other 4 bytes for Size).


Wednesday, November 09, 2005 #

I have been using ILDASM a lot for past few days when I encountered this bug. This problem is with ILDASM shipped with .NET 1.1 SDK.

 

The problem:

            If you open an assembly built with .NET 2.0 and try to disassemble it, it throws error “error : Failed to open meta data” which is valid because we trying to disassemble an assembly built on 2.0 with ILDASM for 1.1. But on clicking OK button, without closing ILDASM, try to delete or rename the assembly you are trying to disassemble. You cannot do it as IDLASM doesn’t release the lock over the file its trying to disassemble which it failed to do so.

 

Workaround:

            Workaround for this is simple, just close ILDASM or open another assembly in ILDASM and it’ll release the lock over this file. Then you are free to delete or rename your assembly.

 

Bug for the same has been logged to MSDN Product Feedback.


Monday, October 17, 2005 #

Recently I was working on a utility very similar spy++, but could do more than what we have in spy++ - like besides getting me the window (not Windows :P) class name and its height/width etc, it could also give me the caption of the window. I read couple of articles and all suggested to use global hooks. Using hooks because we are doing all this stuff using mouse – a very similar UI experience like that of spy++ - you click on the bull’s eye icon and drag the mouse to the destination window, it’ll give you all the details. If we read MSDN about hooks, the very first thing they say is that they are pretty expensive. Of course, it will be expensive; we are adding another function to be processed before the message reaches its destination. When I started working on it, I simply had some P/Invoke definitions and handled Mouse Down and Mouse Up events and it worked! Just simple .NET event handling and some P/Invokes, you are done! In my Mouse Down event, I set my cursor icon to Bull’s eye and other UI effectsJ. In Mouse Up, we get the cursor position, get the window handle by using WindowFromPoint(Point p) API defined in user32.dll. Once you get the window handle, you can get all kind of window details like the window class name, window height, width etc using APIs defined in user32.dll. Then I tried to get the caption of the window – and that also was simple 2 line code. I used SendMessage API again defined in user32.dll and passed WM_GETTEXT (value of WM_GETTEXT is defined in winuser.h file) in the message parameter of this API. Here are the signatures of the same

 

[DllImport("user32.dll")]

static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, [Out] StringBuilder lParam);

 

In first parameter, pass the handle of the window whose caption you are looking for, second parameter is your message ID – in this case, its WM_GETTEXT, third parameter is the length of the string it should read, and fourth parameter which is an out parameter, is the buffer where the caption text will be copied and we can read it from here.

 

If you want to have a look at this utility, email me and I’ll send it across.

 

So without using any hooks, we got window caption and class name – simple isn’t it?


Monday, July 11, 2005 #

Don't have a Pocket PC? Still want to write applications which require an Active Sync Connection with Pocket PC; Here is the way.....

Below is what i did to test my RAPI based application which required an Active Sync Connection!

Installations:
1. Active Sync 3.7.1 on my PC
2. VS 2005 Device Emulators on my PC. (I think there must be separate installation for this...no need to install VS2005 for this ....you need to check for it)

Here is the procedure:
1. Navigate to your "Program Files\Microsoft Device Emulator\1.0" folder. Start the "Device Emulator Manager" by clicking "dvcemumanager.exe" file.
2. Select one emulator e.g. "Pocket PC 2003 SE Emulator" and select Connect from the Actions Menu. Pocket PC 2003 SE Emulator will start.
3. Keep the emulator selected and Select "Cradle" from the Action Menu. The PPC emulator will go into "cradle" mode. You can see the icon beside the emulator name in the Device Emulator Manager change.
4. Start Active Sync if it is not running.
5. Devices will start communicating with each other and you can sync up your data.
6. Start writing your applications :)


Monday, October 17, 2005 #

The views expressed on this weblog are mine and do not necessarily reflect the views of my employer.
 
All postings are provided "AS IS" with no warranties, and confer no rights.

Wednesday, June 15, 2005 #

You can use SOS from within your VS.NET IDE. First you need to unable “unmanaged code” debugging option in Visual Studio. Go to Project Properties -> Configuration Properties -> Debugging -> “Enable Unmanaged Debugging”. Set this option to “True”. Then you set a breakpoint in your code. When this breakpoint is hit, open the “immediate window” and load SOS debugger extension through the “.load sos” command. You can also use “!help” command to get the list of all commands.

Wednesday, June 22, 2005 #

Last evening, I was trying to write an application which could detect IR Devices from my machine and give its details. I was using VS2005 Beta 2 Winforms. I added System.Net.IrDA.dll from “C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\CompactFramework\2.0\WindowsCE\System.Net.IrDA.dll” path. The program is simple, just create an instance of IrDAClient and look for devices using IrDA.DiscoverDevices(int max) which gives an array of IrDADeviceInfo. But to my surprise, when I launch the application, it was throwing exception "IrdaClient.DiscoverDevices throws InvalidProgramException".

Reading more about InvalidProgramException exception online, MSDN says "The exception that is thrown when a program contains invalid Microsoft intermediate language (MSIL) or metadata. Generally this indicates a bug in the compiler that generated the program". I was still doubtful if it was really a bug or am I doing something wrong. After working on the code and looking over internet, nothing resolved this issue. Then I thought will log this issue to MSDN Product Feedback Center. While logging the issue, I found it’s already logged and Microsoft Product Team has already confirmed that this is a reproducible at there end and validated it as a bug. Here are the bug details.


Wednesday, June 15, 2005 #

Moved to this new blog site, my previous blog site link is here.


Wednesday, December 21, 2005 #

Last week, i got the resolution for one the Designer Issue we were facing and this week we bumped into another. Here is the Designer error message we get when we open up winform.

One or more errors encountered while loading the designer. The errors are listed below. Some errors can be fixed by rebuilding your project, while others may require code changes.


Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

Hide    


at System.Reflection.Module.GetTypesInternal(StackCrawlMark& stackMark)
at System.Reflection.Assembly.GetTypes()
at Microsoft.VisualStudio.Shell.Design.AssemblyObsoleteEventArgs..ctor(Assembly assembly)
at Microsoft.VisualStudio.Design.VSDynamicTypeService.ReloadAssemblyIfChanged(String codeBase)
at Microsoft.VisualStudio.Design.VSDynamicTypeService.CreateDynamicAssembly(String codeBase)
at Microsoft.VisualStudio.Design.VSTypeResolutionService.AssemblyEntry.get_Assembly()
at Microsoft.VisualStudio.Design.VSTypeResolutionService.AssemblyEntry.Search(String fullName, String typeName, Boolean ignoreTypeCase, Assembly& assembly, String description)
at Microsoft.VisualStudio.Design.VSTypeResolutionService.SearchProjectEntries(AssemblyName assemblyName, String typeName, Boolean ignoreTypeCase, Assembly& assembly)
at Microsoft.VisualStudio.Design.VSTypeResolutionService.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, ReferenceType refType)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.AggregateTypeResolutionService.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.AggregateTypeResolutionService.GetType(String name, Boolean throwOnError)
at System.ComponentModel.Design.Serialization.CodeDomSerializerBase.GetType(ITypeResolutionService trs, String name, Dictionary`2 names)
at System.ComponentModel.Design.Serialization.CodeDomSerializerBase.FillStatementTable(IDesignerSerializationManager manager, IDictionary table, Dictionary`2 names, CodeStatementCollection statements, String className)
at System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.Deserialize(IDesignerSerializationManager manager, CodeTypeDeclaration declaration)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)

 

Cause:

I don’t have any concrete reason for this, but I am assuming that VS2005 has some kind of assembly cache which it maintains and while designing the form, somehow it gets corrupted, hence we get this error.

 

Workaround:

Follow the steps and it should work fine then!

 

1. When you open your form and you get this error. Close all the forms.

2. Close VS.NET (make sure none of the forms are open at this time)

3. Delete "bin" and "obj" folder physically.

4. Open VS.NET

5. Rebuild your application

6. Try opening your forms now. It should work!


Wednesday, December 14, 2005 #

Recently in my project we migrated from VS2003 to VS2005.  The application I am working on is a smart client application so it has lot many Win Forms. After migration, when the solution was opened up in VS2005, we faced this strange problem. None of the Forms were opening in the designer mode. It was throwing exception (shown below)

 

One or more errors encountered while loading the designer. The errors are listed below. Some errors can be fixed by rebuilding your project, while others may require code changes.


Object reference not set to an instance of an object.

Hide    


at System.Resources.Tools.StronglyTypedResourceBuilder.DefineResourceFetchingProperty(String propertyName, String resourceName, ResourceData data, CodeTypeDeclaration srClass, Boolean internalClass, Boolean useStatic)
at System.Resources.Tools.StronglyTypedResourceBuilder.InternalCreate(Dictionary`2 resourceList, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, Boolean internalClass, String[]& unmatchable)
at System.Resources.Tools.StronglyTypedResourceBuilder.Create(IDictionary resourceList, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, Boolean internalClass, String[]& unmatchable)
at System.Resources.Tools.StronglyTypedResourceBuilder.Create(IDictionary resourceList, String baseName, String generatedCodeNamespace, CodeDomProvider codeProvider, Boolean internalClass, String[]& unmatchable)
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObject.BuildType()
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObject.GetObjectType()
at Microsoft.VisualStudio.Shell.Design.GlobalType.get_ObjectType()
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObject.get_Children()
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObjectProvider.CreateGlobalObjectsForItem(ProjectItem item, GlobalObjectCollection oldObjects, GlobalObjectCollection newObjects, ITypeResolutionService typeResolver)
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObjectProvider.CreateGlobalObjectsForItem(ProjectItem item, GlobalObjectCollection oldObjects, GlobalObjectCollection newObjects, ITypeResolutionService typeResolver)
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObjectProvider.CreateGlobalObjects(Project project)
at Microsoft.VisualStudio.Design.Serialization.ResXGlobalObjectProvider.GetGlobalObjectsCore(Project project, Type baseType)
at Microsoft.VisualStudio.Shell.Design.GlobalObjectProvider.GetGlobalObjects(Project project, Type baseType)
at Microsoft.VisualStudio.Shell.Design.GlobalObjectService.GetGlobalObjects(Type baseType)
at Microsoft.VisualStudio.Shell.Design.GlobalObjectService.GetGlobalObjects()
at Microsoft.VisualStudio.Design.Serialization.CodeDom.AggregateTypeResolutionService.GetTypeFromGlobalObjects(String name, Boolean throwOnError, Boolean ignoreCase)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.AggregateTypeResolutionService.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.AggregateTypeResolutionService.GetType(String name, Boolean throwOnError)
at System.Resources.ResXDataNode.ResolveType(String typeName, ITypeResolutionService typeResolver)
at System.Resources.ResXDataNode.GenerateObjectFromDataNodeInfo(DataNodeInfo dataNodeInfo, ITypeResolutionService typeResolver)
at System.Resources.ResXDataNode.GetValue(ITypeResolutionService typeResolver)
at System.Resources.ResXResourceReader.ParseDataNode(XmlTextReader reader, Boolean isMetaData)
at System.Resources.ResXResourceReader.ParseXml(XmlTextReader reader)
at System.Resources.ResXResourceReader.EnsureResData()
at System.Resources.ResXResourceReader.GetMetadataEnumerator()
at System.ComponentModel.Design.Serialization.ResourceCodeDomSerializer.SerializationResourceManager.GetMetadata()
at System.ComponentModel.Design.Serialization.ResourceCodeDomSerializer.SerializationResourceManager.GetMetadataEnumerator()
at System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializePropertiesFromResources(IDesignerSerializationManager manager, Object value, Attribute[] filter)
at System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.Deserialize(IDesignerSerializationManager manager, CodeTypeDeclaration declaration)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)

 

This was causing lot of problems as we were not able to view the form. It took me 2 days to finally get the cause and find a resolution for the same.

 

Cause:

The cause for this is that while migrating, the existing resource files didn’t get migrated properly (I still need to figure out if this resource migration problem was due to incomplete migration by VS.NET or was due to our ignorance of warnings/errors given by VS.NET while migrating). We have data in format like:

 

<data name="lblName" xml:space="preserve">

    <value>Rupreet</value>

<data>

 

Now, if the previous resource file has some blank values something like:

 

<data name="lblName" xml:space="preserve"></data>

 

This will be invalid in the new schema for resources files. The value can be empty but the schema should be maintained. So the valid data with blank value should be

 

<data name="lblName" xml:space="preserve">

    <value></value>

</data>

 

Resolution:

In the resource file property, you need to add “ResXFileCodeGenerator” in the “Custom Tool” property. When you press enter, this tool runs and create a YourResourceFileName.Designer.cs file. With this, your resource file will contain new schema. If you get an error “Object reference not set to an instance” then this means that your data is not in proper format and the designer file will not be created. You first need to fix your data with the correct schema as I mentioned above and try running the tool again. When it saves properly with the desinger class creates, it means your resource file is in correct format. Now try opening your Forms, it should work! J