ORA-12154: TNS:could not resolve the connect identifier specified for asp.net application to oracle

18. November 2010 16:57 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

I had a Windows Server 2003 and I was trying to connect to Oracle with the System.Data.OracleClient provider.

I was able to connect from a console application but not from ASP.NET.
From ASP.NET I only got ORA-12154 errors.

I found that on Windows 2003 Server, ASP.NET applications run in the
security context of the “Network Service” user.

So I tried these two  things:

I first started following these steps:
1. Log on to Windows as a user with Administrator privileges.
2. Launch Windows Explorer from the Start Menu and and navigate to the
ORACLE_HOME folder. It is usually under the oracle instalation folder.
In my case that is C:\oracle\product\10.2.0\client_1
3. Right-click on the ORACLE_HOME folder and choose the "Properties" option
from the drop down list. A "Properties" window should appear.
4. Click on the "Security" tab of the "Properties" window.
5. Click on "Authenticated Users" item in the "Name" list (on Windows XP
the "Name" list is called "Group or user names").
6. Uncheck the "Read and Execute" box in the "Permissions" list under the
"Allow" column (on Windows XP the "Permissions" list is called
"Permissions for Authenticated Users").
7. Re-check the "Read and Execute" box under the "Allow" column (this is
the box you just unchecked).
8. Click the "Advanced" button and in the "Permission Entries" list make
sure you see the "Authenticated Users" listed there with:
Permission = Read & Execute
Apply To = This folder, subfolders and files
If this is NOT the case, edit that line and make sure the "Apply onto"
drop-down box is set to "This folder, subfolders and files". This
should already be set properly but it is important that you verify this.
9. Click the "Ok" button until you close out all of the security properties
windows. The cursor may present the hour glass for a few seconds as it
applies the permissions you just changed to all subfolders and files.
10. Reboot your computer to assure that these changes have taken effect.
(I thought that rebooting was not that important but it seems that you have to reboot to make changes effective)

It sometimes happens that it is not enough, because it seems that some oracle installations need the
the ASP.NET process to run with an account with sufficient privileges.

The second thing you can do in that case is.

1. First open the machine.config file. That will be usually in %windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config

2. Look for something like:

<system.web>
    <processModel autoConfig="true" />

3. Add the userName=”System” attribute. For example

<processModel autoConfig="true" userName="System" />

4. Restart the IIS.

IIS 6 Metabase and IIS 6 Configuration Compatibility

11. November 2010 04:38 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

 

I have a silverlight application that I was trying to publish from Visual Studio to my local IIS and I got this problem:

For the record I have Windows 7.

image

 

So you can write on the Search program and Files “ Turn Windows Features on or off”

 

image

 

And then select

 

image

Set Fixed port for ASP.NET project. Good for Silverlight and Azure projects

11. November 2010 02:57 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

If you are doing Silverlight development, one thing that can be cumbersome is keeping in sync
your development and production settings. Specially if you are using WCF services because you have
to make sure that your ServiceClient.config file has the right values.

What I usually do is this.

1. First set fixed ports for my application. See http://blogs.msdn.com/b/webdevelopertips/archive/2008/11/07/tip-21-did-you-know-how-to-set-a-fixed-port-for-the-developer-web-server.aspx

2. Modify my hosts file in C:\Windows\System32\drivers\etc adding an entry like:

#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
 127.0.0.1       localhost
 127.0.0.1       productionserver.cloudapp.net  

 In this way all you have to change is your hosts file and you keep the same settings for development and for production

Handling Orientation in Silverlight for Symbian

2. November 2010 05:10 by Mrojas in General  //  Tags: , ,   //   Comments (0)

 

One obvious thing in modern symbian mobiles, is how to detect orientation.
I am currently porting some Silverlight 1.0 samples like GrandPiano to Silverlight for Symbian and I was wondering
how can I detect the phone orientation. Well I just analysed the Bing demo and find out that is kind of simple.

What you need is something like this:

public static readonly DependencyProperty OrientationProperty = 
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(Page),
new PropertyMetadata((Orientation)0, new PropertyChangedCallback(OrientationPropertyChanged))); private static void OrientationPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { (sender as GrandPiano).UpdateOrientation(); } private void UpdateOrientation() { base.Width = (this.Orientation == Orientation.Vertical) ? DeviceVerticalSize.Width : DeviceVerticalSize.Height; base.Height = (this.Orientation == Orientation.Vertical) ? DeviceVerticalSize.Height : DeviceVerticalSize.Width; base.Clip = new RectangleGeometry { Rect = new Rect(new Point(), new Size(base.Width, base.Height)) }; } // Properties public Orientation Orientation { get { return (Orientation)base.GetValue(OrientationProperty); } set { base.SetValue(OrientationProperty, value); } }

Silverlight Symbian: Silverlight Content on this website cannot be displayed on this device

1. November 2010 06:10 by Mrojas in General  //  Tags: , ,   //   Comments (0)

When I wrote my first application for Silverlight on Symbian, I kept getting this annoying
message I really didnt get why was it.

Finally I downloaded the Bing Xap file and looked at it. And it seams it was just something simple.

<?xml version="1.0" encoding="utf-8"?>
<Deployment 
xmlns=http://schemas.microsoft.com/client/2007/deployment
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
ExternalCallersFromCrossDomain="ScriptableOnly"
EntryPointAssembly="BingNokia"
EntryPointType="BingNokia.App"

RuntimeVersion="2.0.31005.0"

>
  <Deployment.Parts>
    <AssemblyPart x:Name="BingNokia" Source="BingNokia.dll" />
    <AssemblyPart x:Name="Microsoft.Windows.Controls.WatermarkedTextBox" Source="Microsoft.Windows.Controls.WatermarkedTextBox.dll" />
    <AssemblyPart x:Name="Mvc" Source="Mvc.dll" />
    <AssemblyPart x:Name="System.Xml.Linq" Source="System.Xml.Linq.dll" />
  </Deployment.Parts>
</Deployment>

My runtime version was wrong.

