No end of problems trying to use a C++ function....

P

Paul Tomlinson

All, i'm at my wits-end. I have this third party C++ function which I am
trying to call from C#, no matter what I try to do I just can't get it to
work.
This is the function prototype in C++:

long IsValidCompressedFile (
const char *pcszSrcFileName,
BOOL *bValid,
char *origFileName,
long lBufferSize);

This has been (one of) my attempt(s) at accessing it in C#:

[DllImport("external.dll")]
public static extern int IsValidCompressedFile( string srcFileName, ref bool
bValid, ref string origFileName, long lBufferSize );

I've then been using it like so:

....
bool bValid = false;
string strOrigFileName = "";
long validRes = SMSPCIsValidCompressedFile( "c:\new.zip", ref bValid, ref
strOrigFileName, 9999999 );
.....

This particular instance fails with "Object reference not set to an instance
of an object"
Will someone, hell *anyone* please clue me up as to how I can access this
function properly. It's been driving me round the bend.

Thanks in advance.
PT
 
D

David Browne

Paul Tomlinson said:
All, i'm at my wits-end. I have this third party C++ function which I am
trying to call from C#, no matter what I try to do I just can't get it to
work.
This is the function prototype in C++:

long IsValidCompressedFile (
const char *pcszSrcFileName,
BOOL *bValid,
char *origFileName,
long lBufferSize);

This has been (one of) my attempt(s) at accessing it in C#:

[DllImport("external.dll")]
public static extern int IsValidCompressedFile( string srcFileName, ref
bool bValid, ref string origFileName, long lBufferSize );

I think it's easiest to marshal the char* as a byte[].

[DllImport("external.dll")]
public static extern int IsValidCompressedFile(
string srcFileName,
ref int bValid,
byte[] origFileName,
int lBufferSize)

David
 
W

Willy Denoyette [MVP]

Paul Tomlinson said:
All, i'm at my wits-end. I have this third party C++ function which I am
trying to call from C#, no matter what I try to do I just can't get it to
work.
This is the function prototype in C++:

long IsValidCompressedFile (
const char *pcszSrcFileName,
BOOL *bValid,
char *origFileName,
long lBufferSize);

This has been (one of) my attempt(s) at accessing it in C#:

[DllImport("external.dll")]
public static extern int IsValidCompressedFile( string srcFileName, ref
bool bValid, ref string origFileName, long lBufferSize );

I've then been using it like so:

...
bool bValid = false;
string strOrigFileName = "";
long validRes = SMSPCIsValidCompressedFile( "c:\new.zip", ref bValid, ref
strOrigFileName, 9999999 );
....

This particular instance fails with "Object reference not set to an
instance of an object"
Will someone, hell *anyone* please clue me up as to how I can access this
function properly. It's been driving me round the bend.

Thanks in advance.
PT

int are 64 bit in C#!
Why ref for 3rd arg and not fot the first?
Change your declaration into:

public static extern int IsValidCompressedFile( ref StringBuilder
srcFileName, ref bool
bValid, ref StringBuilder origFileName, int lBufferSize );

Also make sure API is expecting ANSI strings, and the calling sequence
matches the one used by PInvoke (_stdcall).

Willy.
 
G

Guest

Willy Denoyette said:
Paul Tomlinson said:
All, i'm at my wits-end. I have this third party C++ function which I am
trying to call from C#, no matter what I try to do I just can't get it to
work.
This is the function prototype in C++:

long IsValidCompressedFile (
const char *pcszSrcFileName,
BOOL *bValid,
char *origFileName,
long lBufferSize);

This has been (one of) my attempt(s) at accessing it in C#:

[DllImport("external.dll")]
public static extern int IsValidCompressedFile( string srcFileName, ref
bool bValid, ref string origFileName, long lBufferSize );

I've then been using it like so:

...
bool bValid = false;
string strOrigFileName = "";
long validRes = SMSPCIsValidCompressedFile( "c:\new.zip", ref bValid, ref
strOrigFileName, 9999999 );
....

This particular instance fails with "Object reference not set to an
instance of an object"
Will someone, hell *anyone* please clue me up as to how I can access this
function properly. It's been driving me round the bend.

Thanks in advance.
PT

int are 64 bit in C#!
Why ref for 3rd arg and not fot the first?
Change your declaration into:

