How to make a singleton dll or exe using C#

L

lightdoll

Hello...Everyone...

i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process , like a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...
 
A

Alberto Poblacion

lightdoll said:
i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process , like
a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...

- Make the constructor private, so that a "new" of your class cannot be
done from outside the class.
- Provide a "factory" static method that, when called, does a "new" of
your class (it can use the private constructor since the method is inside
the class), and then stores the instance it just created in a private static
field, and returns it. If called a second time, the method finds that the
static variable is already initialized and returns it directly, so all the
callers receive the same instance (singleton).

This solves the "singleton" problem. HOWEVER: This DLL will be callable
from .Net consumers. But it will not be callable from C, non-managed C++ or
non-.net VB. The DLLs produced in .Net can be exposed to legacy code as COM
objects, but as far as I know the static method cannot be called through
COM, so the above approach would not be useable in this way.

If you only wanted a singleton in order to use shared data, you can
declare the shared fields as "static" and don't bother making the class
itself a singleton.
 
M

Marc Gravell

C# isn't really geared towards creating out-of-process components in
the way you describe.

2 approaches I can think of:
a: Create it as an exe (perhaps a windows service), and communicate
over sockets or similar (since we are talking C etc, remoting isn't an
option)
b: Make it COM accessible, and create (yeuch) create a facade COM exe
in VB6 or similar; the other processes talk to the VB6, which simply
forwards (via COM) to the C#; the VB6 provides the COM server, the C#
provides the CLR framework.

The first is cleaner, but I have seen examples of the second on the
web.

Marc
 
W

Willy Denoyette [MVP]

lightdoll said:
Hello...Everyone...

i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process , like
a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...

This is exactly what COM+ and the EnterpriseServices are made for.
Derive from ServicedComponent, enable object pooling for the component, set
both the max and min pool size to 1, and enable JITA. Register your C# DLL
as a COM+ server type application and you got a singleton out-proc server,
which you can access from COM (VB6, C, C++, ...) and .NET clients.

The following snippet illustrates how you can declare the required
attributes.

