C# COM DLL with Office 2010 64 bit - c#

I may be reposting but I cannot find solution of this.
I create a C# Comvisible Class. This is the following class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace COMTrial
{
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A10B07")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyExample
{
string GetData();
}
[ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(IMyExample))]
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A01B07")]
[ComVisible(true)]
public class Class1
{
public Class1()
{
}
[ComVisible(true)]
public string GetData()
{
return "Vikas";
}
}
}
Then I checked Register for Interop option and even made the complete assembly visible and compile the project and solution.
Then I went to excel and wrote this code:
Dim a as Object
set a = CreateObject("COMTrial.Class1")
It says,
ActiveX cannot create an object.
The only reason I think of is that I am running Office 2010 64 bit with Windows 7 64 bit.

Then I checked Register for Interop option
That will only register your assembly for 32-bit processes. Since this is the 64-bit version of Office, you will need to run Regasm.exe by hand. Do so from the Visual Studio Command Prompt, started with "Run as administrator". Be sure to use the 64-bit version of Regasm.exe, for .NET 4 it is located by default in C:\Windows\Microsoft.NET\Framework64\v4.0.30319. Note the 64. Use the /tlb and /codebase options to match the IDE's behavior.
Another improvement is to use the [ProgId] attribute explicitly so you don't have to guess at the name and won't have a problem if the project name is not "COMTrial".

Related

Can't create C# COM DLL. Is it the code? Project properties? Installer properties? 32-64 bit? What?