public static extern int IsValidCompressedFile( ref StringBuilder
srcFileName, ref bool
bValid, ref StringBuilder origFileName, int lBufferSize );

Also make sure API is expecting ANSI strings, and the calling sequence
matches the one used by PInvoke (_stdcall).

you need to drop the ref on stringbuilder because that's going to be an
additional level of indirection. and the first argument can stay as string
since it's not modified.

and ints are not 64bit in C#, but longs in C are 32bit which maps to int
(Int32).

and I think BOOL* needs to be marshalled as "ref int"

public static extern int IsValidCompressedFile(
string pcszSrcFileName,
ref int bValid,
StringBuilder origFileName,
int lBufferSize );

make sure when you call it, allocate the buffer for the stringbuilder.
 
P

Paul Tomlinson

int are 64 bit in C#!
Why ref for 3rd arg and not fot the first?
Change your declaration into:

public static extern int IsValidCompressedFile( ref StringBuilder
srcFileName, ref bool
bValid, ref StringBuilder origFileName, int lBufferSize );

Also make sure API is expecting ANSI strings, and the calling sequence
matches the one used by PInvoke (_stdcall).

Willy.

What and then call it like:

StringBuilder sourcefile = new StringBuilder( @"c:\test.zip" );
StringBuilder destfile = new StringBuilder();
long validRes = IsValidCompressedFile( ref sourcefile, ref bValid, ref
destfile, 9999 );

:-<
"Capacity exceeds maximum capacity. Parameter name: capacity"
 
P

Paul Tomlinson

Thanks for everyones help so-far. While we are on topic what would be the
C# equivilent of this C++ prototype?

long DecompressFile (
const char *pcszSrcFileName,
const char *pcszDstPath,
PFN pfnCallback,
long lCallback);

PFN is defined as:
long PFN (
long lCallback,
unsigned short type,
long progress);

I don't actually need to specify any of the PFN struct attributes but do I
still need to define it in C#?

Thanks again :-/
 
S

stork

I think you need to wrap that with an extern "C" declaration, as
follows:
long IsValidCompressedFile (
const char *pcszSrcFileName,
BOOL *bValid,
char *origFileName,
long lBufferSize);


extern "C" {
long IsValidCompressedFile ( const char *pcszSrcFileName, BOOL
*bValid, char *origFileName, long lBufferSize);
}

The reason is that the name of that function in the DLL will be mangled
according to C++ conventions and these vary by the compiler vendor. By
wrapping them in extern "C" declarations, you force the system to
generate a DLL signature that looks like what it has.

You can see this by doing the following:

1. Launch your Visual Studio command prompt.
2. dumpbin /exports yourdll
3. dumpbin /exports c:\windows\system32\gdi32.dll.

Compare the way the signatures look. In yourdll, if you see a bunch of
funny characters in your name, that's how you know you are compiling to
C++ function signatures and not C.
This has been (one of) my attempt(s) at accessing it in C#:

[DllImport("external.dll")]
public static extern int IsValidCompressedFile( string srcFileName, ref bool
bValid, ref string origFileName, long lBufferSize );

This seems like this should be correct.
...
bool bValid = false;
string strOrigFileName = "";
long validRes = SMSPCIsValidCompressedFile( "c:\new.zip", ref bValid, ref
strOrigFileName, 9999999 );
This particular instance fails with "Object reference not set to an instance
of an object"

This is because C#'s runtime cannot locate the function within the DLL,
therefor, SMSCPCxxx is not a valid object to call.
Will someone, hell *anyone* please clue me up as to how I can access this
function properly. It's been driving me round the bend.

Thanks in advance.

Good luck!
 
W

Willy Denoyette [MVP]

Daniel,

Inline ***

Willy.

Daniel Jin said:
you need to drop the ref on stringbuilder because that's going to be an
additional level of indirection. and the first argument can stay as
string
since it's not modified.
*** My bad, added a ref to the first arg instead of to remove ref from the
3rd.
and ints are not 64bit in C#, but longs in C are 32bit which maps to int
(Int32).
*** Sorry long is what I meant.
and I think BOOL* needs to be marshalled as "ref int"
*** No BOOL* correctly marshals as ref bool, but sure you can use "ref int"
as well.
 

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