Wednesday, April 13, 2011

Develop an unmanaged DLL (MFC DLL) in VS2010 and Import in managed C# Project



Yesterday I had a need to write a wrapper for a 3rd party ActiveX control (ATL COM dll in VC6). The purpose is to write a wrapper and call from C#. The motive is due to the way ATL ActiveX was developed, there was a design issue in marshalling and when used directly from c# not return the proper results. To cut it short, I was interested to write its wrapper. 
It has been five years; I have not touched COM and VC++ due to the focus in C# majorly. But I was interested to write a wrapper and decided to develop it in VS2010. Question was how to start?
Yes, I should start creating MFC DLL in VS2010 and export a method/calss and call the function from C#.
I decided to create a MFC DLL and choosing type ‘Regular DLL using Shared MFC DLL’. The output produced by this option (dynamically linked) is a small DLL in size. The statically linked DLLs will be of larger size, as they are built with the whole MFC libraries within themselves.  
A MFC Dll can provide/export with functions, variable values, constants and classes. I focused on exporting a function, and then whole class afterwards. 
Then I added two files Util.h and Util.cpp in the project and wrote a sample function ‘Add’. Here is header file single line of code.


extern "C" __declspec(dllexport) int Add (int a, int b);

__declspec(dllexport)'s purpose is to add the "export directive" to the method.  extern "C" is meant to be recognized by a C++ compiler and to notify the compiler that the noted function is compiled in C style.
Here is Utils.cpp code:


#include "stdafx.h"
#include "Util.h"

 __declspec(dllexport) int Add (int a, int b)
{
       return a + b;
}

Compiled the MFC DLL project and it produced TTSUnmanagedWrapper.dll and TTSUnmanagedWrapper.lib in debug folder. There are two debug folders one under project sub folder and other at project root.  Please target the right one mentioned in Output window during compilation proves in VS2010.
Oks now I have MFC DLL available, Question is how to import this Unmanaged DLL to C#?
Crate a new C# Windows Form application and create a new class as follows


using System;
using System.Runtime.InteropServices;

namespace WindowClient
{
    public class NativeDLLHelper
    {

        [DllImport( @"D:\TTSUnmanagedWrapper\Debug\TTSUnmanagedWrapper.dll",
                    EntryPoint = "Add",
                    CallingConvention = CallingConvention.Cdecl)]
        public static extern int Add(int aa, int bb);
   
    }
}

Calling convention CallingConvention.Cdecl means DLL method is in C Calling convention.
And call the method anywhere in C# code like this:

int c = NativeDLLHelper.Add(2, 7);

Next Step: How to export a class instead of single function

Define a new class in Util.h
class __declspec(dllexport) DLLWrapper{
private:

public:
       DLLWrapper();
        
       int DoAdd(int x,int y);

};

And in Util.cpp write following code:

DLLWrapper::DLLWrapper()
 {

 }

int DLLWrapper::DoAdd(int x, int y)
{
       return x+y;
}

Compile the MFC DLL again. 
Now come to NativeDLLHelper class in C# project.

[DllImport( @"D:\TTSUnmanagedWrapper\Debug\TTSUnmanagedWrapper.dll",
                    EntryPoint = "?DoAdd@DLLWrapper@@QAEHHH@Z",
                    CallingConvention = CallingConvention.Winapi )]
        public static extern int DoAdd(int aa, int bb);

I defined the entry point above. It is where ‘Dependency Walker” really helped. 



And Calling convention CallingConvention. Winapi means DLL method is in C++ Calling convention. 
And call the method anywhere in C# code like this:

int d = NativeDLLHelper.DoAdd(3, 5);

That’s it :)

Monday, March 14, 2011

FxCop 10.0 code analysis results are not shown in CCNET Build Report