Goal: Create a C# Assembly called TestDLL.dll that can be installed to any computer such that MS Access VBA can use it via COM.
Environment:
Windows 7 64-bit.
MS Office Professional Plus 2010 Version: 14.0.1753.5000 (64-bit).
Visual Studio 2010 Professional.
TestDLL.dll assembly code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace TestDLL
{
[ComVisible(true)]
[Guid("7CAAEF3F-F867-445B-B078-5837A833620A")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IGreeting
{
string SayHello();
}
[ComVisible(true)]
[ProgId("TestDLL.Greeting")]
[Guid("73D4187A-F71D-4E45-832A-6DD9F88CC59B")]
[ClassInterface(ClassInterfaceType.None)]
public class Greeting : IGreeting
{
[ComVisible(true)]
public string SayHello()
{
return "Hello, World!";
}
}
}
A WinForms project added to the solution successfully calls the SayHello() method.
TestDLL project properties:
Application / Target Framework - .NET Framework 4
Application / Assembly Information / Make assembly COM-visible: false (I only want certain public classes within the assembly to be COM-visible, not ALL public classes. Even though for this demo there's just one class and I do want it to be COM-visible. The code above should have taken care of that.)
Application / Assembly Information / Title and Description and Company and Product are all "TestDLL".
Build / Platform: Active (any CPU)
Build / Platform target: x86
Build / Register for COM interop: false (I don't want it to work on MY computer only but ALL computers. Thus I want to register the assembly when it is INSTALLED, not when it is BUILT.)
Signing / Sign the assembly: false (I want the assembly to live in the install folder, not in the GAC.)
A peek at AssemblyInfo.cs reveals:
[assembly: ComVisible(false)]
[assembly: Guid("6bf701f9-3953-43bb-a8af-1bdf7818af3c")]
The assembly is built.
Then a type library is created using the Visual Studio Command Prompt (run as Administrator) with this command:
tlbexp "C:\(path)\bin\Release\TestDLL.dll" /win32 /out:"C:\(path)\bin\Release\TestDLL.tlb"
A Visual Studio Installer project called SetupTestDLL is added to the solution.
On its File System tab, Application Folder, TestDLL.dll is added. This automatically also adds TestDLL.tlb.
Right-clicking TestDLL.dll in that Application Folder allows opening a properties window.
There, Register: vsdraCOM
When right-clicking TestDLL.tlb in that Application folder to get the properties window:
Register: vsdrfCOM
(I'm guessing that vsdraCOM means register the assembly and vsdrfCOM means register a file for COM.)
One more file is added to the Application folder: TestDLL.pdb.
SetupTestDLL is built.
Browsing to its output folder, reveals setup.exe and setupTestDLL.msi.
Right-click setup.exe and Run as administrator.
A dialog box displays the correct install path and the correct "Install for everyone" option.
The install completes successfully.
In the Control Panel / Programs and Features, TestDLL is now listed. Its publisher is listed as "XYZ". Where did that come from? Evidently from the "Manufacturer" property of the SetupTestDLL project's property window. I created that value only there in the entire solution.
In C:\Program Files (x86) there is now an "XYZ" folder, under which is a TestDLL folder, and in that are the three files.
Launch MS Access. Open an existing database and its existing code module.
From the Access code window toolbar, choose Tools / References.
TestDLL is found in the Available References listbox. Click its check box and click OK.
Click the Object Browser button on the code window toolbar.
is selected in a dropdown list. Change it to TestDLL.
The class "Greeting" is shown with its method "SayHello". So far, so good.
Close the Object Browser.
Create this procedure in the code module and try to run it.
Public Sub Test2()
' Dim o As New TestDLL.Greeting
' The above is early binding. It should also work
' since we set a reference.
Dim o As Variant
Set o = CreateObject("TestDLL.Greeting")
' The above is late binding.
Debug.Print o.SayHello()
Set o = Nothing
End Sub
Result:
Whether early or late bound,
ActiveX Component can't create object.
What's wrong?
I was just going to add a comment, but I don't have enough reputation points so I'll just post this as an answer and remove it if necessary.
I'm not familiar with Visual Studio Installer projects, so I'm not sure if it is registering the assembly correctly. Have you tried using regasm to register TestDLL? Something like:
regasm /codebase TestDLL.dll /tlb:TestDLL.tlb
64-bit MS Office cannot use a 32-bit COM DLL early bound, but with a reg hack involving DLLSurrogate, it can use it late-bound. I got that to work.

Steps for creating a dll in C# that can then be used from php

By gleaning bits of information from various posts, I have come so far, but still not there yet.
I am trying to create a dll in C# which can then be used by php.
I have created a VS2012 C# class library project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace test1
{
[System.Runtime.InteropServices.Guid("0283F337-AF8D-45BE-BD32-829F5976E9EF")]
[ComVisible(true)]
public class Class1
{
public Class1()
{
// do nothing
}
public int blah()
{
return 42;
}
}
}
Platform Target: Any CPU
Target framework: .NET Framework 4
I have compiled this and have got a test1.dll file.
I have tried registering it with:
regsvr32 test1.dll
but get the following error:
The module "test1.dll" was loaded but the entry-point DllRegisterServer was not found.
Also tried:
regsvr32 /i /n test1.dll
but I get this error:
The module "test1.dll" was loaded but the entry-point DllInstall was not found.
I use:
regasm test1.dll
and that says it is successful.
I next create a test php file:
<?php
$obj = new COM("test1.Class1");
$output=$obj->blah();
echo $output;
?>
I also add the following to my php.ini:
[PHP_COM_DOTNET]
extension=php_com_dotnet.dll
but when I run it, I get:
Fatal error: Uncaught exception 'com_exception' with message
'Failed to create COM object `test1.Class1': Class not registered
So it seems to me that I have to use regsvr32 and make some changes in C# to deal with the DllRegisterServer issue
Can somebody fill me in on what else I need to do to make this work.
I am using:
PHP 5.6.7
Visual Studio Express 2012
Windows 8.1 (64 bit version)
Addendum:
Also tried:
regasm test1.dll /tlb:test1.tlb
regsvr32 test1.tlb
That gives me:
The module "test1.tlb" may not be compatible with the version of Windows
that you're running. Check if the module is compatible with an x86 (32-bit)
or x64 (64-bit) version of regsvr32.exe.
I get that message whether the platform target is "x64" or "any CPU".
test1.dll is not really a COM dll, you can't register it.
You need to follow the steps(https://msdn.microsoft.com/en-us/library/x66s8zcd.aspx) to enable COM.
To set up the code in your class to create a COM object
In Solution Explorer, double-click Class1.vb to display its code.
Rename the class to ComClass1.
Add the following constants to ComClass1. They will store the Globally Unique Identifier (GUID) constants that the COM objects are required to have.
VB.NET
Public Const ClassId As String = ""
Public Const InterfaceId As String = ""
Public Const EventsId As String = ""
On the Tools menu, click Create Guid. In the Create GUID dialog box, click Registry Format and then click Copy. Click Exit.
Replace the empty string for the ClassId with the GUID, removing the leading and trailing braces. For example, if the GUID provided by Guidgen is "{2C8B0AEE-02C9-486e-B809-C780A11530FE}" then your code should appear as follows.
VB.NET
Public Const ClassId As String = "2C8B0AEE-02C9-486e-B809-C780A11530FE"
Repeat the previous steps for the InterfaceId and EventsId constants, as in the following example.
VB.NET
Public Const InterfaceId As String = "3D8B5BA4-FB8C-5ff8-8468-11BF6BD5CF91"
Public Const EventsId As String = "2B691787-6ED7-401e-90A4-B3B9C0360E31"
Make sure that the GUIDs are new and unique; otherwise, your COM component could conflict with other COM components.
Add the ComClass attribute to ComClass1, specifying the GUIDs for the Class ID, Interface ID, and Events ID as in the following example:
VB.NET
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)>
Public Class ComClass1
COM classes must have a parameterless Public Sub New() constructor, or the class will not register correctly. Add a parameterless constructor to the class:
VB.NET
Public Sub New()
MyBase.New()
End Sub
Add properties, methods, and events to the class, ending it with an End Class statement. Select Build Solution from the Build menu.
Now, you can register your dlls using regsvr32.
It's not really an answer, but is a bit of a work round. It looks like the 64 bit version does not work in windows 8.1 or in VS2012 Express or the combination of both even though it is the 64 bit version of the OS.
If I build the solution with a platform target of x86, it all works fine.
I have also discovered that there are two regsvr32.exe files on windows 8.1, one in c:\windows\system32 and one in c:\windows\SysWoW64. I've had no success with either of them.
The first is for registering 64 bit versions of Dlls and the second for 32 bit versions.
Fortunately for me, I don't need to have a 64 bit version.
That all said, I can only register it in VS, so I still have to figure out how to register it on the actual server.
Addendum
Got a step closer today - can now register it on my development PC at the cmd prompt
Steps involved:
Run VS2012 express as administrator
I removed the [System.Runtime.InteropServices.Guid... line as it seems that it is not needed
I signed the assembly:
right click project name in solution explorer and select properties
Select "Signing"
Tick "Sign the assembly"
Choose "New..." under "Choose a strong name key file"
I gave mine a name of test1.snk and chose not to password protect it
Build it (F7)
At the cmd prompt (run as administrator):
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe test1.dll /tlb:test1.tlb /codebase
This now works on my Windows 8.1 PC
I copy this over to the Win 2008 R2 server and try the same:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe test1.dll /tlb:test1.tlb /codebase
but I get a popup window with this error:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe is not a valid Win32 application
followed by a "Access is denied." at the cmd prompt.
I have discovered that there are 12 different versions of regasm.exe installed on Win8.1 and 10 on Win2008R2. I have tried them all, but the one that works is the one I have been using all along.
In case it's of use to anyone, here they are:
WIN 2008 R2
C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
C:\Windows\winsxs\amd64_regasm_b03f5f7f11d50a3a_6.1.7601.17514_none_a3c349b4bdac0898\RegAsm.exe
C:\Windows\winsxs\amd64_regasm_b03f5f7f11d50a3a_6.1.7601.18523_none_a3c462acbdab0575\RegAsm.exe
C:\Windows\winsxs\amd64_regasm_b03f5f7f11d50a3a_6.1.7601.22733_none_8cf7bc12d7517f23\RegAsm.exe
C:\Windows\winsxs\x86_regasm_b03f5f7f11d50a3a_6.1.7601.17514_none_eb70808bd228319e\RegAsm.exe
C:\Windows\winsxs\x86_regasm_b03f5f7f11d50a3a_6.1.7601.18523_none_eb719983d2272e7b\RegAsm.exe
C:\Windows\winsxs\x86_regasm_b03f5f7f11d50a3a_6.1.7601.22733_none_d4a4f2e9ebcda829\RegAsm.exe
WIN 8.1
C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
C:\Windows\WinSxS\amd64_regasm_b03f5f7f11d50a3a_4.0.9600.16384_none_95117f30a7195a76\RegAsm.exe
C:\Windows\WinSxS\amd64_regasm_b03f5f7f11d50a3a_6.3.9600.16384_none_ea742672c514173d\RegAsm.exe
C:\Windows\WinSxS\amd64_regasm_b03f5f7f11d50a3a_6.3.9600.17226_none_ea6df930c519af4b\RegAsm.exe
C:\Windows\WinSxS\amd64_regasm_b03f5f7f11d50a3a_6.3.9600.20708_none_d39e21d6dec31402\RegAsm.exe
C:\Windows\WinSxS\x86_regasm_b03f5f7f11d50a3a_4.0.9600.16384_none_dcbeb607bb95837c\RegAsm.exe
C:\Windows\WinSxS\x86_regasm_b03f5f7f11d50a3a_6.3.9600.16384_none_32215d49d9904043\RegAsm.exe
C:\Windows\WinSxS\x86_regasm_b03f5f7f11d50a3a_6.3.9600.17226_none_321b3007d995d851\RegAsm.exe
C:\Windows\WinSxS\x86_regasm_b03f5f7f11d50a3a_6.3.9600.20708_none_1b4b58adf33f3d08\RegAsm.exe
So I'm a step closer, but still not quite there. Still can't compile a 64 bit version (don't need it, but was hoping I could get that version to work on WIN2008R2) and can't register the 32 bit version (x86) on the server.
Addendum2
Success - finally. I noticed that C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe had a size of zero bytes (goodness knows why), so I copied one from another win2008r2 server and all is well. So I'm a happy man - don't care about the 64 bit version :-)

VS2005 .NET 2.0 and C# and x86 target platform

I use VS2005 on Windows Vista.
I create a very simple Windows application in C# using .NET 2.0, a form with a close button.
Due to a necessary library, I need the VS-option target platform "x86". If I build on Vista and transfer the application to a X64 Windows 7 computer, the application requires administrator rights for execution (UAC-Message-Dialog), which I want to avoid.
If using the VS-option target platform "anyCPU", this works fine, but I need a solution for the target platform "x86".
Can anybody help me?
What I want to do is to change the code or the project configuration to avoid the UAC-Message-Dlg on Windows7 (x64). But I don’t know what I have to do. I need the option “x86”, because we want to use an x86 library. The test code is totally simple (see below), so I presume the problem is in the project configuration:
// Project code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Updater2
{
public partial class Form1 : Form
{
public Form1( )
{
InitializeComponent( );
}
private void toolStripButton1_Click( object sender, EventArgs e )
{
Close( );
} // -- toolStripButtonClose_Click
} // - Form1
}
Chances are you are trying to write files to the C:/ or C:/Program Files folder. Try writing any files to the %Current User% folder to avoid UAC. Apart from that, without seeing any of your code, I can't offer much more of a solution.
The problem is the word "Update" in the program name.
When an executable has words like "Update", "Install" or "Setup" in its name, Windows assumes it may be an installer which will most likely require administrative rights. So, these programs are forced to run with an elevation prompt on UAC-enabled systems.
It's not just the executable name either. If renaming the file does not solve the problem, the application might have these keywords in its version information too. Having the following will result in the same behavior:
[assembly: AssemblyTitle("Setup DVD Player")]
[assembly: AssemblyProduct("Instal President")] // Yes, even with the misspelling.
Easy way out is to rename the application and to avoid using these keywords.
Proper way out is including an application manifest in the executable.

c# excel dll - can't add a reference to the specified file - regasm

When deploying and registering a .Net Excel.dll on another computer, I get an error Can't add a reference to the specified file when attempting to add reference to DLL in VBA editor.
I have created the Excel.dll in C# in Visual Studio that runs fine on my machine with Windows 7 and Office 2010. No problem adding reference to the dll in Excel VBA editor on my computer. My problem is deploying on another machine which is running Vista and Excel 2007. I copied dll to this computer and used regasm to register the dll.
Can anyone point me in the right direction? Here is code and regasm:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe excelDll.dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TestDll
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Test
{
public string HelloWorld
{
get
{
return "Hello World";
}
}
public void sayGoodbye1()
{
MessageBox.Show("Say Goodbye");
}
public string sayGoodbye2()
{
return "Say Goodbye";
}
}
}
You need to register the type library for excel to see your dll in References.
i.e. regasm.exe excelDll.dll /tlb:excelDll.tlb
Mark.
I recently encountered and managed to solve exactly this problem - though I can't claim to understand exactly why my solution worked.
Both my systems are running Windows 7 x64. One has Excel 2010, the other Excel 2007.
All the C# assemblies are set to "Platform Target: Any CPU". The primary assembly is set to "Register for COM Interop". The whole thing is installed using an MSI created by a Visual Studio Installer project.
I found that if I set the Visual Studio Installer project "Target Platform" to "x64", then it works in Excel 2010, but not in Excel 2007. Conversely, if I set the Visual Studio Installer project "Target Platform" to "x86", it works in Excel 2007 but not in Excel 2010.
Sadly, I'm not in a position to test both Excel versions on the same machine at the same time - but at least this might get it working for you!

Unable to instantiate COM library built with Visual Studio 2008 in VBA inside a 64 bit application

I am trying to build an object library which can be registered and used from VBA using 64 bit excel 2010. I am using Dev Studio 2008. I think this is a 64 bit issue as I am pretty sure this worked when I tried it with with my previous version of Excel (XP). I have clicked "Make COM visible" in the Assembly info Information dialog and "Register for COM interop" in the build tag. When I set the target type to x64 I can't see the library in the references dialog at all. I if I select Any CPU I can register it but I get a "Can't create Active X object" error when I try to instantiate it.
namespace Tester
{
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface _Numbers
{
int GetDay();
int GetMonth();
int GetYear();
int DayOfYear();
}
[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Tester.Numbers")]
public class Numbers : _Numbers
{
public Numbers(){}
public int GetDay()
{
return(DateTime.Today.Day);
}
public int GetMonth()
{
return(DateTime.Today.Month);
}
public int GetYear()
{
return(DateTime.Today.Year);
}
public int DayOfYear()
{
return(DateTime.Now.DayOfYear);
}
}
}
Since Visual Studio is a 32-bit process, it will erroneously run the 32-bit version of regasm.exe in order to register your 64-bit assembly. Of course, that version of regasm.exe will write to the 32-bit portion of the registry, so that won't work.
One way to solve the problem would be to run the 64-bit version of regasm.exe on the target assembly yourself (e.g. in a post-build step). You'll need to export its type library using the /tlb option, and you'll also need to pass the /codebase option since the assembly doesn't reside in the GAC:
"%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\regasm.exe"
/tlb /codebase "$(TargetPath)"

Categories