<Deployment 
xmlns=http://schemas.microsoft.com/client/2007/deployment
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
EntryPointAssembly="NokiaTest1"
EntryPointType="NokiaTest1.App"
RuntimeVersion="3.0.40818.0"> <Deployment.Parts> <AssemblyPart x:Name="NokiaTest1" Source="NokiaTest1.dll" /> </Deployment.Parts> </Deployment>

I still dont how to customize my AppManifest file
I suppose that behaviour is due to the fact that I have Silverlight 3 installed in my machine.
So what I did is that I compiled my application. Then renamed my .xap for .zip. Extracted my AppManifest.xml and modified it
changing the runtime version and copied it back to my .xap file. And voila!

Starting a Project for the Cloud

27. October 2010 08:43 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

 

If you dont have Windows Azure Tools installed

1. Open Visual Studio 2010

2. On the File Menu, Click new, and then click Project. This opens the New Project dialog

3. In the New Project dialog under Installed Templates, expand the Visual C# node

4. In project type click Cloud. A project that says Enable Windows Azure Tools appears

5. In Name type for example EnableTools and click OK

6. A project with a web page will appear. Click the Download Windows Azure Tools button. Close Visual Studio. Download and installed them.

image

Once you have Windows Azure Toolsl installed

 

1. Open Visual Studio 2010

2. On the File Menu, Click new, and then click Project. This opens the New Project dialog

3. In the New Project dialog under Installed Templates, expand the Visual C# node

4. In project type click Cloud. A project that says Windows Azure Cloud Service appears

image

5. In Name Type for example Phonebook  and click ok. The New Cloud Service Project is shown

 

If you are developing a Silverlight application with some services select the WCF Service Web Role. Rename it to something appropriate. In this example will be Phonebook.Web and Press OK

image

Your solution explorer will look like this:

image

Now you can developing your application. We already have an Silverlight application (that was migrated from VB6 to Silverlight) and some existing Silverlight Class libraries and Server Class Libraries (Class Libraries compiled with the full 4.0 Framework that will be used in the Server Project Phonebook.Web).

To add your Silverlight app. Right Click your server project (Phonebook.Web), then Properties and in Properties go to Silverlight Application and add Phonebook_Silverlight

When everything compiles Go to the Visual Studio Menu Bar, then Debug and then Start Without Debugging. That starts the local development environment on your computer.

image

You can now start testing and finish development of your application.

There is something you myst notice. Everytime you start the Cloud Service, the Azure test environment starts. By default it will start in http:\\localhost:81 but there was a previous Development Fabric it will start in http:\\localhost:81. This is important for Silverlight applications because you must configure your service end point to a particular port. Make sure that your ServiceReferences.ClientConfig file is in sync with the port that your DevelopmentFabric is using

Notes for Azure development:

Sometimes during development it might happen that you get more than one instance of the Development Fabric. This will affect your silverlight apps that rely on WFC services because each new instance starts on a new port. You can use the CSRun tool to stop all instances.

If you have installed the Windows® Azure™ SDK to the default location, the CSRun tool can be found at C:\Program Files\Windows Azure SDK\v1.0\bin\csrun.exe.Then run C:\Program Files\Windows Azure SDK\v1.2\bin\csrun.exe /devfabric:shutdown

 

Publishing your Application

1. Navigate to Azure : https://windows.azure.com/Cloud/Provisioning/Default.aspx

2. On the page that says My Projects. When you are starting you will only see one project line. Click on it

image

3. Click on New Service

image

4. Click on Hosted Services

image

5. In the Create Service page, specify the service properties. In this example we will use Phonebook.Web for service label and a short description and press next.

image

6. Now your hosted service needs a public url. You must check availability. In this example we will use phonebook. Hosted Affinity tries to group your services and storages in the same area. We have a SQL Azure database that is hosted in North Central US, so we will create a new AffinityGroup and call it PhonebookGroup. Press Create

image

7. After Creation your Service is ready, and you can start the deployment.

image

 

8. In Visual Studio 2010 Right click your Cloud Service. And Select Publish…

image

 

9. The Publish Cloud Service Dialog appears. From the Credentials drop down list select <Add>

image

10. From the Create or select an existing certificate select <Create>.
10.1 In our example we will enter a FriendlyName for the new certificate of PhoneBook.

image


10.2 Click the “Copy the full path” link in the dialog. Then Open your browser and navigate to https://windows.azure.com/cloud/provisioning/ and click on your project

 

image

10.3 Now click on account.And in the Account page click on Manage My API Certificates

image

10.4 Click the Choose file and paste the full path you had copied before and then click upload

image

the installed certificate will be shown below.

image

10.5 Now navigate to AppFabric by clicking AppFabric on the left hand side. This will show your subscription ID. Select it and copy it. You have to pasted on the dialog box in Visual Studio on the textbox that says above it “Copy the subscription ID”

image

and name those Credentials PhonebookAccount and press  OK

 

 

 

 

 

 

 

 

 

11 You need a storage account. If you have not created one. Then you have to follow these steps:

11.1 Open your browser and navigate to https://windows.azure.com/cloud/provisioning/ and click on your project.

 

image

11.2 Now click on New Service

image

11.3 Now click on Storage Account

image

11.4 The Create Service Page is show. Enter a Service label and Description and Click Next

image

 

 

 

11.5 Select a name for the public URL, check its availability. And select Affinity.And press Create

image

12. Press OK on the Publish Cloud Service Dialog

 

image

13. Visual studio will upload your application to the cloud

image

While your application is in staging the only problem might be that the published URL changed and that might be conflictive for your ServiceReferences.ClientConfig.

Once your application is on Staging you can switch it to Production and your are ready for business.

Create a Database in SQL Azure

26. October 2010 06:28 by Mrojas in General  //  Tags: , , , , , ,   //   Comments (0)

One of the first steps to put your database in Windows Azure is to put your data on the cloud.

1. The first step is to log in to Azure

1.a) Go to https://windows.azure.com/Cloud/Provisioning/Default.aspx 

1.b)Type your user name and password.