Situation:
I am using cruise Control .NET (V1.5.7256.1) with TFS 2008 and VS2010.  Integration is such that for each checkin CCNet gets latest version using sourcecontrol type="vsts", and build with MSBuild. My solution contains single project file, I have enabled option “Code Analysis on Build” from Code Analysis tab in VS2010 and selected “Microsoft Minimum Recommended Rules”.
Now FxCop (V10.0) obviously run and generate “[ProjectName].exe.CodeAnalysisLog.xml” file in bin\debug folder when build is successful. Using CC merge tool, I can integrate the results to BuildLog xml files. Everything is working upto this point.  I can see build XML and Fxcop report is integrated nicely.
Problem Statement: when I see build report in dash board, no Fxcop results are displayed. How to identify and integrate FxCop 10.0 xsl to display the results on HTML report is the issue.

Resolution:
I googled for some time and found, CCNet does support FxCop version 1.36 and not later than that. When I browsed to “C:\Program Files\CruiseControl.NET\webdashboard\xsl” folder, I can see “fxcop-report_1_36.xsl” file. So at another place, there was a clue to generate xsl for FxCop 10.0. Very simple, just create a copy of fxcop-report_1_36.xsl with new name “fxcop-report_10_0.xsl” and replace version number in new created file to “10.0”. Here is original code need to replace:
<xsl:variable name="fxcop.root" select="//FxCopReport[@Version = '1.36']" />
 - to -
<xsl:variable name="fxcop.root" select="//FxCopReport[@Version = '10.0']" />
Still no report is coming under Build Log
Then I reached to the conclusion, I should edit dashboard.config to under ccnet website in IIS, so I opened it and append fxcop10 xsl path as follows:
   <buildPlugins>
      <buildReportBuildPlugin>
        <xslFileNames>
          <xslFile>xsl\header.xsl</xslFile>
          <xslFile>xsl\modifications.xsl</xslFile>
          <xslFile>xsl\fxcop-report_10_0.xsl</xslFile>
        </xslFileNames>
      </buildReportBuildPlugin>

I saved the changes, Restarted CCNET service under SCM, then Reset IIS using command line. When I accessed the page, I can see the Build Report with Fxcop 10.0 static code analysis. Here is a snap:

 Great, isn't it :)

Thursday, March 3, 2011

CRM Discovery service, WCF Client and NTLM Authentication on LAN

First point was how I access the Dynamics CRM 4.0 Discovery Service? Here is the url provided in search engines:

http://[IP:port]/MSCrmServices/2007/ad/crmdiscoveryservice.asmx?WSDL

This is a url that can work on CRM server itself and on intranet.
after adding this service reference in a plain c# project, here is bining information added in config file:

<binding name="CrmDiscoveryServiceSoap" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
                </binding>

You can see default security mode is none. Let us try to build access this discovery service.
CrmDiscoveryServiceSoapClient discoSvc = new CrmDiscoveryServiceSoapClient();
NetworkCredential crmCredential = new NetworkCredential(User, Password, Domain);
discoSvc.ClientCredentials.Windows.ClientCredential = crmCredential;
discoSvc.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification;
           
RetrieveOrganizationsRequest orgrequest = new RetrieveOrganizationsRequest();
RetrieveOrganizationsResponse orgresponse = (RetrieveOrganizationsResponse)discoSvc.Execute(orgrequest);
OrganizationDetail myorg = new OrganizationDetail();
foreach (OrganizationDetail organizationDetail in orgresponse.OrganizationDetails)
{
if (organizationDetail.OrganizationName.Equals(orgname, StringComparison.OrdinalIgnoreCase))
       {
             // ...
        }
 }

I get following exception while execution:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'.
I replaced web.cofg security section, and it worked for me.
<security mode="TransportCredentialOnly">
  <transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
  <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

Tuesday, February 15, 2011

Upgrade VS2008 to work with TFS 2010

Steps for VS2008 are quite similar to that for VS2005. You should install the below mentioned components in order. The Installation order is important.
- Install Visual Studio 2008
- Install
Team Explorer 2008
- Install Visual Studio 2008 SP1 (This will upgrade both VS2008 and Team Explorer 2008 to SP1)
- Install
VSTS 2008 Forward Compatibility Update
After the installation is completed successfully, you should provide the entire URL to connect TFS2010 server.
For more details see previous post:

