|
|
| "Willy Denoyette [MVP]" wrote:
|
| >
| > | > |
| > |
| > | "Willy Denoyette [MVP]" wrote:
| > |
| > | >
| > | > | > | > |
| > | > |
| > | > | "Andreas Mueller" wrote:
| > | > |
| > | > | > DrBonzo wrote:
| > | > | > > In order to get events back from a DCOM server (an embedded
device
| > | > running
| > | > | > > Windows CE), I seem to have to turn off security for my
process.
| > To
| > | > do this,
| > | > | > > I'm saying:
| > | > | > >
| > | > | > > int ret = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero,
| > | > IntPtr.Zero, 1,
| > | > | > > 3, IntPtr.Zero, 0, IntPtr.Zero);
| > | > | > >
| > | > | > > in the constructor of the first static member of my 'Main'
| > executable
| > | > class.
| > | > | > > This worked OK in VisualStudio '03 under .NET v1, but no
longer
| > works
| > | > under
| > | > | > > VisualStudio '05 under .NET v2. The 'ret' I now get is
| > 0x80010119,
| > | > which
| > | > | > > 'Error Lookup's to:
| > | > | > >
| > | > | > > Security must be initialized before any interfaces are
marshalled
| > or
| > | > | > > unmarshalled. It cannot be changed once initialized.
| > | > | > >
| > | > | > > As far as I can tell, this is the first line of my code that's
| > getting
| > | > | > > executed, so it seems that either the framework or the
compiler is
| > | > doing
| > | > | > > something hidden from me.
| > | > | > This is correct, .NET is build on (D)COM and therefore does call
| > | > | > CoInitializeSecurity itself.
| > | > | > >
| > | > | > > Can anyone explain this and/or suggest a work-around?
| > | > | > >
| > | > | > >
| > | > | >
| > | > | > As this can happen any time, e.g. when .NET wants to load
another
| > | > | > assembly before your call to CoInitializeSecurity, the only
| > workaround I
| > | > | > have found is to provide a "shim" application that just calls
| > | > | > CoInitializeSecurity and then hosts your application using
| > | > | > AppDomain.ExecuteAssembly().
| > | > | >
| > | > | > I have tested this in C# implementation and it works, if the
| > | > | > CoInitializeSecurity is implemented inside of he shim's app
| > assembly.
| > | > | >
| > | > | > static void main()
| > | > | > {
| > | > | > CoInitializeSecurity(..);
| > | > | > AppDomain.CurrentDomain.ExecuteAssembly("yourapp.exe");
| > | > | > }
| > | > | >
| > | > | > To be on the safe side we have decided to build the shim app
using
| > raw
| > | > | > unmanaged C++.
| > | > | >
| > | > | > HTH,
| > | > | > Andy
| > | > | >
| > | > | > --
| > | > | > You can email me directly by removing the NOSPAm below
| > | > | > (e-mail address removed)
| > | > | >
| > | > |
| > | > | Thanks, Andy - I was afraid of something like this.
| > | > |
| > | > | I was trying to avoid being verbose, but just for completeness,
here's
| > the
| > | > | solution structure (simplified):
| > | > |
| > | > | Solution: sol
| > | > | (project/assembly) core
| > | > | core.cs
| > | > | UI
| > | > | UI.cs
| > | > | exe
| > | > | (references core & UI)
| > | > | exe.cs
| > | > |
| > | > | exe.cs contains:
| > | > |
| > | > | public sealed class Exe {
| > | > | private static Core _core;
| > | > | . . .
| > | > |
| > | > | and the Core constructor starts off with the CoInitializeSecurity.
| > | > |
| > | > | To follow up on Andy's suggestion, I don't suppose it's possible
to
| > mix
| > | > | languages in the same 'solution', is it?
| > | > |
| > | >
| > | > Did you read my reply?
| > | > The default CoInitializeSecurity is called by the CLR at the first
call
| > into
| > | > COM, that is' when the first RCW get's created. That means that you
need
| > to
| > | > call CoInitializeSecurity as early as you can, and the earliest is
in
| > your
| > | > Main entry of the program's exe assembly. Note that setting the
security
| > can
| > | > only be done and is "per process", not per application domain!!,
doing
| > it in
| > | > a constructor of a dynamically loaded type make little sense unless
you
| > | > disregard the error returned by CoInitializeSecurity.
| > | >
| > | > Willy.
| > | >
| > | >
| > | >
| > |
| > | Yes, Willy, I read your reply, but I'm apparently confused (basically,
I'm
| > a
| > | C++ guy and inherited this C# code - this was my legator's 1st C#
program
| > & I
| > | think he went a bit 'feature wild' - I see no good reason for this to
be a
| > | multi-assembly solution, but I've been too lazy to flatten it). ...
so
| > | what's an "RCW"? ... and how does "application domain" relate to the
| > | process? ... maybe I need to spend some more time with the dox.
| > |
| > | From experimenting with setting breakpoints, I can assure you that the
| > Core
| > | constructor gets executed before any Main() in the Exe class, so the
1st
| > COM
| > | call is apparently happening before even that, but I don't really
| > understand
| > | where.
| >
| > This is not possible normally, the Main function is the first function
| > called by the CLR after the main assembly has been loaded (the exe). My
| > guess is that you are loading the assembly (or assemblies) from
unmanaged
| > code through COM interop, that is, your main program is unmanaged (C++
??)
| > and your .NET assemblies are registered as COM servers, right?.
| > If that's the case, it makes no sense to CoInitializeSecurity in an
assembly
| > (it never does), it's too late, it's up to the main program (the
unmanaged
| > code) to initialize COM security before calling into COM. ( that is
creating
| > an instance of Core).
| >
| > Willy.
| >
| >
| >
|
| None of the assemblies are registered COM servers, and the whole solution
is
| pure C# and thus all managed I presume. The core assembly does reference
the
| type library for the DCOM remote object, though. Since _core is a static
| member it's constructor gets invoked before any other method (just like
C++,
| right?).
|
Ok, I see all C#, and what kind of application is this, Windows forms or
other?
If it's a non-windows application, you should remove the [STAThread]
attribute from Main or change it into [MTAThread], the STAThread attribute
forces the run-time to initialize COM and it's default security before the
main thread starts executing Main, so initializing COM and COM security at
this point is too late. When Main is not attributed or MTAThread attributed,
no such initialization is done before Main enters.
However, if it's a Windows Forms application things are lot more
complicated. Windows Forms requires you to run Main in an STA. The easiest
thing to do is use the process wide security setting through the registry
(run dcomcnfg). If you need to set the security from code you will have to
PInvoke SetBlanket or CoSetProxyBlanket,
AFIIK, this behavior is the same in VS2003 (.NET 1.1), so my guess is that
the STA attribute (supposed it's there) was added when converting your
project to VS2005.
| But here's something interesting: under VS '03, when I break at the
| CoInitializeSecurity call the call stack shows:
|
| location in Core constructor
| location of: private static Core _core
|
| but under VS '05 it shows:
|
| location in Core constructor
| location of: private static Core _core
| [Native to Managed Transition]
| [Managed to Native Transition]
|
This is new in VS2005, native/managed transitions are now tracked.
Willy.