1.c) When your are logged in go to SQL Azure option on the left hand menu.

1.d) You will see a list of your projects. Click on the project.

image

2. You must accept Azure Terms of Use

image

3. Now create a server. You must indicate an administrator username and password. Azure will set the server name.
Press the Create Server button and continue.

image 

4. Now let’s create a new database.Press the Create Database Button

image

5. Just type your database name, edition and size. Editions can be Web or Business.
At this moment Size for Web Edition is 1GB or 5GB and for Business is 10GB, 20GB, 30GB, 40GB and 50GB.
Prices varies according to the options that you select.
For my purposes I will select a Web Edition of 1GB

image

6. You should be able to see your new database in the Databases list.

image

7. Configure Firewall settings so you can connect to the new database.

image

7.1 Press the Allow Microsoft Services access to this server checkbox.
That will add a Rule Name that allows access from 0.0.0.0 to 0.0.0.0.
Select the rule and press Edit. You must can type something like 0.0.0.0 to 255.255.255.255 to allow access to all IP Address.

Moving your data to SQL Azure

The easiest way to upload a SQL Server database to SQL Azure is to use
the SQL Azure Migration Wizard this is a great tool that you can download from
CodePlex http://sqlazuremw.codeplex.com/

1. Download the tool. In my case I installed it in D:\SQLAzureTools. Run SQLAzureMW.exe

image

2. Select SQL Database and press Next

image

3. Select your database and press connect. That will add your database to a list. Click on your database name and press Next

image

4. Select the tables and other object that you will move to your SQL Azure database

image

5. Press Next a Summary is presented with all options

image

 

 

 

6. The wizard will generate a BCP file and a script for your tables.

image

You can connect to run your scripts with the following command:

> sqlcmd -S tcp:<servername>.database.windows.net -U <username>@<servername> -P <password> –d <database>

Depending on your configuration you might have problems with BCP. In general you need something like:

To export data:

bcp PhoneBook out c:\temp\Phonebook-c.dat –S <Server> –T –c

-T  means a trusted connection and native format

To import data

bcp Phonebook.dbo.Phonebook in c:\temp\Phonebook-c.dat -c -U <username>@<servername> -P <Password> -S tcp:<servername>.database.windows.net -c

 

 

 

 

 

 

After importing your data, you are set to keep on developing your applications on Azure

NOTE:

If you dont know the schema name connect to your database and run something like:

SELECT '['+SCHEMA_NAME(schema_id)+'].['+name+']' AS SchemaTable FROM sys.tables

Silverlight for Nokia!! WOW! Just about time

25. October 2010 03:45 by Mrojas in General  //  Tags: , ,   //   Comments (0)

I am a big fan of mobile applications and recently due to our migration activities
(we now offer migrations from VB6 and WinForms to Silverlight)
have been involved with Silverlight programming.

I have done some mobile application development activities
in J2EE and flash and I am now very happy with Silverlight.

What makes me even happier is that I am a Symbian fan and I can now
start developing applications for my Nokia phone with silverlight.

Dont miss it!: http://www.silverlight.net/getstarted/devices/symbian/

 

 

How to restore SQLSERVER .bak file to .mdf

22. October 2010 06:51 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

If you have a .bak file, and all you want is to restore that file to a mdf. Then this is what you can do.

First you need an empty .mdf and .ldf files. The easier way to do that is to create a WebProject in Visual Studio and then In the App_Data folder right click and add new database. That will create an mdf and a .ldf.

Now copy those files to the data directory of your SQLSERVER Express. If it usually under the C:\Program Files\Microsoft SQL Server. In my case it is in C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\

So if your database is PhoneBook just copy:

copy PhoneBook.mdf “C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook.mdf”
copy PhoneBook_log.ldf “C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook_log.ldf”

Now attach your database:

open a Visual Studio 2008 Command Prompt or other prompt (Remember to right click the Run as Administrator, specially if it is Vista)

in the command prompt run:

sqlcmd –S ./SQLEXPRESS

and run the following commands:

CREATE DATABASE Phonebook ON
( FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\Phonebook.mdf' ),
( FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\Phonebook_log.ldf' )
FOR ATTACH ;
GO

copy your .BAK file to the data directory.

copy PhoneBook.bak “C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook.bak”

NOTE: Why the data directory: It seams that in some installation you can have permitions issues

RESTORE DATABASE PhoneBook
FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook2.BAK'
WITH MOVE 'Phonebook' TO 'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\Phonebook.mdf',
MOVE 'Phonebook_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\Phonebook_log.ldf',
REPLACE

After that if everything runs ok then you can detach your database:

1> exec sp_detach_db 'Phonebook'

Now you can copy your mdf files back to where you wanted them

NOTE: If you dont know the name you have to put for Data and Log then Run commands like

RESTORE HEADERONLY FROM DISK ='C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook2.BAK'

RESTORE FILELISTONLY FROM DISK ='C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\PhoneBook2.BAK'

In my case it gives something like:

LogicalName
---------------------------------------------------------------------------------
Phonebook
Phonebook_log

How to create an adding that add context menu for certain files types in Visual Studio

21. October 2010 03:29 by Mrojas in   //  Tags: , , , , , , , , ,   //   Comments (0)

Recently I was looking for a way to create an Adding that will add a Context Menu only when I Right Click on .xaml files.

I know there a many ways now, but I still love using VS studio addins for some simple tasks.

In case you are wondering how to do that 

I found this great article: http://davedewinter.com/2008/03/22/dynamic-menu-commands-in-visual-studio-packages-part-2/

Localization of ASP.NET Login Control

21. October 2010 01:55 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

ASP.NET comes with very nice controls for Login, Password recovery and user creation.

 I have VS 2008 and VS 2010 in English, but I want my application to be available in Spanish and French as well.
If you add your Login control you will see that by default it only shows English captions.
How can you change them?
Well it is very easy.
Just do this:
1. Open your form, the one with the Login Controls.

2. Switch to Design mode

3. Go to the Visual Studio Menus and Select Tools\Generate Local Resource

4. That will generate a new file. That file will be in a directory called App_LocalResources and if your login webform was login.aspx
then the file will be Login.aspx.rexx. Add new pages for you languages like: Login.aspx.es.resx for spanish or Login.aspx.fr.resx for
French.
Behind the scenes, Visual Studio added in the page header a UICulture="auto" attribute.
This tells ASP.net to automatically detect the visitors' prefered language (it's sent in the HTTP headers) and provide them with the
most adequate translation of my page.

In others post I'll give instructions on how to add a languages drop down list to let the user change the displayed language.

What is the ClientBin folder?

16. October 2010 16:25 by Mrojas in General  //  Tags: ,   //   Comments (0)
Silverlight applications are packaged as .xap files. Those files must be keep in your web application. The default directory that is used for that is the ClientBin folder. So if you have silverlight applications associated to your web project their .xap files should go there.

Interop: BinaryCompatibilty for VB6 Migrations

In VB6 when you have an ActiveX Library it was very important to use
the BinaryCompatibility setting to make sure that your applications did not break after a change.

So let’s first introduce what is binary compatibility and how to accomplish that in .NET.

Binary Compatibility allows to make changes to your components or COM classes without recompiling
every application you've made that uses the component.
And why do you need it. Why compatibility breaks.
On lets see.

An ActiveX Control or DLL expose Public interfaces.
Those interfaces have all of the properties, methods, events, etc. that you've marked as Public.
In other words, everything you've added that shows in Intellisense while working outside of your component.

Now let's say you have create a class, with two Methods Method1 and Method2

When you compile, VB generates all the COM infraestructure you need for your component.
It defines a CoClass and an interface and an entry for each method.

For a vb class with two methods:

Sub Method1()

End Sub

Sub Method2()

End Sub

It will produce a typelib like:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>
[
  uuid(8ABA2C0C-7CCA-40CD-A944-56707566634A),
  version(1.0)
]
library Project1
{
    // TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _Class1;

    [
      odl,
      uuid(6B86684C-B3DD-4680-BF95-8DEE2C17AF5B),
      version(1.0),
      hidden,
      dual,
      nonextensible,
      oleautomation
    ]
    interface _Class1 : IDispatch {
        [id(0x60030000)]
        HRESULT Method1();
        [id(0x60030001)]
        HRESULT Method2();
    };

    [
      uuid(C71C7AB0-552A-4D5D-A9FB-AF33830A697E),
      version(1.0)
    ]
    coclass Class1 {
        [default] interface _Class1;
    };
};

As you can see in the typelib there are IDs associated to each coclass, interface and
methods. Those IDs are the ones use when you generate the .exe file for your application.
Now if you modify your Class to:

 

Sub Method3()

End Sub

Sub Method4()

End Sub

Sub Method1()

End Sub

Sub Method2()

End Sub

and you use No Compatibility the typelib after your changes will be:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>

[
  uuid(FE5C56C2-E03A-4DC0-994D-B68543C72A46),
  version(1.0)
]
library Project1
{
    // TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _Class1;

    [
      odl,
      uuid(A3032E1E-52FE-42E0-98FF-84A9DD4FD8C3),
      version(1.0),
      hidden,
      dual,
      nonextensible,
      oleautomation
    ]
    interface _Class1 : IDispatch {
        [id(0x60030000)]
        HRESULT Method3();
        [id(0x60030001)]
        HRESULT Method4();
        [id(0x60030002)]
        HRESULT Method1();
        [id(0x60030003)]
        HRESULT Method2();
    };

    [
      uuid(72721504-CC56-4BB9-9447-C7193FE8C02D),
      version(1.0)
    ]
    coclass Class1 {
        [default] interface _Class1;
    };
};

As you can see, now the ids for the methods, CoClass are different, so your applications will return errors like: Error 430 (Automation error, the component dies horribly) or Error 429 (can't create the object at all)

But if you instead used BinaryCompatibility then the typelib for your class will be:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>
[
  uuid(8ABA2C0C-7CCA-40CD-A944-56707566634A),
  version(1.1)
]
library Project1
{
    // TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _Class1;
    [
      odl,
      uuid(6E9C59C3-82D7-444C-92FB-01B49D91A2FF),
      version(1.1),
      hidden,
      dual,
      nonextensible,
      oleautomation
    ]
    interface _Class1 : IDispatch {
        [id(0x60030002)]
        HRESULT Method3();
        [id(0x60030003)]
        HRESULT Method4();
        [id(0x60030000)]
        HRESULT Method1();
        [id(0x60030001)]
        HRESULT Method2();
    };

    [
      uuid(C71C7AB0-552A-4D5D-A9FB-AF33830A697E),
      version(1.1)
    ]
    coclass Class1 {
        [default] interface _Class1;
    };

    typedef [uuid(6B86684C-B3DD-4680-BF95-8DEE2C17AF5B), version(1.0), public]
    _Class1 Class1___v0;
};

If you compare now the two typelibs you can see the Method1 and Method2 keep the same ids.

For each version a typedef is generated that will point to the last version. For example adding a Method5 will add new entry like:


    typedef [uuid(6B86684C-B3DD-4680-BF95-8DEE2C17AF5B), version(1.0), public]
    _Class1 Class1___v0;

    typedef [uuid(6E9C59C3-82D7-444C-92FB-01B49D91A2FF), version(1.1), public]
    _Class1 Class1___v1;

Well that is what binary compatibility does. Now how to achieve binary compatibility in .NET

Binary Compatibility in .NET

Achieving binary compatibility in .NET is really easy. You just need to give more information to
make explicit how your typelib information will be. I will follow an approach as the one I already explained in this post:
http://blogs.artinsoft.net/mrojas/archive/2010/06/23/exposing-c-classes-thru-interop.aspx

Lets take our previous example:

using System;
using System.Runtime.InteropServices;

namespace InteropExamples
{
    public class Class1
    {
        public void Method3()
        {
        }
        public void Method4()
        {
        }
        public void Method1()
        {
        }
        public void Method2()
        {
        }
        public void Method5()
        {
        }
    }
}

In previous posts I had recommended using partial classes and using interfaces to explicitly specify what you what to be seen in COM. This means you start up with something like:

  public partial class Class1
    {
        public void Method3()
        {
        }
        public void Method4()
        {
        }
        public void Method1()
        {
        }
        public void Method2()
        {
        }
    }

    [ComVisible(true)]
    public interface _Class1
    {
        void Method3();
        void Method4();
        void Method1();
        void Method2();

    }
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(_Class1))]
    partial class Class1 : _Class1
    {
        #region _Class1 Members

        void _Class1.Method3()
        {
            Method3();
        }

        void _Class1.Method4()
        {
            Method4();
        }

        void _Class1.Method1()
        {
            Method1();
        }

        void _Class1.Method2()
        {
            Method2();
        }

        #endregion
    }

