Notes from Daily Encounters with Technology RSS 2.0
 
# Sunday, November 28, 2010

While reading an article on the difference between const and readonly it surprised me that changes to public consts in the referenced assembly don’t affect the referencing assembly unless it is recompiled using the changed referenced assembly. The C# Reference doesn’t hint at such behavior at all, which means it’s time for further exploration.

A sample can be pretty straight forward. Let’s start with a single class in the library:

public class Urls
{
    public const string ProductWebPage = "http://www.damirscorner.com/myproduct";
}

The reference the library in a test application:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Product URL: " + Urls.ProductWebPage);
        Console.ReadKey();
    }
}

Compiling both assemblies and running the application returns the expected result. The surprise comes if the value in the library changes and the application doesn’t get recompiled. The new value in the library could be:

public class Urls
{
    public const string ProductWebPage = "http://www.myproduct.com";
}

The application will return the new value only if it is also recompiled. As long as only the changed referenced assembly is copied to the application folder, the old URL value will still be displayed. Checking the compiled MSIL, this behavior can easily be explained:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Product URL: http://www.myproduct.com"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0011:  pop
  IL_0012:  ret
} // end of method Program::Main

The constant value is not referenced at all. It is included into the referencing assembly as a literal. Consequently the compiled application doesn’t reference the library in its manifest at all and will still work even if the library is deleted from the application folder:

// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly MyProduct
{
  // ...

To avoid the problem, public constant values in libraries should always use static readonly modifiers instead of const:

public class Urls
{
    public static readonly string ProductWebPage = "http://www.damirscorner.com/myproduct";
}

The application code remains the same; the compiled MSIL is different:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Product URL: "
  IL_0006:  ldsfld     string [Library]DamirsCorner.Samples.Const.Urls::ProductWebPage
  IL_000b:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_0010:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0015:  nop
  IL_0016:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_001b:  pop
  IL_001c:  ret
} // end of method Program::Main

Now the changes in the library will reflect in the application even without recompiling it. Of course the application also references the library in its manifest and won’t work without it:

// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly extern Library
{
  .ver 1:0:0:0
}
.assembly MyProduct
{
  // ...

The moral of the story: “Know Thy Language”. And never use const for public constant values in libraries.

Sunday, November 28, 2010 11:40:37 AM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | C#
# Wednesday, November 10, 2010

Recently I tackled a seemingly simple task: XML serialization of a generic class used with a TimeSpan data type. Basically I had a situation similar to the following two classes:

// the generic class used
public class GenericClass<T> where T: new()
{
    public virtual T Value { get; set; }

    public GenericClass()
    {
        Value = new T();
    }
}

// the class for XML serialization
public class Configuration
{
    public GenericClass<TimeSpan> Time { get; set; }

    public Configuration()
    {
        Time = new GenericClass<TimeSpan>();
    }
}

The only remaining thing to do should be calling the XmlSerializer.Serialize method:

Configuration config = new Configuration();
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
using (FileStream stream = new FileStream("configuration.xml", FileMode.Create))
{
    serializer.Serialize(stream, config);
}

Though, the result wasn’t what expected:

<?xml version="1.0"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Time>
    <Value />
  </Time>
</Configuration>

Where did the value go? After some exploration it turned out that XmlSerializer doesn’t serialize the TimeSpan structure at all. Unfortunately the suggested standard workaround by hiding the property with XmlIgnore attribute and adding an additional property of the desired type can’t be used in the above scenario because it has to be applied to the generic class only when it is used with TimeSpan data type. The problem also can’t be solved by deriving a class from TimeSpan and fixing its XML serialization because it is a structure which doesn’t support inheritance. Well, it looked like I’ll just have to derive a new class from GenericClass for the case of TimeSpan:

public class TimeSpanClass : GenericClass<TimeSpan>
{
    [XmlIgnore]
    public override TimeSpan Value
    {
        get
        {
            return base.Value;
        }
        set
        {
            base.Value = value;
        }
    }

    [XmlElement(ElementName="Value")]
    public string StringValue
    {
        get
        {
            return Value.ToString(@"hh\:mm\:ss");
        }
        set
        {
            Value = TimeSpan.ParseExact(value, @"hh\:mm\:ss", CultureInfo.InvariantCulture);
        }
    }
}

This should work, right? Wrong. The following exception is thrown when initializing XmlSerializer for the modified Configuration class now containing TimeSpanClass instead of GenericClass<TimeSpan>:

The XML element 'Value' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.

How come? Well the XmlIgnore attribute doesn’t have any effect when used in a derived class on an overridden property. If you remove the XmlElement attribute from the StringValue property, you’ll see that both properties will get serialized:

<?xml version="1.0"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Time>
    <Value />
    <StringValue>00:00:00</StringValue>
  </Time>
</Configuration>

So, is there really no way to get this working? There is, but only if you do your own serialization by implementing IXmlSerializable interface on the TimeSpanClass:

public System.Xml.Schema.XmlSchema GetSchema()
{
    return null;
}

public void ReadXml(System.Xml.XmlReader reader)
{
    reader.ReadStartElement();

    Value = TimeSpan.ParseExact(reader.ReadElementContentAsString("Value", String.Empty), @"hh\:mm\:ss", CultureInfo.InvariantCulture);

    reader.ReadEndElement();
}

public void WriteXml(System.Xml.XmlWriter writer)
{
    writer.WriteElementString("Value", Value.ToString(@"hh\:mm\:ss"));
}

This will finally produce the desired serialization:

<?xml version="1.0"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Time>
    <Value>00:00:00</Value>
  </Time>
</Configuration>

Writing your own XML serialization logic pretty much defeats the purpose of having XmlSerializer class available in the first place. It’s not that difficult in this simple case but it can get quite tedious if you have to write it for a more complex class. It’s definitely not something I’m looking forward to writing, but if it’s the most elegant way to get the job done… Since the problem is already present in .NET framework for almost a decade, it’s a pretty safe bet it won’t get fixed any time soon if ever.

Wednesday, November 10, 2010 11:04:36 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET
# Friday, September 10, 2010

In a technical document I was working on today I hade to include some details about database table definitions, including the column names, data types, primary and foreign key information, and column descriptions stored in MS_Description extended property. Using information schema views and the fn_listextendedproperty function I wrote a table valued function which returns information about all the columns in the given table. I’m posting it here in case someone else finds it useful.

CREATE FUNCTION [dbo].[GetColumnDetails] 
(    
    @tableName sysname
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT
        ColumnName = C.COLUMN_NAME, 
        DataType = UPPER(C.DATA_TYPE) + CASE
                WHEN C.CHARACTER_MAXIMUM_LENGTH = -1 THEN '(MAX)'
                WHEN C.CHARACTER_MAXIMUM_LENGTH IS NOT NULL THEN
                    '(' + CONVERT(nvarchar(10), C.CHARACTER_MAXIMUM_LENGTH) + ')'
                WHEN C.DATA_TYPE IN ('decimal', 'numeric') THEN
                    '(' + CONVERT(nvarchar(2), C.NUMERIC_PRECISION) + '; '    
                    + CONVERT(nvarchar(2), C.NUMERIC_SCALE) + ')'
                ELSE ''
            END
            + ', ' + CASE C.IS_NULLABLE 
                WHEN 'NO' THEN 'NOT NULL'
                ELSE 'NULL'
            END
            + CASE
                WHEN PK.CONSTRAINT_NAME IS NOT NULL THEN ', PK'
                ELSE ''
            END
            + CASE
                WHEN FK.CONSTRAINT_NAME IS NOT NULL THEN ', FK'
                ELSE ''
            END,
        Description = D.value
    FROM INFORMATION_SCHEMA.COLUMNS C
        LEFT OUTER JOIN
            (SELECT KCU.TABLE_NAME, KCU.COLUMN_NAME, KCU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
                INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU 
                ON TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'FOREIGN KEY') AS FK
            ON C.TABLE_NAME = FK.TABLE_NAME AND C.COLUMN_NAME = FK.COLUMN_NAME
        LEFT OUTER JOIN
            (SELECT KCU.TABLE_NAME, KCU.COLUMN_NAME, KCU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
                INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU 
                ON TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'PRIMARY KEY') AS PK
            ON C.TABLE_NAME = PK.TABLE_NAME AND C.COLUMN_NAME = PK.COLUMN_NAME
        LEFT OUTER JOIN
            fn_listextendedproperty('MS_Description', 'schema', 'dbo', 
                'table', @tableName, 'column', default) AS D 
            ON D.objname COLLATE database_default = C.COLUMN_NAME COLLATE database_default
    WHERE C.TABLE_NAME = @tableName
)
Friday, September 10, 2010 10:21:02 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | SQL
# Wednesday, September 01, 2010

Trace listeners are a great mechanism for troubleshooting and monitoring applications in production environment. After you have decorated your code with the necessary Trace and Debug calls, you only have to add the desired listeners either in code or in the configuration file and voila: the application starts emitting information to the configured destinations. Usually there is no need to have trace listeners attached all the time, you can only add them to the configuration file when you need to troubleshoot a problem.

What I didn’t know until recently, is that by adding a trace listener to your application you can cause it to crash. That’s definitely not something I wanted or expected to happen! After investigating the issue further the offender turned out to be EventLogTraceListener which (obviously) logs information to the event log. To do that the event log source is required and therefore it needs to be specified when adding (initializing) the EventLogTraceListener. And here lies the root of the problem.

To register a new event log source, administrative privileges are required. If the event log source is not yet registered and the user running the application is not an administrator, the call to Trace will raise a security exception. If this exception is not handled properly, the application will crash. To be on the safe side all Trace and Debug calls in your application should be in a try/catch block. And I have often seen this not being the case, in particular when the calls are already placed in a catch block. The other option is of course to ensure that the account has administrative privileges or that the event log source is already registered. But is it really possible to be 100% sure of that in production environment?

What I find surprising is that there doesn’t seem to be any consistency between different trace listeners provided in the framework. TextWriterTraceListener has a similar security related problem when the user doesn’t have write permissions for the specified log file location. But this situation is handled in the trace listener itself which simply doesn’t write the information to the log file if it can’t. It doesn’t raise any exceptions which (at least for me) is the expected behavior. Why is this not the case with EventLogTraceListener?

Wednesday, September 01, 2010 4:56:09 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET
# Sunday, June 13, 2010

A few months ago I worked on a small spare time project which included some manipulation of binary Excel (.xls) files. This seemingly simple task soon turned out to be quite a challenge if you want to handle it right. The post you are reading is a short summary of my experiences. They should make your choices easier if you are about to tackle a similar problem.

The most obvious choice for handling .xls files is Excel automation using the Excel object model. As long as your application is always going to be used interactively, you should be fine. It’s probably the best method to use in spite of a few downsides:

  • The object model is COM based which means you’ll have to do interop if you are developing a .NET application. Fortunately there are some nice improvements in .NET Framework which make coping with COM in C# much easier.
  • Your application will have to be compiled in 32-bit in order for it to work on 64-bit Windows. This usually isn’t a real limitation just don’t forget to switch the target platform from Any CPU to x86 if you’re doing development on a 32-bit OS to avoid the problem. (You’re going to notice it yourself when developing on a 64-bit OS.)
  • Don’t try unit testing the Excel automation code outside your IDE (e.g. on your continuous integration server). As described below this scenario is not supported.

As soon as you want your code to be run non-interactively, you’re out of luck with Excel automation. Since all Office applications assume to be running on the interactive desktop, there are several reasons why such usage is not supported and is even strongly discouraged by Microsoft. If you want to run your code on a web server, as a Windows service, a scheduled task or just automatically test it on your build server, you’ll have to find a different approach. And in this case there are no obvious choices.

Your best bet is to use Open XML file format (.xlsx, .xlsm) instead of the binary one (.xls) if this is an option for you. Since this is a well documented XML based format you can manipulate it directly without running Excel at all. You can even use Open XML SDK for Microsoft Office which includes strongly typed classes that simplify many common tasks.

This is not the case with the binary format. Microsoft doesn’t provide or support any SDK or API for manipulating the files directly. You are only provided with detailed documentation of the format. Based on it some third party solutions have been developed. Aspose and SoftArtisans have their own commercial offerings which I haven’t evaluated because as such they weren’t suitable for me.

On the other hand the only free library that I have found is MyXLS and this one leaves much to be desired. It also seems to be pretty much abandoned with the latest release almost a year ago and only a single commit to the repository in this year so far. That being said, it still might prove useful if you only want to create the files, mostly focusing on the appearance with only minimal requirements regarding formulas. According to the samples this seems to work fine. Reading existing files is another story. You are more or less on your own as soon as you need to read cells with formulas. This made the library useless for me therefore I used another approach based on the fact that the OLE DB Provider for Jet can be used to read and write data in Excel worksheets.

At first I haven’t even considered this possibility because I was convinced that this method can only be used on worksheets designed as database tables (having columns of data with or without header columns). This article proved me wrong and in spite of many issues in the demo project it showed off techniques which turned out really useful for me. The most important one was the possibility to address regions, not only complete worksheets – this can be used to retrieve and set individual cell values as well as for accessing database table-like blocks of data in a part of the worksheet. Let’s take a look at a sample:

SELECT F1 FROM [Sheet1$C2:C2];

This query retrieves a value of a single cell. The same syntax can be used to access any region: after the worksheet name with a trailing $ character the region is defined just like in Excel formulas. If the region doesn’t include column headers (specified by including HDR=No in the Extended Properties of the connection string) the columns are named F# where # is the sequential number of the column in the defined region. Similarly the following query can be used to set a value of an individual cell:

UPDATE [Sheet1$C2:C2] SET F1 = 'Value';

A few more things worth mentioning:

  • Be aware of the IMEX option in the connection string. It doesn’t seem to be documented very well, probably its best description is here.
  • Make sure you keep the connection to the file open if you plan to do more data access later. Opening the connection takes quite some time therefore the performance will be terrible if you keep closing and reopening it.
  • The technique doesn’t seem to work if the worksheet name begins with a space. At least I couldn’t make it work, no matter how I set the quotes.
  • I encountered a file which couldn’t be opened in this way but the problem was resolved after I opened the file in Excel and saved it again.
Sunday, June 13, 2010 1:47:10 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Software | Office
# Sunday, May 30, 2010

Subversion and CruiseControl.NET can be invaluable tools in your .NET development process. There are many resources available to help you get started which I’ll try to gather in this post along with some of my personal experiences.

Let me start with the list of recommended software:

  • VisualSVN Server is the ultimate Windows version of Subversion including a simple setup and powerful management tools. If you are planning to install a Subversion server on Windows it should be your first choice.
  • AnkhSVN is a Subversion Source Control Provider (SCC) for Visual Studio. As long as you’re not using Express editions of Visual Studio, this is the suggested way of working with SVN directly from Visual Studio IDE.
  • TortoiseSVN is a Windows shell extension for working with Subversion from within Windows Explorer. When you're not working with Visual Studio solutions this is the best choice for using SVN.
  • CruiseControl.NET is a continuous integration server including a web dashboard and CCTray - a system tray client application for monitoring and controlling builds.

If you’re not already familiar with the above mentioned products, you should consult their documentation or search for tutorials. I will rather focus on setting up your development and release process. If you haven’t done so already I suggest you first read the following articles by Ariejan de Vroom:

I mostly based my configuration on the ideas in these articles. I have projects configured in CC.NET to build all copies of the project: trunk (ProjectName-Trunk), all branches (ProjectName-REL-#.#) and all tags (ProjectName-v#.#.#). To identify individual builds I am using CC.NET’s Assembly Version Labeller together with AssemblyInfo MsBuild Community Task.

Assembly Version Labeller is really simple to configure. You only need to add a short snippet to each project:

<labeller type="assemblyVersionLabeller">
    <major>1</major>
    <minor>0</minor>
    <build>0</build>
</labeller>

I’m using the following versioning policy:

  • I start each project with version 1.0.0.
  • Once it’s ready for release I make a copy of the trunk in the branches directory, named REL-#.# containing the major and the minor version number. Immediately afterwards I bump the version of the trunk (only minor or major and minor, depending on the nature of the new features planned).
  • In the release branch I make the necessary changes before release (e.g. I change the AssemblyProduct name to distinguish between development and release quality builds) and make another copy in the tags directory, named v#.#.# containing the major, minor and build version numbers. Immediately afterwards I increase the build version number in the release branch.
  • I make no changes to the copies in the tags directory. All bug fixes go to the release branch. Once I’m ready for a new release I repeat the previous step.

Since I don’t specify the revision number directly, the SVN Revision number gets used automatically. This makes it possible to match each build to the revision of the code in SVN.

To put the generated assembly version in the build I am using the AssemblyInfo MsBuild task. There are two steps involved in doing this.

First you need to move the AssemblyProduct, AssemblyInfo and AssemblyFileVersion attributes from the auto generated AssemblyInfo.cs file into a new file. In my case the AssemblyVersion.cs has the following contents:

using System.Reflection;

[assembly: AssemblyProduct("ProjectName DEV")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Next you have to modify your project file (*.csproj) by importing the community tasks and adding a call to the AssemblyInfo MsBuild task:

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
    <AssemblyInfo Condition="'$(CCNetLabel)' != ''"
        CodeLanguage="CS" 
        OutputFile="Properties\AssemblyVersion.cs" 
        AssemblyProduct="ProjectName TRUNK" 
        AssemblyVersion="$(CCNetLabel)" 
        AssemblyFileVersion="$(CCNetLabel)" />
</Target>

If you have never edited a project file before, you might want to read these first:

One more thing to note which might not be all that obvious. The Condition in the AssemblyInfo task is met only when building from CC.NET. For builds in Visual Studio the task doesn’t regenerate the AssemblyVersion.cs file therefore the revision number is always 0 and the AssemblyProduct has a DEV suffix as defined in the original file. Also I remove the TRUNK suffix from the AssemblyProduct attribute of the AssemblyInfo task when moving code from trunk to release branches to separate between the two.

Sunday, May 30, 2010 12:45:16 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Software | CruiseControl | Subversion | VisualStudio
# Sunday, August 09, 2009

Microsoft Exchange supports Send As and Send On Behalf Of permissions to be granted to users for individual e-mail addresses. Sending e-mail from Outlook for these users is very simple – they just enter the desired address in the From field of a new message (toggled with the Show From command on the Options ribbon) and if they have the required permission it will be sent accordingly – either as if it was actually sent from that address or as sent by the user on behalf of the address in the From field.

If you want to achieve this from code there is a little more work involved. First of all the user must be authenticated on the server using one of the methods below:

SmtpClient smtp = new SmtpClient("smtp.domain.com");

// use user’s existing credentials
smtp.UseDefaultCredentials = true;

// pass username and password
smtp.Credentials = new NetworkCredentials("username", "password");

The next step is to set up the correct headers in the message otherwise the server will return error code 5.7.1 describing the permission the user does not have.

To send the e-mail as only the From property has to contain the desired address:

MailMessage mail = new MailMessage();
mail.From = new MailAddress("send.as@domain.com");

To send the e-mail on behalf of another user the Sender property must additionally contain the user’s e-mail address:

MailMessage mail = new MailMessage();
mail.From = new MailAddress("send.as@domain.com");
mail.Sender = new MailAddress("user.address@domain.com");

On a related note, the required permissions can be granted using PowerShell.

To grant the Send As permission:

Add-ADPermission –Identity "user1" –User "user2" –ExtendedRights Send-As

To grant the Send On Behalf Of permission:

Set-Mailbox "user1" -GrantSendOnBehalfTo "user2"

In both cases the user1 specifies the mailbox to grant the permission for and the user2 specifies the user to grant the permission to.

Sunday, August 09, 2009 7:39:38 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Software | Exchange
# Saturday, July 05, 2008

Gama System eArchive, one of the two products in our document product line, received accreditation from the Archives of the Republic of Slovenia last week. This acknowledgement by our national body means that any document stored in Gama System eArchive is automatically legally valid.

This is important for both our company and other companies looking for a long term electronic document storage solution. Our product is the first service oriented solution to receive the accreditation.

Congratulations to everyone involved in the product. Well done!

Saturday, July 05, 2008 10:37:14 PM (Central European Daylight Time, UTC+02:00)  #    Comments [1] - Trackback
Development | .NET | Personal | Work
# Tuesday, April 29, 2008

A .NET application in the company I work for recently started crashing under Windows Vista when trying to open a window implemented in an ActiveX DLL. Investigations showed that they were caused by an AccessViolationException "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". The cause was one of the ActiveX controls in the window. When instantited directly in a .NET Form the exception above was contained in a TargetInvocationException "Unable to get the window handle for the '<control name>' control. Windowless ActiveX controls are not supported.". Knowing that the control didn't suddenly turn windowless we dug deeper.

It turned out that the problem appeared with .NET Framework 2.0 Service Pack 1. Apparently it caused the C# compiler in Visual Studio 2005 and later to set the NXCOMPAT bit for all build targets without an option to turn this new behavior off. For those who don't know, this means that DEP (data execution prevention) will kick in unless it is turned off completely in the operating system. This wouldn't be a big deal unless ATL before Visual Studio 2005 didn't have a bug which caused the heap allocated memory not to be flagged as executable, which under the new circumstances results as the already mentioned exception. Windows XP has DEP turned off by default therefore everything still works but in Windows Vista it is turned on and prevents such application from functioning properly.

The best solution would of course be to recompile the ActiveX controls in Visual Studio 2005 or later but this might not be possible if they are supplied by a third party. In this case the most obvious approach to dealing with the situation is to disable DEP in Vista. There is a Data Execution Prevention tab in the Performance Options which open when you click the Settings button in the Performance frame of the Advanced tab in the System Properties dialog but it only allows switching between DEP for all processes with defined exceptions and DEP for essential Windows programs and services, i.e. executables flagged with the NXCOMPAT bit. The only way to turn DEP completely off is executing the following command with administrative privileges:

bcdedit.exe /set {current} nx AlwaysOff

After restart DEP will be turned off and problematic binaries will work once again. To restore the previous (default) state replace AlwaysOff with OptIn. The AlwaysOn option enables DEP for all processes and might cause additional problems (e.g. Google Calendar Sync in its current version 0.9.3.2 doesn't work in this mode).

Unfortunately, this solution would require all your Vista using customers to disable DEP as well which really isn't an option for commercial software. Fortunately, there is another solution. Although there is no compiler option to turn keep the NXCOMPAT bit unset, you can still do this after compilation using the editbin.exe which comes with C++ compiler for Visual Studio 2005 and later:

editbin.exe /NXCOMPAT:NO <filename.exe>

This command removes the NXCOMPAT bit and restores the behavior before .NET 2.0 SP1. If your assembly was signed it also invalidates the signature so you'll have to resign it:

sn.exe -R <filename.exe> <keyfile.snk>

You can automate this by putting the two commands in the Post-build event command line for the project:

editbin.exe /NXCOMPAT:NO "$(TargetPath)"
sn.exe -R "$(TargetPath)" "$(ProjectDir)<keyfile.snk>"

You might need to call vcvars32.bat before that to put the required executables in path and enable editbin.exe dependencies to be resolved. Note that in a completely automated build scenario using MSBuild you'll have to specify full path for the vcvars32.bat because $(DevEnvDir) resolves to *Undefined* outside Visual Studio 2005. Also your strong name key should be in a snk file instead of a password protected pfx file because sn.exe doesn't allow the password to be read from a redirected standard input.

Tuesday, April 29, 2008 3:29:08 PM (Central European Daylight Time, UTC+02:00)  #    Comments [2] - Trackback
Development | .NET | Interop
# Monday, April 14, 2008

The MonthCalendar control's BoldedDates functionality doesn't appear to work properly on Windows Vista. The dates added to any of the BoldedDates, MonthlyBoldedDates and AnnuallyBoldedDates collections are rendered just the same as those not added to any of the collections. The same code works just fine on Windows XP and causes those dates to be rendered bold. The only workaround i've managed to find is disabling visual styles in the application, i.e. commenting out the first line in the Program.Main() method of a new Windows Application:

Application.EnableVisualStyles();

Monday, April 14, 2008 9:54:58 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET
Previous Page Page 3 of 7 in the Development category Next Page
Sponsored Ads

About Me
Currently Reading

Entity Framework 4.1: Expert's Cookbook

Twitter
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

All Content © 2012, Damir Arh, M. Sc. Send mail to the author(s) - Privacy Policy - Sign In
Based on DasBlog theme 'Business' created by Christoph De Baene (delarou)
Social Network Icon Pack by Komodo Media, Rogie King is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.