Monday, February 14, 2011

Upgrade VS2005 to work with TFS 2010

Problem Statement: We made a decision move to TFS2010. Problem is we have a set of projects running in .Net Framework 2.0 (VS2005), 3.5 (VS2008) and some in 4.0 (VS2010).
And this it;
VS2010 is fine with TFS 2010. I have to check the feasibility to run TFS 2010 server with old clients VS 2005 and VS2008. Here is the sequence documented in different forums for VS2005:
Connect to TFS2010 Server using VS 2005 Client
1.    Fresh Machine
Be aware that the order of the installation is important for the solution to work correctly.
1.    Install Visual Studio 2005
2.    Install Team Explorer 2005
3.    Install latest Service Pack for Visual Studio 2005
4.    Install the Forward Compatibility Update for TFS 2010
When you install Team Explorer after you install the service pack, Team Explorer will not be patched by the Forward Compatibility Update!
2.    Machine with VS2005 and SP1 installed
Be aware that the order of the installation is important for the solution to work correctly.
1.    Install Team Explorer 2005
2.    Re-Install SP1 for Visual Studio 2005 to upgrade team explorer to SP1.
3.    Install the Forward Compatibility Update

ü  How to know whether VS2005 SP1 is already installed o?
I have some developers running VS2005 from Vista/Windows 7. So I should install ‘VS 2005 SP1 update to Vista/Win7 (not for XP)’ before last step ‘Install the Forward Compatibility Update.
3.    Important URLs for VS2005 upgradation
Here are some of the details:
ü  Visual Studio Team System 2005 Team Explorer
ü  Visual Studio 2005 Service Pack 1 Update for Windows Vista/Windows7  (not needed for XP)
ü  Visual Studio Team System 2005 Service Pack 1 Forward Compatibility Update for Team Foundation Server 2010 (Installer)
4.    How to connect with TFS2010 from VS2005 when everything is installed

As TFS2010 uses concept to Team Project Collections. And path in my case is like http://tfs-server:8080/tfs .  Problem is how to put this connection string in the dialog when there is no ‘Path’ textbox available. If I specify just IP and port, I get error ‘Unable to connect to this Team Foundation Server’. You should provide the entire URL to connect TFS2010 server.

Thursday, February 3, 2011

Full Migration from VSS 2005 to TFS 2010 with History

I wanted to perform 'Full Migration' along with all code/label history to transfer from Visual Source Safe 2005 (or V8) to TFS 2010.

I figured out, VSSConvertor 2010 is more stable than previous versions. All issues reported in previous version are fixed in VSSConvertor10 with framework4.0. VSSConvertor10 does not support old tfs migrations (tfs2008 and tfs2005). We can use VS2010 commandline to use VSSConverter tool. 
Here are the steps:
1. Make sure TFS 2010 is installed on accessible location
2. Make sure, TFS explorer is available on VSS machine
3. VSS is version 2005 or V.8
4. You have Admin password of VSS Application
5. Make sure all files are checked-in by all developers
6. Create a copy of VSS database file (Must do for safety purpose in case things go wrong).
7. Install KB947647 to fix known issue during migration. http://code.msdn.microsoft.com/KB947647/Release/ProjectReleases.aspx?ReleaseId=1028
8. Create the Analysis settings files like analysissettings.xml in a location you want. I have this path on my machine E:\BashVSS2TFSMigration\analysissettings.xml