Now to make this code binary compatible then you have to make sure that the tlb file generated for your class is almost identical to that generated before. To acomplish that we must make sure that we your methods, interfaces and classes have the same guids and ids. Lets see how:

using System;
using System.Runtime.InteropServices;

namespace InteropExamples
{
    public partial class Class1
    {

        public void Method3()
        {
            System.Windows.Forms.MessageBox.Show("3 N");
        }

        public void Method4()
        {
            System.Windows.Forms.MessageBox.Show("4 N");
        }

        public void Method5()
        {
            System.Windows.Forms.MessageBox.Show("5 N");
        }


        public void Method1()
        {
            System.Windows.Forms.MessageBox.Show("1 N");
        }

        public void Method2()
        {
            System.Windows.Forms.MessageBox.Show("2 N");
        }
    }

    [ComVisible(true)] //This to make the interface Visible for COM
    [TypeLibType((TypeLibTypeFlags)((short)TypeLibTypeFlags.FHidden |
        (short)TypeLibTypeFlags.FDual |
        (short)TypeLibTypeFlags.FNonExtensible |
        (short)TypeLibTypeFlags.FOleAutomation))] //This to use the same flags as in previous tlb
    [Guid("9BAFD76D-8E6B-439C-8B6D-37260BFA3317")] //This is to make the class have the guid
    public interface _Class1
    {
        [DispId(0x60030000)]
        void Method1();
        [DispId(0x60030001)]
        void Method2();
        [DispId(0x60030002)]
        void Method3();
        [DispId(0x60030003)]
        void Method4();
        [DispId(0x60030004)]
        void Method5();


    }

    [ComVisible(true)] //This to make the class Visible for COM
    [ClassInterface(ClassInterfaceType.None)] //This is to make sure that we have control on interface generation
    [ComDefaultInterface(typeof(_Class1))] //To set default interface
    [ProgId("Project1.Class1")] //To set ProgId 
    [Guid("C71C7AB0-552A-4D5D-A9FB-AF33830A697E")] //Maintain same Guid.
    partial class Class1 : _Class1, Class1___v0, Class1___v1
    {
        #region _Class1 Members

        void _Class1.Method3()
        {
            Method3();
        }

        void _Class1.Method4()
        {
            Method4();
        }

        void _Class1.Method1()
        {
            Method1();
        }

        void _Class1.Method2()
        {
            Method2();
        }

        #endregion


        #region Class1___v0 Members

        void Class1___v0.Method1()
        {
            Method1();
        }

        void Class1___v0.Method2()
        {
            Method2();
        }

        void Class1___v0.Method3()
        {
            Method3();
        }

        void Class1___v0.Method4()
        {
            Method4();
        }

        void Class1___v0.Method5()
        {
            Method5();
        }

        #endregion

        #region Class1___v1 Members

        void Class1___v1.Method1()
        {
            Method1();
        }

        void Class1___v1.Method2()
        {
            Method2();
        }

        void Class1___v1.Method3()
        {
            Method3();
        }

        void Class1___v1.Method4()
        {
            Method4();
        }

        void Class1___v1.Method5()
        {
            Method5();
        }

        #endregion
    }

    //This is to keep compatibility with old versions
    //we cannot generate a typedef so we will need to add all of the versions
    //for BinaryCompatibility
    [ComVisible(true)]
    [Guid("6B86684C-B3DD-4680-BF95-8DEE2C17AF5B")]
    [TypeLibType(TypeLibTypeFlags.FHidden)]
    public interface Class1___v0
    {
        [DispId(0x60030000)]
        void Method1();
        [DispId(0x60030001)]
        void Method2();
        [DispId(0x60030002)]
        void Method3();
        [DispId(0x60030003)]
        void Method4();
        [DispId(0x60030004)]
        void Method5();
    }

    //This is to keep compatibility with old versions
    //we cannot generate a typedef so we will need to add all of the versions
    //for BinaryCompatibility
    [ComVisible(true)]
    [Guid("4A7A3317-BF13-443E-9DB0-2C5EA21F00CA")]
    [TypeLibType(TypeLibTypeFlags.FHidden)]
    public interface Class1___v1
    {
        [DispId(0x60030000)]
        void Method1();
        [DispId(0x60030001)]
        void Method2();
        [DispId(0x60030002)]
        void Method3();
        [DispId(0x60030003)]
        void Method4();
        [DispId(0x60030004)]
        void Method5();
    }

}

Sadly in .NET you cannot use Interface Inheritance in COM. If there is interface inheritance YOU HAVE TO IMPLEMENT each interface. In the case of code that comes from VB6. VB6 just uses typedefs, so you really don’t know which methods belong to each version. So in the end all versions have all methods.

The other alternative to this method, is just to implement last version. And after generating the tlb, decompile it to an .IDL file add the typedefs and recompiled it. I explained something similar in this post:http://blogs.artinsoft.net/mrojas/archive/2010/05/17/interop-remove-prefix-from-c-enums-for-com.aspx

Ok. I hope this helps you to have an more clear idea of what Binary Compatibility is and how to do it in .NET. I am attaching some sample code. It show an ActiveX library that uses BinaryCompatibility and three version on an aplications that uses the different versions. And also a .NET class library that is equivalent to the VB6 one. HERE

