C# access to C DLL

B

_BNC

Here's the breakdown:

I have an old C DLL that I want to access via C#.

I'm doing this via an outer DLL that wraps the old C DLL in an unmanaged
C++ class, which is in turn wrapped in a Managed C++ class. Both these
unmanaged C++ and managed C++ classes are compiled into a single assembly
(DLL) that is accessed by C#.

[C DLL] <--> [Unmanaged C++ / Managed C++] <--> [C# app]
old dll new C++ assembly app

I don't want to use standard Interop methods. I'm trying to do all the
direct access to the old C DLL with unmanaged C++. The data types in the
old C DLL are relatively complex, so I'm encapsulating the cluttered
legacy stuff in the new unmanaged C++ class.

IOW, I'll usually only be passing ints and a couple strings between the
unmanaged and managed sides.

In general, this approach works, but I'm getting occasional runtime errors
that I can't explain. Could someone post or refer me to a very simple
example that does this with even a single function? Say, take a function
from a stock Windows DLL and show a correct unmanaged C++ class
and managed C++ class that will wrap it correctly.

Thanks for any insights you can provide.
 
B

_BNC

Here's the breakdown:

I have an old C DLL that I want to access via C#.

I'm doing this via an outer DLL that wraps the old C DLL in an unmanaged
C++ class, which is in turn wrapped in a Managed C++ class. Both these
unmanaged C++ and managed C++ classes are compiled into a single assembly
(DLL) that is accessed by C#.

[C DLL] <--> [Unmanaged C++ / Managed C++] <--> [C# app]
old dll new C++ assembly app

I don't want to use standard Interop methods.

Oops. I meant I don't want to use PInvoke. I'm using the flat 'IJW'
model.
 
N

Nicholas Paldino [.NET/C# MVP]

_BNC,

The example isn't going to be that complex, I am afraid. Actually, you
don't even need code to show how to call the C code from the unmanaged C++
code. The issue is properly handling the unmanaged C++ class (since it is
allocated on the unmanaged heap, etc, etc.).

Because your class will have an unmanaged resource in it (the unmanaged
C++ class), you should implement the IDispose interface, so that the Dispose
method can be exposed, and the class can be cleaned up correctly.

For more information on doing this sort of thing, check out the section
of the .NET framework titled "Managed Extensions for C++ Migration Guide",
located at (watch for line wrap):

http://msdn.microsoft.com/library/d.../vcgrfmanagedwrappersaroundunmanagedtypes.asp

Also, if you have time, and think that you can use the CLI extensions
(as managed extensions are going out the window), you might want to do that,
as it would be much easier, from what I hear.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)



_BNC said:
Here's the breakdown:

I have an old C DLL that I want to access via C#.

I'm doing this via an outer DLL that wraps the old C DLL in an unmanaged
C++ class, which is in turn wrapped in a Managed C++ class. Both these
unmanaged C++ and managed C++ classes are compiled into a single assembly
(DLL) that is accessed by C#.

[C DLL] <--> [Unmanaged C++ / Managed C++] <--> [C# app]
old dll new C++ assembly app

I don't want to use standard Interop methods.

Oops. I meant I don't want to use PInvoke. I'm using the flat 'IJW'
model.
I'm trying to do all the
direct access to the old C DLL with unmanaged C++. The data types in the
old C DLL are relatively complex, so I'm encapsulating the cluttered
legacy stuff in the new unmanaged C++ class.

IOW, I'll usually only be passing ints and a couple strings between the
unmanaged and managed sides.

In general, this approach works, but I'm getting occasional runtime errors
that I can't explain. Could someone post or refer me to a very simple
example that does this with even a single function? Say, take a function
from a stock Windows DLL and show a correct unmanaged C++ class
and managed C++ class that will wrap it correctly.

Thanks for any insights you can provide.
 
B

_BNC

[re 'flat model / C++ interop' bridge to unmanaged DLL]

The example isn't going to be that complex, I am afraid. Actually, you
don't even need code to show how to call the C code from the unmanaged C++
code. The issue is properly handling the unmanaged C++ class (since it is
allocated on the unmanaged heap, etc, etc.).
Because your class will have an unmanaged resource in it (the unmanaged
C++ class), you should implement the IDispose interface, so that the Dispose
method can be exposed, and the class can be cleaned up correctly.

I've done all unmanaged mem management (ahem) inside the unmanaged C++
wrapper. I haven't used 'dispose', as I manually keep track of all the
alloc'd memory. I don't think that's the problem, especially in that
there are only a couple large buffers that need to be accounted for. I'll
give that another look, but the code problems occur before the dealloc of
any objects.

The problem IS that the bridge between unmanaged and managed is somewhat
of a black box to me. I don't have time on this project to study the
Marshal class as thoroughly as I'd like, nor to review the sparse examples
that I've seen for 'flat model'. I'm afraid I'm missing something.

Despite that, the only thing I'm passing between managed/unmanaged is a
few pointers, and the code that I was drawing from did not use Marshal for
transfering simple (int, short) types.

The other puzzling thing is that failures are intermittent. It would seem
that (short of a sweep of the memory manager) they should either fail or
succeed. The failure rate seems independent of machine speed or amount of
available ram.

With enough study time and clues, I'd be able to solve this easily, but
unfortunately, the project manager doesn't have much patience for a
methodical approach.
For more information on doing this sort of thing, check out the section
of the .NET framework titled "Managed Extensions for C++ Migration Guide",
located at (watch for line wrap):

http://msdn.microsoft.com/library/d.../vcgrfmanagedwrappersaroundunmanagedtypes.asp

Thanks for the pointer.
Also, if you have time, and think that you can use the CLI extensions
(as managed extensions are going out the window),

!? Uh-oh. I've done a search for CLI Extensions and come up with only a
handful of google hits. Is this part of VS 2005, or is it something that
is currently accessible?

Thanks, Nicholas.

B
 
N

Nicholas Paldino [.NET/C# MVP]

_BNC,

When I said that you would want to expose a Dispose method on the
managed end, it wasn't because of the memory management you use in the
unmanaged code, but for the class you use to wrap that code. Simply, if
your class has all the operations exposed as methods, then you are going to
create and store an instance of that class in the managed wrapper. You
should have a Dispose method on the managed wrapper so that it can dispose
of the unmanaged memory as soon as possible.

Now it could be argued that if you delete the unmanaged memory properly
in the finalizer, then the CLR will handle the memory management. However,
it isn't aware of the pressure that you place on the system to allocate that
class (or the buffers you manage), so it's probably better to expose an
IDisposable implementation.

If you are creating instances of these classes (using auto pointers) and
using them only in your methods, and not storing them on the class level,
then the IDisposable implementation is not needed.

As for CLI, check out the section of the Visual C++ Developers Center
titled "Translation Guide: Moving Your Programs from Managed Extensions for
C++ to C++/CLI", located at (watch for line wrap):

http://msdn.microsoft.com/visualc/w...ull=/library/en-us/dnvs05/html/transguide.asp


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


_BNC said:
[re 'flat model / C++ interop' bridge to unmanaged DLL]

The example isn't going to be that complex, I am afraid. Actually,
you
don't even need code to show how to call the C code from the unmanaged C++
code. The issue is properly handling the unmanaged C++ class (since it is
allocated on the unmanaged heap, etc, etc.).
Because your class will have an unmanaged resource in it (the
unmanaged
C++ class), you should implement the IDispose interface, so that the
Dispose
method can be exposed, and the class can be cleaned up correctly.

I've done all unmanaged mem management (ahem) inside the unmanaged C++
wrapper. I haven't used 'dispose', as I manually keep track of all the
alloc'd memory. I don't think that's the problem, especially in that
there are only a couple large buffers that need to be accounted for. I'll
give that another look, but the code problems occur before the dealloc of
any objects.

The problem IS that the bridge between unmanaged and managed is somewhat
of a black box to me. I don't have time on this project to study the
Marshal class as thoroughly as I'd like, nor to review the sparse examples
that I've seen for 'flat model'. I'm afraid I'm missing something.

Despite that, the only thing I'm passing between managed/unmanaged is a
few pointers, and the code that I was drawing from did not use Marshal for
transfering simple (int, short) types.

The other puzzling thing is that failures are intermittent. It would seem
that (short of a sweep of the memory manager) they should either fail or
succeed. The failure rate seems independent of machine speed or amount of
available ram.

With enough study time and clues, I'd be able to solve this easily, but
unfortunately, the project manager doesn't have much patience for a
methodical approach.
For more information on doing this sort of thing, check out the
section
of the .NET framework titled "Managed Extensions for C++ Migration Guide",
located at (watch for line wrap):

http://msdn.microsoft.com/library/d.../vcgrfmanagedwrappersaroundunmanagedtypes.asp

Thanks for the pointer.
Also, if you have time, and think that you can use the CLI extensions
(as managed extensions are going out the window),

!? Uh-oh. I've done a search for CLI Extensions and come up with only a
handful of google hits. Is this part of VS 2005, or is it something that
is currently accessible?

Thanks, Nicholas.

B
 
W

Willy Denoyette [MVP]

Can't help you if you don't show us some code (preferably a complete sample
that illustrates the problem) and/or more details about the run errors.
My guess is that you are passing un-pinned pointers to unmanaged code.

Willy.
 
B

_BNC

I'm doing this via an outer DLL that wraps the old C DLL in an unmanaged
C++ class, which is in turn wrapped in a Managed C++ class. Both these
unmanaged C++ and managed C++ classes are compiled into a single assembly
(DLL) that is accessed by C#.

[C DLL] <--> [Unmanaged C++ / Managed C++] <--> [C# app]
old dll new C++ assembly app

I don't want to use standard Interop methods. I'm trying to do all the
direct access to the old C DLL with unmanaged C++.

Can't help you if you don't show us some code (preferably a complete sample
that illustrates the problem) and/or more details about the run errors.
My guess is that you are passing un-pinned pointers to unmanaged code.

Yeah, I was hoping that there was a simple code illustration somewhere.
I've seen many examples for PInvoke, but very little info on wrapping
unmanaged code, especially with both unmanaged and managed C++
classes in the same module. (Are there no code samples that do this?
I would have thought it was a common thing to do)

I will try to work up a simple example to post, but it will probably work
OK. The actual app is complex, and apparently only turns up problems
when stressed.

Still, your comment about pinning pointers may well be the main problem.

I've bought plenty of books on the subject (Grimes, Troelsen, etc) but as
I mentioned, my client won't afford the necessary time to dig into it (I
bet no one has heard that before). I believe it will take more more time
to NOT dig into the internals of this, but I don't have the luxury. I do
have a feeling that my initial reference example may have taken some
shortcuts.

Re pinning, a couple Q's come to mind:

Wouldn't pointer corruption only occur when the GC runs? Otherwise,
I can't imagine why a managed pointer would be altered.

How often does the garbage collector normally run on a medium-sized app?
(Presuming that lots of RAM is available)

Any recommended references that address this directly?

_B
 

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