<?xml version="1.0" encoding="utf-8"?>
<SourceControlConverter>
<ConverterSpecificSetting>
<Source name="VSS">
<VSSDatabase name="E:\BashWorkspace\VSSRepository"></VSSDatabase>
<UserMap name="E:\BashVSS2TFSMigration\Usermap.xml"></UserMap>
<SQL Server="TEO-SRV-CCNET2K\SQLEXPRESS"></SQL>
</Source>
<ProjectMap>
<Project Source="$/PilotProject4Teo"></Project>
</ProjectMap>
</ConverterSpecificSetting>
<Settings>
<Output file="E:\BashVSS2TFSMigration\Analysis.xml"></Output>
</Settings>
</SourceControlConverter>
Here is xml description:

VSSDatabase = VSS Repository/databse file path
UserMap = User mapping frile name to be generated after analysis command.
SQL Server – instance name – can use SQL express for files < 4GB. Otherwise use Full SQL Server Instance where user should have access rights
Project = project name on vss to be ported
Output = analysis file to be generated after analysis command.
9. Analysis Command.

cmd> vssconverter analyze "E:\BashVSS2TFSMigration\analysissettings.xml"

10. Two files are generated with names Analysis.xml and Usermap.xml.
 11. I double clicked Analysis.xml and figure out that one Error Occured. Error was nothing but asking me to install a hot fix in VSS 'KB950185' from path: 
 12. Installed hotfix: KB950185
http://code.msdn.microsoft.com/KB950185/Release/ProjectReleases.aspx?ReleaseId=1123
 13. Again run the analysis command, this time things went correct. Here is analysis report with 0 Error and 1 Warning.
14. I edited Usermap.xml to assign destination users (which are Active Directory Users offcourse mapped to VSS users). History will be transferred to mapped users in tfs.

15. I edited Usermap.xml to assign destination users (which are Active Directory Users offcourse mapped to VSS users). History will be transferred to mapped users in TFS 2010.
<?xml version="1.0" encoding="utf-8"?>
<UserMappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!--
This file is automatically created by VSS Converter. You can optionally use the file to map
a VSS user to a Team Foundation user. For example, <UserMap From="Jane" To="MyDomain\Janep"></UserMap>
This mapping causes all actions logged by VSS user “Jane” to be changed to Team
Foundation user “ MyDomain\Janep ” during migration.
-->
  <UserMap From="basharat.hussain" To="[MyDomain]\basharat.hussain" />
  <UserMap From="Cruisecontrol" To="[MyDomain]\shahid.iqbal" />
  <UserMap From="ADMIN" To="[MyDomain]\tfssetup001" />
</UserMappings>

At least users should have readonly rights on TFS team project.
16. Created a Team Project in TFS with name ‘GD Project’ and provided full rights to domain user ‘basharat.hussain’ and Shahid.Iqbal readonly rights.
17. Created a MigrattionSettings.XML file by copying from AnalysisSettings.XML.

<?xml version="1.0" encoding="utf-8"?>
<SourceControlConverter>
<ConverterSpecificSetting>
<Source name="VSS">
<VSSDatabase name="E:\BashWorkspace\VSSRepository"></VSSDatabase>
<UserMap name="E:\BashVSS2TFSMigration\Usermap.xml"></UserMap>
</Source>
<ProjectMap>
<Project Source="$/PilotProject4Teo" Destination="$/GD Project/PilotProject4Teo"/>
</ProjectMap>
</ConverterSpecificSetting>
<Settings>
<TeamFoundationServer name="192.168.3.249" port="8080" protocol="http"
collection="tfs/DefaultCollection"></TeamFoundationServer>
<Output file="E:\BashVSS2TFSMigration\Migration.xml"></Output>
</Settings>
</SourceControlConverter>
Here is xml description:
Project Source = Project path in VSS
Project Destination = Propased Project path under ‘GD Project’ team project
TeamFoundationServer = TFS2010 DNS or IP address, with port
Collection – Project collection Name, I accessed following url and I can see collection name in web page ‘http://192.168.3.249:8080/tfs/web’
Output = migration file to be generated after analysis command.
18. Migrate Command:
cmd> vssconverter migrate "E:\BashVSS2TFSMigration\MigrationSettings.xml"
19. Inspect TFS 2010 and you can see migrated projects with history
20. Done