Enjoy.

Exposing C# Classes thru Interop

23. June 2010 05:38 by Mrojas in General  //  Tags: , , , , , , , , ,   //   Comments (0)

Either if you migrate your application from VB6 to C# or if you develop a new application in C# something you end up with cases where you need to use your classes in legacy apps. Some of them could have been written in VB6 or could even be VBA macros in Excel applications.

Exposing your .NET classes can be sometimes very easy (you can think is just a matter of putting a ComVisible tag) but in other occasions is not that simple. Specially if your legacy application is using a lot of Late Bound calls like in VBA, so you must make sure that the COM information that you are exposing for your class is exactly what you really want and need.

OK. So I will provide some guidelines or some steps you should follow to provide a consistent COM interface for your .NET Code.

1. First you have to add the [ComVisible(true)]  attribute. Don’t think that’s all. Even if in some cases that is enough is better if you take an strict control of want is being generated for your class. Ok Let’s use the following class as an example:

using System;
using System.Runtime.InteropServices;

namespace InteropExamples
{
    [ComVisible(true)]
    public class MyVerySimpleClass 
    {
        public Class2 CreateANewClass()
        {  return new Class2()     }

        public int GetMyLuckyNumber() { return 15; }
    }
public class Class2 { 
  }
}

// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: <could not determine filename>
[
  uuid(370E4AD4-073B-4984-8C7D-5ED027F7B1CA),
  version(1.0)
]
library ClassLibrary1
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _MyVerySimpleClass;

    [
      uuid(E03CCE68-2D55-3576-9DB6-019AAA667A5D),
      version(1.0),
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "InteropExamples.MyVerySimpleClass")
    ]
    coclass MyVerySimpleClass {
        [default] interface _MyVerySimpleClass;
        interface _Object;
    };

    [
      odl,
      uuid(D18BEEE1-4425-3AC7-891E-807EC2283731),
      hidden,
      dual,
      oleautomation,
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "InteropExamples.MyVerySimpleClass")   

    ]
    interface _MyVerySimpleClass : IDispatch {
    };
};

In this case your class will be expose using all defaults. That is, a progId that will be the <AssemblyName>.ClassName an interface _<ClassName> is generated and the class is exposed only for IDispatch, which would not provide class information if you add the tlb reference to a VB6 or VBA project.

And if you run this code in VB6 you will have a problem like type mismatch when you try to use the method x.CreateAClass because it is returning an object that is not exposed thru COM.

Private Sub Command1_Click()
    Dim x As Object
    Set x = CreateObject("InteropExamples.MyVerySimpleClass")
    MsgBox x.GetMyLuckyNumber
    MsgBox x.CreateAClass
End Sub

So my recommendation is to make explicit what you want to expose. Maybe you only need some of the methods to be exposed. Well that is step two.

2. Define a public, ComVisible(true) interface that will define the methods that you want to be exposed thru COM. Sometimes it is better to implement the interface explicitly. I even recommend using partial classes so you isolate the COM stuff from your normal class. If you class is very simple you can leave all COM stuff there.

    //It is better to have an interface, because
    //you are completely sure what you are exposing or not
    [ComVisible(true)]
    public interface _MyVerySimpleClass
    {
        int GetMyLuckyNumber();
    }

3. (Recommedation) This is not an obligatory step but I recommend using partial classes.

    //Using partial classes allow you to separate all the
    //COM plumbing and leave your .NET implementation simple
    public partial class MyVerySimpleClass 
    {
        public Class2 CreateAClass()
        {
            return new Class2();
        }

        public int GetMyLuckyNumber() { return 15; }
    }

3. Make sure your partial class has the following attributes:

[ComVisible(true)] <—This is obvious because you want to use your class in COM

[ClassInterface(ClassInterfaceType.None)] <—This is because your want to take charge or what will be generated in your Typelib (tlb)

[ComDefaultInterface(typeof(_MyVerySimpleClass))] <—This is to indicate the interface that holds your COM visible methods.

[ProgId("InteropExamples.MyVerySimpleClass")] <—To establish which will be the progId not have a generated one
[Guid("{029D468C-8BE6-498f-8A57-3B4B0306BA41}")] <—this is important specially if you are trying to accomplish binary compatibility

Optionally add this attribute [IDispatchImpl(IDispatchImplType.CompatibleImpl)] this is currently marked as an obsolete attribute but it still works and I have found scenarios, specially in some VBA applications where you need this attribute in order to make some late bound calls.

4. And Explicitly implement the interface methods. This is important because some of the return values or arguments might need convertions. For example what can you do if your method returns a DataSet and your Excel VBA script is expecting something like a Recordset (more on this on other posts).

So now you will have a class like:

    //Using partial classes allow you to separate all the
    //COM plumbing and leave your .NET implementation simple
    public partial class MyVerySimpleClass
    {
        public Class2 CreateAClass()
        {
            return new Class2();
        }

        public int GetMyLuckyNumber() { return 15; }
    }

    //It is better to have an interface, because
    //you are completely sure what you are exposing or not
    [ComVisible(true)]
    public interface _MyVerySimpleClass
    {
        int GetMyLuckyNumber();
    }

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)] //This is to make sure that no automatic generation of COM methods is done
    [ComDefaultInterface(typeof(_MyVerySimpleClass))] //This to explicitly establish which is the default interface
    [ProgId("InteropExamples.MyVerySimpleClass")]
    [Guid("{029D468C-8BE6-498f-8A57-3B4B0306BA41}")]
    [IDispatchImpl(IDispatchImplType.CompatibleImpl)]
    partial class MyVerySimpleClass : _MyVerySimpleClass
    {
    
        #region _MyVerySimpleClass Members
        //Explicit implementation is better because it avoids messing your .NET
        //class specification. Sometimes when you expose thru COM you can have problem with
        //methods overloads. For example you have to have the same method name but differente 
        //return type. Or you have a collition with an existing member.
        int _MyVerySimpleClass.GetMyLuckyNumber()
        {
            return GetMyLuckyNumber();
        }

        #endregion
    }

