I'm using a 3rd party COM Library with C#, all works fine on 32 bit XP. I use tlbimp to create the wrapper, add a reference all works. However, when porting to our Server environment which is 64 bit Windows Server 2008, I've run into a road block.
The code below only runs properly when I right click and test it, ie run within the VS environment. The code does not work when compiled to a Console App, nor does the code work in an Assembly whether in test or called from a console App. In an attempt to get it working I'm running as Administrator and in a 32bit command window - still nothing grouper is always null, and no exception is thrown, indicating that GrpSvr.GrpCall is a valid Com Library name.
string sMessage = "no grouper";
GrpSvr.GrpCall grouper = Activator.CreateInstance(
Type.GetTypeFromProgID("GrpSvr.GrpCall")) as GrpSvr.GrpCall;
if (grouper != null)
sMessage = grouper.GroupInit(#"C:\CmdGrp.txt", true, true);
Console.WriteLine(sMessage);
Try using COM+ as host, and keep your application compiled for 64 bits. For more info see this link
It sounds like the 3rd party COM DLL is 32 bits only. You have to configure your app to run as 32 bits only, instead of any cpu.
Related
There are a few questions (and unwanted answers) all over the forums about Microsoft.ACE.OLEDB.12.0 provider not being registered on the local machine, like this one. The gist of the problem, how I understand it, is that the application will look for the provider on the same platform as what the application is running on. So if your computer is 64 bit and the provider 32 bit, then there will be a mismatch if you don't compile the application to run in 32 bit mode.
Most answers effectively deal with this by installing the appropriate data components for the current platform. Other suggestions are to compile for whichever platform the data components are available.
I am developing an app using PCs running Windows 7, 8 and 10, all 64 bit, depending on where I am, but some have older versions of Office and others newer versions. This causes me to have to change the platform for which I compile depending on the PC I currently work on. While this is no problem for me, personally, I foresee this causing headaches for the end users not being able to run the program.
Trying to avoid asking users to install other components on their computers; is there a way I can tell the program to check the platform availability of the database provider and then run in that mode? Might it be possible to create 32 bit and 64 bit extensions of the database module and load the appropriate one regardless of the mode the main program is running in?
EDIT:
I just tried to compile my database extensions on different platforms Whichever one that is not the same platform as the application causes an exception when being loaded saying that I am attempting to load an assembly from a different platform. So I guess I'm out of luck with my option 2...
You can use CorFlags utility to modify your executable on target machine, after you will detect which mode it needs to run.
First ensure that your main exe is compiled under any cpu with Prefer 32 bit flag not set. Now when application is started you need to check if we are in 64-bit process or not, and also check your dependencies (this I won't cover - I don't work with OLEDB). If you found mismatch (say you are running in 64-bit process but your dependencies are 32-bit) - you need to run external process to modify your main executable and then restart it. Easiest way to do it is via simple cmd script, like this (in this example my main exe is called ConsoleApplication3.exe):
:start
start /wait "" "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\CorFlags.exe" ConsoleApplication3.exe /32BIT+
if errorlevel 1 (
goto start
)
start "" ConsoleApplication3.exe
Note that this is just example and if something goes wrong it will fall into endless loop, adjust to your requirements. What this script does is just updates your exe using CorFlags tool to run in 32-bit mode, then starts your main exe.
Right after starting your application, you might do the following check:
static void Main() {
if (Environment.Is64BitProcess) {
// here you also check if you have dependency mismatch, and then:
Console.WriteLine("Running in 64-bit mode. Press any key to fix");
Console.ReadKey();
// run script (here we assume script is in the same directory as main executable, and is called fix-mode.cmd
var process = new Process() {
StartInfo = new ProcessStartInfo("cmd.exe", "/c call fix-mode.cmd")
};
process.Start();
// here you should exit your application immediatly, so that CorFlags can update it (since it cannot do that while it is running)
}
else {
// after restart by our script - we will get here
Console.WriteLine("Running in 32bit mode");
}
}
Note that this tool (CorFlags) is available only with Visual Studio so you may want to pack it together with your application (might be not available on remote machine).
OK while I never thought in 2012 I would be writing my first ActiveX control (and yes there is a good reason for it) I am struggling with getting it running under Windows 7 (x64).
The Solution Short Story: I was missing /codebase from some of my regasm calls and also mixing up 32 and 64 bit processes, but that wasn't being helped by the standard VS2010 command prompt mixing up 32 and 64 bit paths for regasm and cscript.
The long story follows:
I have been bouncing between
Creating an ActiveX control in .Net using C#
(Oops I had the wrong link .. although it looks like the link I initially supplied was someone copying the original blog page)
Creating an ActiveX control in .Net using C#
and
C# ActiveX control (CSActiveX)
And I appear to be building the projects successfully (for the latter one I had to change the resource compiler location to the correct location).
For the first project I am using the suggested installer, for the second project I am trying to use regasm directly.
But after this it all goes down hill. I try and register the all's but either:
I have no idea how I should be registering them, or:
I have no idea how I should be registering them.
My test case has been a simple JScript file containing
var x = new ActiveXObject( "name of object" );
Which fails with the error:
test.js(1,1) Microsoft JScript runtime error: Automation Server can't create object
I am not sure if this is a permissions issue, or a 32 vs 64 bit issue or a combination.
A lot of sites offering help on ActiveX are assuming you will be accessing it via a web page , so I have tried looking at IE permissions (even though I want to load the control into a 3rd part program).
I know if I use either the 'framework' or 'framework64' versions of regasm I can control where in the registry entries get put - and I have seen some references to running cscript as either 32 or 64 bit (which possible affects what part of the registry is searched) depending on the cmd shell invoked (and I have tried both ways, as well as trying an "administrator" shell).
So basically at this point I have no idea what I am doing or what I should be doing.
My goal is to register an ActiveX control on Windows 7 x64 and have it be able to be loaded by:
A test .js script running from the default Windows command prompt
Load the same control into something like Excel 2007 VBA (for testing only)
Load the control into a 3rd part application (RSView Studio from Rockwell) and have it hosted within a VBA application (and I need to check if this isa 32 or 64bit program .. I suspect the former)
Notes
For the project that users the installer (Creating an ActiveX control in .Net using C#), it installs the code into "c:\program Files (x86)\" and looking with regedit I find entries under "Computer\HKEY_CLASSES_ROOT\Wow6432Node\CLSID\" which I believe is telling me that the DLL was installed as a 32 bit process. I have tried running my cscript test from both a 32 and 64 bit cmd and they both fail. NOTE that the installer was creating the equivalent of "regasm /codebase" when it ran.
For the project where I tried using regasm to register it (C# ActiveX control (CSActiveX)), it has some additional code for registering an ActiveX COM control. This code mentions registering 32 bit in-process servers (see ActiveXCtrlHelpers.cs)
(BTW I'm also cursing auto correct in Safari/Lion at the moment, keeps changing lower case "DLL" into "all")
Edit 2012-08-07
Prompted by Art's answer I discovered:
From standard VS2010 command prompt
When running 'regasm /codebase' through the standard VS2010 command prompt (and as administrator to allow regasm to perform changes), the entries got dumped into the registry under HKEY_CLASSES_ROOT\Wow6432Node\CLSID and the test scripts failed from the same prompt.
However I can see the ActiveX control in Excel 2007 (32 bit)
From x64 Win64 VS2010 command prompt
When running under the VS2010 x64 Win64 command prompt (again as admin) the registry entries appeared under HKEY_CLASSES_ROOT\CLSID but this time the test scripts worked from the same prompt and also from a standard Windows cmd prompt (however they fail from a 32 bit prompt)
But!! I can't see the active X control from Excel 2007 (32 bit)
Now I just need to figure out what the windows equivalent of the *nix 'which' command to ensure which regasm I am using) the 'where' command
Looking at the VS2010 and Windows 7 command prompts:
VS2010 (standard prompt): cscript => c:\windows\system32\cscript.exe
regasm => c:\windows\Microsoft.net\framework\v4.0.30319\regasm.exe
VS2010 (x64 Win 64): cscript => c:\windows\system32\cscript
regasm => c:\windows\Microsoft.net\framework64\v4.0.30319\regasm.exe
Windows 7 std. prompt: cscript => c:\windows\system32\cscript.exe
Windows 7 32 bit prompt: cscript => c:\windows\SysWOW64\cscript.exe
This is all starting to make some of my confusion understandable. I have been unknowingly mixing and matching 32 and 64 bit systems, but the VS2010 standard prompt didn't help either!
(and my latest peeve - VS2010 saving files as UTF-8 with BOM)
I was able to make this work both via IE and vbscript by doing the following:
Create .NET class library named 'ActiveXTest'
Add a class named MyObject which is defined as follows:
namespace ActiveXTest
{
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.ProgId("ActiveXTest.MyObject")]
[System.Runtime.InteropServices.Guid("df2dac4d-ba8a-4ecc-b76e-958c1bc32f1f")]
public class MyObject
{
public string HelloWorld()
{
return "This is Hello World from the COM component!";
}
}
}
Compile the class. Go to the folder where you compiled the class and do the following from a Visual Studio command prompt: regasm /codebase ActiveXTest.dll
To test from a .vbs script, create a file in notepad call test.vbs. type the following into the file:
Dim myObject
set myObject = CreateObject("ActiveXTest.MyObject")
MsgBox(myObject.HelloWorld)
Open a command prompt and navigate to where where you created the Test.vbs and type: wscript test.vbs. A dialog should be displayed stating "This is Hellow World from the COM component"
To test this from IE, I created a TEST.HTML file with the following contents:
<HTML>
<HEAD>
<script language="JScript" language="JavaScript">
var obj = new ActiveXObject("ActiveXTest.MyObject");
alert(obj.HelloWorld());
</script>
</HEAD>
<body>
<span>nothing to see here!</span>
<body>
</HTML>
Open the TEST.HTML file in IE. You will get a warning about the ActiveX control; just say Yes to allow the interaction. You will get an alert dialog stating "This is Hello World from the COM Component".
Similar steps can be used to make it work from a .js file or from Excel VBA. Note that if you change the COM method signature of the ActiveX assembly I believe you will need to re-register it.
We've created a C# class library assembly and made it COM visible to be able to call its methods from PHP. This used to work fine, but now we wanted to install it on a Windows Server 2008 server and we keep walking into the error "Class not registered".
To rule out any dependency problems I made a tiny little test class library in C#. The class library is built for Any CPU and it is COM visible (also set COMVisible to true in AssemblyInfo.cs). The test class library only contains one class with one method. The class is called TestLib and the namespace is also called TestLib. The method is called Test and only returns a string.
What we have done is the following:
- built the TestLib.dll
- copied it to the Windows Server 2008 machine
- registered the dll with: regasm /codebase TestLib.dll
- the regasm tool returns a success message
- in PHP we simply try to create a new COM instance:
try
{
$test = new COM("TestLib.TestLib");
}
catch (Exception $e)
{
die($e->getMessage());
}
when we call this test script from either the browser or the commandline (php -f test.php) we get the error "Class not registered" in both cases
I also tried adding TestLib to the GAC by using gacutil -i, but to no avail; still the class not registered error.
Then I tried compiling the testlibrary with .NET 2.0 instead of 4.0 as the target framework, same result. The .NET framework 4.0 is installed on the server by the way.
Any ideas?
Okay, so after some more research I figured it out. The php.exe process is 32 bit. The COM visible assembly is compiled for Any CPU so it should be accessible to both 32 and 64 bit applications.
The problem is that on a 64 bit OS php.exe, and any 32 bit process for that matter, searches in HKEY_CLASSES_ROOT\Wow6432Node\CLSID instead of HKEY_CLASSES_ROOT\CLSID and in HKEY_LOCAL_MACHINE\Software\Classes\Wow6432Node\CLSID instead of HKEY_LOCAL_MACHINE\Software\Classes\CLSID. The registry entries in the Wow6432 keys aren't created by regasm that is shipped with .NET framework v4 on Windows Server 2008. On Windows 7 they are created, don't ask me why.
It also turned out that if I create a little test assembly for .NET v2.0 and register it with regasm that ships with .NET framework v2.0 that it does create the Wow6432Node entries on Windows 2008. Strange.
So my solution is to create a basic registry file on the server using:
regasm /regfile MyClassLib.dll
This creates a file MyClassLib.reg with only the 'normal' 64 bit entries. Then I exported the Wow6432Node keys from a Windows 7 machine and added it to that .reg file. Now when I import that reg file into the registry on Windows 2008 everything works fine.
For more info on the Wow6432Node entries check out: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724072%28v=vs.85%29.aspx
Hope this saves someone else some time and headaches.
If you are trying to call a 32-bit COM DLL on 64-bit Windows, you will need to register it.
Copy your 32-bit DLL to C:\Windows\sysWOW64
Run C:\Windows\sysWOW64\regsvr32.exe your_com_32.dll
A bit more info with screenshots.
I'm working on a 64 bits application coded with .Net 4.0, C#.
In this application, at some point, I need to start another exe file using the following code :
l_process.StartInfo.FileName = _sFullFilePath;
l_process.StartInfo.Verb = "Open";
l_process.StartInfo.CreateNoWindow = true;
l_process.StartInfo.Arguments = l_sParams;
l_process.Start();
Now, this external application being compiled under 32 bits environment (x86), I get the following error :
**The specified executable is not valid for this OS platform**
Is it even possible to do so ? If yes, how can I manage to start this application from mine without having troubles ?
Usually, no extra work is required to run a 32-bit program on 64-bit machine.
Try to run 32-bit program individually.
Read this: http://www.techsupportalert.com/content/how-windows7-vista64-support-32bit-applications.htm
I've created a C# COM object, and am trying to instantiate it from VBscript (under Windows Scripting Host).
The assembly builds correctly, etc, and RegAsm claims that it is successfully registered. However, whenever I try to instantiate it in a .vbs script, I get:
Error: Could not creawte object named
"MyProgId.blah" Code: 80040154
I'm running Win7 x64 Ultimate, object built for .NET 3.5 with VS2010.
I also tried copying the compiled DLL over to a Win Server 2003 machine, and I get the same results there.
Help.
Also, of note: I can register, but not instantiate, any of our old VB6 COM DLLs. (Yes, I am running the script as administrator.)
Update
Just for grins, I created a test application that uses Type.GetFromProgID() to find and create the object:
Type t = Type.GetTypeFromProgID(progId);
if (t == null)
{
Console.WriteLine("Couldn't create object.");
}
else
{
var obj = Activator.CreateInstance(t);
Console.WriteLine("Successfully created Object: Type is [{0}]", obj);
Console.WriteLine("Calling method [{0}]\n\n", methodName);
var result = t.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null);
Console.WriteLine("Result: {0}", result);
}
This works correctly. Attempting to create the object from VBscript, however, still fails.
Argh.
Update, the 2nd
After running SysInternals ProcMon, I see quite a few registry queries looking for the progID and guid under HKCU\Software\Classes\..., where there is no mention of the object (when I look in RegEdit). There are quite a few NAME NOT FOUND errors.
I've tried registering with the %windir%\microsoft.net\framework\v4... and framework64 versions of regasm, with no effect.
I'm running Win7 x64 Ultimate
That's very relevant to COM issues like these. The error message means that the COM client could not find the registry information for the COM server. The 64-bit version of Windows has two VB-script interpreters, a 64-bit and a 32-bit version. Processes with different bitness have a different view of the registry, a 64-bit client cannot see 32-bit COM servers. And the other way around.
What matters is what version of Regasm.exe you used. There are two, one in C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe, another in Framework64. You by default run the 32-bit version which enters registration info in the 32-bit view of the registry. You should use the 64-bit version from Framework64 instead. Or use both, .NET creates COM servers that can run in both bitnesses.
If you still have trouble then use SysInternals' ProcMon tool to see where the script interpreter is looking for the CLSID key.
If you're running a 32-bit interface under a 64-bit OS, you can get around that VBScript error by using the wscript/cscript under \windows\syswow64 (instead of the default under \windows\system32) to run your script. That tripped me up for a day.
I think that it is possible you are looking at a security issue.
Check out this stackoverflow post and see if this solves your issue.
Cannot instanciate .Net COM object in classic ASP/VBScript page (Error ASP 0177)