using System.EnterpriseServices;
.....
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: ApplicationName("Singleton")]
[assembly: ApplicationID("xxxxxxxxxxxxxxxxxxxxxxxxxxx")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(Value=false,
Authentication=AuthenticationOption.None)]

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("wwwwwwwwwwwwwwwww")]
public interface ISingleton
{
void Foo();
....
}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=2000)]
[Guid("zzzzzzzzzzzzzzzzzzzzzzzzzzz")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{
public Singleton () {}
public void Foo()
{
....
}
}

Substitute a valid uuid for xxxxxxxxx, wwwwwwwww and zzzzzzzzzzzzzzzzz (run:
uuidgen -x -n3)
Compile and register using regsvcs <yourdll>

Native latebound COM clients can call a method using the ProgId
'VBScript client
set o = CreateObject("SomeOnes.Singleton")
o.Foo()
....
o.Dispose 'when done


Early bound clients (C, VB, C++ etc...) can use the tlb produced by the
registration process,

..NET clients can access the metadata needed by setting a reference to the
assembly containing the interface definition when compiling the client.

csc /r:yourdll singletonclient.cs

and call into the component like this:

....
ISingleton mySingleton = new Singleton();
IDisposable disposableSingleton = mySingleton as IDisposable;
try
{
mySingleton.Foo();
}
finally
{
disposableSingleton.Dispose();
}

Willy.
 
L

lightdoll

Thank you for your reply.

After i made the service component followed your text.

but the service component is n't sigleton.

i have modified your code like below


public sealed class Singleton : ServicedComponent, ISingleton
{

int i = 0;
public Singleton () {}
public int Foo()
{
return ++i;
}
}

after any process will call the service component,
but The component always returns 1;

so i found a web site

http://www.pcreview.co.uk/forums/thread-1382837-2.php

i also modifed a source code .

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("4b3b9bfe-304b-4a5c-ad7f-a1472fdcd41f")]
public interface ISingleton
{
int Foo();

}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=5000)]
[Guid("e57cd005-f67e-44a0-99e4-9c1032c4420a")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{


public Singleton () {}
public int Foo()
{
return SingleInstance.instance.GetFoo();
}
}

public sealed class SingleInstance
{
int i;
public static readonly SingleInstance instance = new
SingleInstance();
public SingleInstance(){}
public int GetFoo()
{
return ++i;
}
}

After any process will call the service, then The i's variable always keep
its value.


Thank you for your reply.
Willy Denoyette said:
lightdoll said:
Hello...Everyone...

i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process , like
a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...

This is exactly what COM+ and the EnterpriseServices are made for.
Derive from ServicedComponent, enable object pooling for the component, set
both the max and min pool size to 1, and enable JITA. Register your C# DLL
as a COM+ server type application and you got a singleton out-proc server,
which you can access from COM (VB6, C, C++, ...) and .NET clients.

The following snippet illustrates how you can declare the required
attributes.

using System.EnterpriseServices;
.....
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: ApplicationName("Singleton")]
[assembly: ApplicationID("xxxxxxxxxxxxxxxxxxxxxxxxxxx")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(Value=false,
Authentication=AuthenticationOption.None)]

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("wwwwwwwwwwwwwwwww")]
public interface ISingleton
{
void Foo();
....
}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=2000)]
[Guid("zzzzzzzzzzzzzzzzzzzzzzzzzzz")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{
public Singleton () {}
public void Foo()
{
....
}
}

Substitute a valid uuid for xxxxxxxxx, wwwwwwwww and zzzzzzzzzzzzzzzzz (run:
uuidgen -x -n3)
Compile and register using regsvcs <yourdll>

Native latebound COM clients can call a method using the ProgId
'VBScript client
set o = CreateObject("SomeOnes.Singleton")
o.Foo()
....
o.Dispose 'when done


Early bound clients (C, VB, C++ etc...) can use the tlb produced by the
registration process,

..NET clients can access the metadata needed by setting a reference to the
assembly containing the interface definition when compiling the client.

csc /r:yourdll singletonclient.cs

and call into the component like this:

....
ISingleton mySingleton = new Singleton();
IDisposable disposableSingleton = mySingleton as IDisposable;
try
{
mySingleton.Foo();
}
finally
{
disposableSingleton.Dispose();
}

Willy.
 
W

Willy Denoyette [MVP]

Make i a class variable, local variables are per method, in your case, i
starts it's life when i gets initialized and ceases to exist when the method
returns.

Willy.



lightdoll said:
Thank you for your reply.

After i made the service component followed your text.

but the service component is n't sigleton.

i have modified your code like below


public sealed class Singleton : ServicedComponent, ISingleton
{

int i = 0;
public Singleton () {}
public int Foo()
{
return ++i;
}
}

after any process will call the service component,
but The component always returns 1;

so i found a web site

http://www.pcreview.co.uk/forums/thread-1382837-2.php

i also modifed a source code .

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("4b3b9bfe-304b-4a5c-ad7f-a1472fdcd41f")]
public interface ISingleton
{
int Foo();

}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=5000)]
[Guid("e57cd005-f67e-44a0-99e4-9c1032c4420a")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{


public Singleton () {}
public int Foo()
{
return SingleInstance.instance.GetFoo();
}
}

public sealed class SingleInstance
{
int i;
public static readonly SingleInstance instance = new
SingleInstance();
public SingleInstance(){}
public int GetFoo()
{
return ++i;
}
}

After any process will call the service, then The i's variable always keep
its value.


Thank you for your reply.
Willy Denoyette said:
lightdoll said:
Hello...Everyone...

i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process ,
like
a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...

This is exactly what COM+ and the EnterpriseServices are made for.
Derive from ServicedComponent, enable object pooling for the component,
set
both the max and min pool size to 1, and enable JITA. Register your C#
DLL
as a COM+ server type application and you got a singleton out-proc
server,
which you can access from COM (VB6, C, C++, ...) and .NET clients.

The following snippet illustrates how you can declare the required
attributes.

using System.EnterpriseServices;
.....
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: ApplicationName("Singleton")]
[assembly: ApplicationID("xxxxxxxxxxxxxxxxxxxxxxxxxxx")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(Value=false,
Authentication=AuthenticationOption.None)]

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("wwwwwwwwwwwwwwwww")]
public interface ISingleton
{
void Foo();
....
}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=2000)]
[Guid("zzzzzzzzzzzzzzzzzzzzzzzzzzz")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{
public Singleton () {}
public void Foo()
{
....
}
}

Substitute a valid uuid for xxxxxxxxx, wwwwwwwww and zzzzzzzzzzzzzzzzz
(run:
uuidgen -x -n3)
Compile and register using regsvcs <yourdll>

Native latebound COM clients can call a method using the ProgId
'VBScript client
set o = CreateObject("SomeOnes.Singleton")
o.Foo()
....
o.Dispose 'when done


Early bound clients (C, VB, C++ etc...) can use the tlb produced by the
registration process,

..NET clients can access the metadata needed by setting a reference to
the
assembly containing the interface definition when compiling the client.

csc /r:yourdll singletonclient.cs

and call into the component like this:

....
ISingleton mySingleton = new Singleton();
IDisposable disposableSingleton = mySingleton as IDisposable;
try
{
mySingleton.Foo();
}
finally
{
disposableSingleton.Dispose();
}

Willy.
 
J

Jon Skeet [C# MVP]

Make i a class variable, local variables are per method, in your case, i
starts it's life when i gets initialized and ceases to exist when the method
returns.

Which i do you mean? I can't see any local variables in the posted
code.

Then again, it's Monday morning, so I'm probably being dumb...

Jon
 
W

Willy Denoyette [MVP]

Jon Skeet said:
Which i do you mean? I can't see any local variables in the posted
code.

Then again, it's Monday morning, so I'm probably being dumb...

No, it's me...., took a cold shower, and things are much clearer now ;-)

Willy.
 
W

Willy Denoyette [MVP]

Please disregard my previous reply.
You need to return true from your overridden CanBePooled method, otherwise
each client will get a new instance of the class.


protected override void Activate() {
// stuff you want to get done when the object gets activated
}
protected override void Construct(string s) {
// stuff you need to get done when the class gets constructed
}
protected override void Deactivate() {
// stuff you wan to get done when the instance gets deactivated
}
protected override bool CanBePooled() {
// return true when you want the instance to get pooled, else
return false.
return true;
}


Willy.

lightdoll said:
Thank you for your reply.

After i made the service component followed your text.

but the service component is n't sigleton.

i have modified your code like below


public sealed class Singleton : ServicedComponent, ISingleton
{

int i = 0;
public Singleton () {}
public int Foo()
{
return ++i;
}
}

after any process will call the service component,
but The component always returns 1;

so i found a web site

http://www.pcreview.co.uk/forums/thread-1382837-2.php

i also modifed a source code .

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("4b3b9bfe-304b-4a5c-ad7f-a1472fdcd41f")]
public interface ISingleton
{
int Foo();

}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=5000)]
[Guid("e57cd005-f67e-44a0-99e4-9c1032c4420a")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{


public Singleton () {}
public int Foo()
{
return SingleInstance.instance.GetFoo();
}
}

public sealed class SingleInstance
{
int i;
public static readonly SingleInstance instance = new
SingleInstance();
public SingleInstance(){}
public int GetFoo()
{
return ++i;
}
}

After any process will call the service, then The i's variable always keep
its value.


Thank you for your reply.
Willy Denoyette said:
lightdoll said:
Hello...Everyone...

i want to make a singleton dll or exe using C#,

i want to call the C# dll or exe from C, C++, VB...

The C# dll will be called by any process(C, C++, VB), after any process
call the C# dll, the C# dll have a same instance all of any process ,
like
a
ATL Singleton(Out-of-Service), so i can use a shared data from C# dll

Could you tell me how i can make this kind of dll by C#...

This is exactly what COM+ and the EnterpriseServices are made for.
Derive from ServicedComponent, enable object pooling for the component,
set
both the max and min pool size to 1, and enable JITA. Register your C#
DLL
as a COM+ server type application and you got a singleton out-proc
server,
which you can access from COM (VB6, C, C++, ...) and .NET clients.

The following snippet illustrates how you can declare the required
attributes.

using System.EnterpriseServices;
.....
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: ApplicationName("Singleton")]
[assembly: ApplicationID("xxxxxxxxxxxxxxxxxxxxxxxxxxx")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(Value=false,
Authentication=AuthenticationOption.None)]

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("wwwwwwwwwwwwwwwww")]
public interface ISingleton
{
void Foo();
....
}