And your TLB is now explicit and exposes ONLY what you really really want.

// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: <could not determine filename>

[
  uuid(370E4AD4-073B-4984-8C7D-5ED027F7B1CA),
  version(1.0)
]

library ClassLibrary1
{
   // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
   // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _MyVerySimpleClass;

    [
      odl,
      uuid(80D00C45-EE10-3D65-A5FF-42AB7D8F8A71),
      version(1.0),
      dual,
      oleautomation,
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "InteropExamples._MyVerySimpleClass")   

    ]
    interface _MyVerySimpleClass : IDispatch {
        [id(0x60020000)]
        HRESULT GetMyLuckyNumber([out, retval] long* pRetVal);
    };

    [
      uuid(029D468C-8BE6-498F-8A57-3B4B0306BA41),
      version(1.0),
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "InteropExamples.MyVerySimpleClass")
    ]

    coclass MyVerySimpleClass {
        interface _Object;
        [default] interface _MyVerySimpleClass;
    };
};

For more info about BinaryCompatibility see my other posts on Interop.

Repair Crashing Open Document in Sharepoint

10. June 2010 08:22 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

I love sharepoint and it is very nice and cool. We use it a lot to share information with our clients. But every know and then when I try to open or check out a document IE just crashes.

So I got tired of it and decided to put an end to that annoyance. I pointed my browser to google and found the: http://www.groovypost.com/howto/microsoft/ie/fix-ie-crash-when-opening-documents-in-sharepoint/ This post recommends running the Microsoft Office Diagnostics Tools and it really works.

If you cannot find your Diagnostics Tools use this page: http://office.microsoft.com/en-us/help/HA012340761033.aspx

 

 

 

 

Interop: Remove prefix from C# Enums for COM

17. May 2010 09:44 by Mrojas in General  //  Tags:   //   Comments (0)

Sometimes when you do a migration, you still need to “Interop” with legacy applications.

Normally this interop is done thru COM and .NET assemblies can be easily registered with COM.
However the devil is in the details, and there are always subtle details that can be difficult to tackle with
COM Interop.

One of those subtle details is that the tlbexp tool (this is the tool that generates the .tlb for a .NET assembly)
generates a prefix for enum elements.

So if you have something in C# like:

using System;
using System.Runtime.InteropServices;

namespace ClassLibrary1
{
    [ComVisible(true)]
    public enum simpleEnum
    {
     Field1 = 1,
     Field2 = 2,
     Field3 = 3,
     Field4 = 4,
     Field5 = 5
    } ;

}

Sadly that would generate a COM Interface like:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>

[
  uuid(D3DB73ED-08B3-4E2F-AD20-61E44E3FDF17),
  version(1.0)
]
library ClassLibrary1
{
    // TLib :     // Forward declare all types defined in this typelib

    typedef [uuid(9D2C80FF-C124-33D2-9991-676A18DA7CAF), version(1.0)    ,
    custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "ClassLibrary1.simpleEnum")    
]
    enum {
        simpleEnum_Field1 = 1,
        simpleEnum_Field2 = 2,
        simpleEnum_Field3 = 3,
        simpleEnum_Field4 = 4,
        simpleEnum_Field5 = 5,
    } simpleEnum;
};

And the problem with that is that your legacy programs are expecting something like:

enum { Field1 = 1, Field2 = 2, Field3 = 3, Field4 = 4, Field5 = 5, } simpleEnum;

Is there a way to solve this?
Well yes there is but it is not a nice one. You have to:

  • take the tlb that the tlbexp tool generates,
  • generate an .idl file from it
  • modify the .idl to correct its syntax
  • change the name of the enum fields
  • compile the .idl file to tlb with the midl compiler
  • use the generated tlb with the legacy application.

Lets see an example. Suppose we have something like:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ClassLibrary1
{
    [ComVisible(true)]
    
    public enum simpleEnum
    {
     Field1 = 1,
     Field2 = 2,
     Field3 = 3,
     Field4 = 4,
     Field5 = 5
    } ;

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)] 
    public class Class1
    {
        public void foo(simpleEnum val)
        {
            switch(val)
            {
                case simpleEnum.Field1:
                    MessageBox.Show("FieldValue1");
                    break;
                case simpleEnum.Field2:
                    MessageBox.Show("FieldValue2");
                    break;
                case simpleEnum.Field3:
                    MessageBox.Show("FieldValue3");
                    break;
                case simpleEnum.Field4:
                    MessageBox.Show("FieldValue4");
                    break;
                case simpleEnum.Field5:
                    MessageBox.Show("FieldValue5");
                    break;
            }
        }
    };

}

When you open that generated IDL with the OLE2VIEW tool:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>

[
  uuid(D3DB73ED-08B3-4E2F-AD20-61E44E3FDF17),
  version(1.0)
]
library ClassLibrary1
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _Class1;

    typedef [uuid(4087FBAF-9633-30D1-8A64-533E37B784B6), version(1.0)    ,
    custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "ClassLibrary1.simpleEnum")    
]
    enum {
        simpleEnum_Field1 = 1,
        simpleEnum_Field2 = 2,
        simpleEnum_Field3 = 3,
        simpleEnum_Field4 = 4,
        simpleEnum_Field5 = 5
    } simpleEnum;

    [
      uuid(0D39F056-DF63-3860-9E79-B57F6358FD4D),
      version(1.0),
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "ClassLibrary1.Class1")
    ]
    coclass Class1 {
        [default] interface _Class1;
        interface _Object;
    };

    [
      odl,
      uuid(1A87868B-7CE6-3C75-B2FA-71A86F77FC7D),
      hidden,
      dual,
      nonextensible,
      oleautomation,
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "ClassLibrary1.Class1")    

    ]
    interface _Class1 : IDispatch {
        [id(00000000), propget,
            custom({54FC8F55-38DE-4703-9C4E-250351302B1C}, "1")]
        HRESULT ToString([out, retval] BSTR* pRetVal);
        [id(0x60020001)]
        HRESULT Equals(
                        [in] VARIANT obj, 
                        [out, retval] VARIANT_BOOL* pRetVal);
        [id(0x60020002)]
        HRESULT GetHashCode([out, retval] long* pRetVal);
        [id(0x60020003)]
        HRESULT GetType([out, retval] _Type** pRetVal);
        [id(0x60020004)]
        HRESULT foo([in] simpleEnum val);
    };
};
 
