Okay, i've written a Console application and it works. This is the code.
static void Main(string[] args)
{
IceMain.Instance.Start();
Console.ReadLine();
IceMain.Instance.Stop();
IceMain.Instance.Term();
}
Now, when i write a C# Windows Service, and try to start the service. It didn't work. This is the Windows service code...
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
IceMain.Instance.Start();
}
protected override void OnStop()
{
IceMain.Instance.Stop();
IceMain.Instance.Term();
}
}
Of course, i gave it a service name, sid, and setup things correctly.
But when i did the net start sid it gave me:
Microsoft (R) .NET Framework Installation utility Version 4.8.3752.0
Copyright (C) Microsoft Corporation. All rights reserved.
Exception occurred while initializing the installation:
System.BadImageFormatException: Could not load file or assembly 'file:///C:\Project\sptrader_dotnet\ICEService\IcePrice\bin\Debug\IcePrice.exe' or one of its dependencies. An attempt was made to load a program with an incorrect format..
The service name is invalid.
More help is available by typing NET HELPMSG 2185.
All I know is that the underlying application also depends on several x64 C++ DLLs.
But i did set my service to compile in x64 platform, and made sure those Dlls are in the sample folder, but the service still cannot run, while in the Console application, it works.
How is that, and how can i fix it to run on a windows service?
It doesn't seem like it has anything to do with my service name, as I've written many windows service before and it all works, but for this case it involves some C++ DLLs.
The exception System.BadImageFormatException is normally associated with 32 bit Vs 64 bit mismatches.
Possible scenario:
Your service (IcePrice.exe) is a 64 bit process, (i.e., it was built as x64)
But the "actual service registration" is 32 bit, i.e., installed using the 32 bit InstallUtil
Try to install your service using the 64 bit InstallUtil tool
The 64 bit InstallUtil is normally in:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319 (note the '64' in the path)
https://learn.microsoft.com/en-us/dotnet/framework/tools/installutil-exe-installer-tool
When using the 64-bit CLR, use the 32-bit Installer tool to install 32-bit assemblies, and the 64-bit Installer tool to install 64-bit and Microsoft intermediate language (MSIL) assemblies. Both versions of the Installer tool behave the same.
Related
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 :-)
I have a service that I've built using the C# ServiceBase class. It works when I run it in Windows 7 and Windows Server 2008; however, it doesn't work on Windows XP.
I created the service using sc create PBUService binpath= "C:\PBULogger.exe". This is the correct path.
Nothing is logging in the Event Viewer under anything and my exception handling code doesn't fire either.
I thought maybe I didn't have the correct .NET version installed, but I have 4.0 installed on the XP machine. However, I created this project using Visual Studio Express 2012, which I'm pretty sure uses .NET 4.5 by default. Is this causing an issue? All the classes I'm using are version 4.0.
I have stripped down all my code to the base methods and this still doesn't work. Here is my code:
namespace PBULogger {
class PBULoggerService : ServiceBase {
protected override void OnStart(string[] args) {
try {
base.OnStart(args);
} catch (Exception ex) {
EmailUtility.sendEmail("Service Error", ex.Message + ex.StackTrace);
}
}
protected override void OnStop() {
base.OnStop();
}
}
Since it doesn't log in the event viewer, it tells me it isn't even trying to start the service.
I found these entries in my registry for the service under 'HKEY_LOCAL_MACHINE/System/ControlSet001/Enum/Services/PBUService/Enum'.
Not really sure what it means.
Anybody know what's going on?
You must have compiled your exe either for .Net 4.5 or for 64-bit architecture (or both). This is the explanation of error code you run into from WinError.h:
// %1 is not a valid Win32 application.
//
#define ERROR_BAD_EXE_FORMAT 193L
Make sure you have compiled it for x86 platform or Any CPU, and whatever version of .Net Framework you compiled against is installed on the machine.
I found this after googling the windows service error number:
*Generally the error message means that the service manager couldn't find the exact .exe path to run the service. Sometimes, the service is installed from a directory with multiple words for the directory name. So the registry path to the service needs to be placed with double quotes.
Click ‘Start’ and type ‘services.msc’ and hit Enter
Check for the multimedia class scheduler and audio endpoint builder service.
Check for the path under "path to executable:" for both the services. Make a note of the same.
Also make a note of the service name for both the services.
The services are as follows:
AudioEndpointBuilder - AudioEndpointBuilder
Multimedia Class Scheduler - MMCSS
Now, let’s check if the paths under these two services are the same as well in the registry.
Click ‘Start’, type regedit and hit Enter
Locate the following key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
Under services, check for these services: MMCSS and AudioEndpointBuilder.
Corresponding to the above two services, the Image path (on the right pane) should be same as the path in ‘services.msc’*
I found it here
In our case this happened after a server crash and the exe file got corrupted. We re-deployed the binaries and then the service started successfully.
In my case, this was due to building with target of 64-bit only. I forgot that one of my test servers running Server 2003 was 32-bit. My service runs fine on the 64-bit Server 2008 R2 box.
I think that there is a compatibility problem with .net framework that you use and windows server 2003.Do you use .net 4.5? Windows server 2003 can't run applications which target net framework 4.5.
http://www.microsoft.com/visualstudio/eng/products/compatibility
So you could change your target framework to 4.0.
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 have a custom .Net interface written in C++/CLI:
public interface class IBackgroundExtractor
{
};
In my C# application, the interface is used by:
private IBackgroundExtractor extractor = null;
The above code runs smoothly in my computer (which installed visual studio) but it crashed in another one (without installing visual studio):
AppName: speedtest.exe AppVer: 1.0.0.0 ModName: kernel32.dll
ModVer: 5.1.2600.5512 Offset: 00012aeb
If I remove the null assignment, the code will run in both computer:
private IBackgroundExtractor extractor;
However, I made another interface in pure C#. Setting the interface to null will not make the program to crash:
interface IAnotherInterface
{
}
private IAnotherInterface test = null;
What's wrong in my C++/CLI interface?
[Remarks]
I've create two 'clean' new projects for testing, the first one is a C++/CLI Class Library (New Project -> Visual C++ -> CLR -> Class Library). Add the following lines into the .h file of the library:
public interface class ITest {
};
Then create a Windows Form Application project (Net Project -> Visual C# -> Windows -> Windows Forms Application) and declares an ITest variable in the main function:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
ITest xxx = null;
}
The program will run in the development computer (installed visual studio) but crash in two other computers. One of the crashed computers is physical machine and the other one is an virtual machine.
I am using Windows XP Pro SP3, Visual Studio 2010 and .Net Framework 4.0.
Have you checked to make sure the right version of the Microsoft Visual C++ Runtime is installed on the target machines? (Your development environment will already have this installed, but no current version of Windows includes this runtime by default).
If you set up your C++/CLI project to use "SAFE" mode, it will not reference the Microsoft Visual c++ runtime at all (just .NET). See this for reference: Pure and Verifiable Code. If you need to do native stuff, then there's a very high chance that you need to have the latest Visual C++ runtime installed. You can pick up the redistributable here: Microsoft Visual C++ 2010 Redistributable Package.
If you want to verify that this is the problem, you can use the sxstrace tool to diagnose these issues (helpful tutorial).
The null assigment is probably not the error but the trigger for the error. This assigment to null is probably first line of code that accesses that the C++/CLI assembly. So before the that null assigment is even executed, the unmanaged part of C++/CLI assembly is initialized. That is probably where the error is occuring.
I have a program that works fine on VS2008 and Vista, but I'm trying it on Windows 7 and VS2010 / .NET Framework 4.0 and it's not working. Ultimately the problem is that System.Diagnostics.PerformanceCounterCategory.GetCategories() (and other PerformanceCounterCategory methods) is not working. I'm getting a System.InvalidOperationException with the message "Cannot load Counter Name data because an invalid index '' was read from the registry."
I can reproduce this with the very simple program shown below:
class Program
{
static void Main(string[] args)
{
foreach (var pc in System.Diagnostics.PerformanceCounterCategory.GetCategories())
{
Console.WriteLine(pc.CategoryName);
}
}
}
I did make sure I'm running the program as an admin. It doesn't matter if I run it with VS/Debugger attached or not. I don't have another machine with Windows 7 or VS2010 to test it on, so I'm not sure which is complicating things here (or both?). It is Windows 7 x64 and I've tried forcing the app to run in both x32 and x64 but get the same results.
It seems performance counters were corrupted on my system. Although I didn't follow this post exactly, it led me to the solution. Here is what I did:
In an command prompt with administrator/elevate privileges typed the following:
lodctr /?
Useful stuff in there...
Then typed:
lodctr /R
According to the docs from the prior step, this gets windows to rebuild the perf registry strings and info from scratch based on the current registry settings and backup INI files. I have a feeling this is what did the magic. However, next I noticed the .NET performance counters were not there anymore so based on this I typed the following to reload them:
lodctr "C:\Windows\Microsoft.NET\Framework64\v4.0.20506\corperfmonsymbols.ini"
Note that this path is for .NET Framework 4.0 on x64. You can imagine the path for other variations of the framework/platform. I'm guessing you should always load the counters from the highest version of the .NET framework that you have installed, but that is just a guess.
I hope this helps someone else someday!