[JustInTimeActivation]
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1,
CreationTimeout=2000)]
[Guid("zzzzzzzzzzzzzzzzzzzzzzzzzzz")]
[ProgId("SomeOnes.Singleton")]
[ComVisible(true)]
public sealed class Singleton : ServicedComponent, ISingleton
{
public Singleton () {}
public void Foo()
{
....
}
}

Substitute a valid uuid for xxxxxxxxx, wwwwwwwww and zzzzzzzzzzzzzzzzz
(run:
uuidgen -x -n3)
Compile and register using regsvcs <yourdll>

Native latebound COM clients can call a method using the ProgId
'VBScript client
set o = CreateObject("SomeOnes.Singleton")
o.Foo()
....
o.Dispose 'when done


Early bound clients (C, VB, C++ etc...) can use the tlb produced by the
registration process,

..NET clients can access the metadata needed by setting a reference to
the
assembly containing the interface definition when compiling the client.

csc /r:yourdll singletonclient.cs

and call into the component like this:

....
ISingleton mySingleton = new Singleton();
IDisposable disposableSingleton = mySingleton as IDisposable;
try
{
mySingleton.Foo();
}
finally
{
disposableSingleton.Dispose();
}

Willy.
 
R

Rathinayagam Saravanan

Hi,

Can someone please tell me if,
1. We can create the tlb file just with a ComVisible property and
'Register for COM interop' project property with a Singleton class?
2. I don't want to use any command line tools like regasm or tlbexp.

It worked fine if the class is not singleton.

Thanks a lot for your response.

Thanks,
Rathi
 
O

Omkar Prabhudesai

Hi,

I tried these things but the strange error that I am getting is
regarding the timeout while creating the object. Following is the Use
case that gives me this error:-

1. Created exe app. and tried to access COM+ object, it successful.

2. Again, tried to access it from another instance of same exe or
totally different exe it fails and Time out error appear.


Can anybody give clue on what is happening?

Thanks,
Omkar
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top