When you use this tlb for example in VB6 look at the member names for the enum:
 
image 

If you want to be able to use your enum fields unchanged then this is the modified IDL you will have to use. The OLE2View Tool adds an extra “{“ to the IDL custom attribute and the enum name must be put after the enum keyword.

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>

[
  uuid(D3DB73ED-08B3-4E2F-AD20-61E44E3FDF17),
  version(1.0)
]
library ClassLibrary1
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _Class1;

    typedef [uuid(4087FBAF-9633-30D1-8A64-533E37B784B6), version(1.0)    ,
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibrary1.simpleEnum")    
]
    enum simpleEnum {
        Field1 = 1,
        Field2 = 2,
        Field3 = 3,
        Field4 = 4,
        Field5 = 5
    } simpleEnum;

    [
      uuid(0D39F056-DF63-3860-9E79-B57F6358FD4D),
      version(1.0),
        custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibrary1.Class1")
    ]
    coclass Class1 {
        [default] interface _Class1;
        interface _Object;
    };

    [
      odl,
      uuid(1A87868B-7CE6-3C75-B2FA-71A86F77FC7D),
      hidden,
      dual,
      nonextensible,
      oleautomation,
        custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibrary1.Class1")    

    ]
    interface _Class1 : IDispatch {
        [id(00000000), propget,
            custom(54FC8F55-38DE-4703-9C4E-250351302B1C, "1")]
        HRESULT ToString([out, retval] BSTR* pRetVal);
        [id(0x60020001)]
        HRESULT Equals(
                        [in] VARIANT obj, 
                        [out, retval] VARIANT_BOOL* pRetVal);
        [id(0x60020002)]
        HRESULT GetHashCode([out, retval] long* pRetVal);
        [id(0x60020003)]
        HRESULT GetType([out, retval] _Type** pRetVal);
        [id(0x60020004)]
        HRESULT foo([in] simpleEnum val);
    };
};

Save the modified .idl file as ClassLibrary1.dll and run a command like:

midl ClassLibrary1.idl /tlb ClassLibrary1_new.tlb

and then register the new tlb with:

regtlib ClassLibrary1_new.tlb

NOTE: I you cannot find the regtlib tool you can look for it at: %windir%\Microsoft.NET\Framework\v2.0.50727 it will be there with the name regtlibv12.zip. If you still cannot find it, download it from HERE

.HLP files in Windows Vista

13. May 2010 04:07 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

Microsoft has decided that .hlp files are not the best option for your help files.

And you will probably receive an error message like: http://support.microsoft.com/kb/917607

If you still want to run your .hlp help files you still can look for a WinHelp viewer for Vista from Microsoft.

But as someone that has been in the application migration/upgrade bussiness for several year I think automatic migration is a very good option.

 

For example take a look at the following links:

 

 

http://www.herdsoft.com/linux/themen/hlp_to_chm.html 

Some guidance and scripts to help in migrating your files
http://www.helpscribble.com/vista.html Tools to automatically upgrade your .hlp files and projects

Good luck! And If you had any other suggestions just leave a comment.

Which App.Config file will my ServiceComponent load?

30. April 2010 04:51 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

When a VB6 COM+ Component is migrated to a ServiceComponent,
you might want to take advantage of the Configuration files of .NET to specify your
connection strings and other important information.

So where should your App.Config go.

There is a slight diference with a ServiceComponent.
Remember that for a ServicedComponent the hosting process is ‘dllhost.exe’.
So your programs will look for config files in %windir%\System32, which is not a very nice solution.

You can instead set the ‘Application Base Directory’ of the COM+ Application.

Follow these steps:

1) Create an application.manifest file and copy it to the directory
that will be used as the base directory for the COM+ application. The file can be like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"/>

 

2) Create an app.config file and copy that file to the same :

<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
<appSettings>
<add key="ConfigData" value="My Custom AppSetting!" />
</appSettings>
</configuration>
3) Configure the COM+ Application:
3.1) Open the Component Services MMC
3.2) Find the COM+ Application
3.3) Right Click the Application and go to Properties and Activation Tab
3.4) Find option: ‘Application Root Directory’
3.5) Write the path where the other two files where created.
 

This blog post was created from an original Blog Post from HeikkiRi.

AutoCAD VBA Migration to VB.NET or C#

AutoCAD 2010 will not be supporting VBA.

Quoting

“If you utilize VBA macros in your work environment, they will no longer work unless the VBA module is installed on your system. “
“When you run a command that requires VBA, a message dialog box will be displayed stating that VBA is no longer installed with AutoCAD and directing you to a website where you can download the VBA module. “

And also you can see that Autodesk states: “Autodesk is evaluating how long VBA will be supported in Autodesk products in the future. Though supported in the AutoCAD 2010-based products, it may or may not be supported in future releases. Therefore, it is strongly recommended that VB developers develop all new code using VB .NET.

VBA does not support 64bit systems in a native way.

But If you want some advice from the VB migration experts or help on your migration project from VBA to VB.NET or C# you can us contact Artinsoft Migration Services.

We build the VB Upgrade Wizard that shipped with Visual Studio and have been doing VB migrations for years.

DataGridView does not show Horizontal scrollbar

16. February 2010 10:25 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

During a migration from a FlexGrid to a DataGridView, we encountered a situation where the HorizontalScrollBar did not show.

I found many suggestions like setting a MinimumColWidth value for all columns, etc.

But it wasn’t until my friend Jesus added a line like:

 

mygrid.DockStyle = DockStyle.Fill

that the HorizontalScrollBar appear.

It might just be that the grid was too big for form but just for the record this is a possible solution.

Categories