Invoke

  • Thread starter Thread starter GTi
  • Start date Start date
G

GTi

I have some functions that I want to Invoke in my C# project:

int NumberOfServers (BOOL UseENUM, LPCSTR MachineName);
BOOL GetServerName (int index, LPSTR Buffer, int BufSize);

can be used by:
[DllImport("some.dll")]
private static extern int NumberOfServers(bool UseENUM,
[MarshalAs(UnmanagedType.LPStr)]string MachineName);

[DllImport("some.dll")]
private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.LPTStr)]string Buffer, int BufSize);

But GetServerName just returns blanks:
string serverName = "
";
GetOPCServerName(index, serverName, serverName.Length);


And this one I have no idea:
HANDLE Connect(LPCSTR MachineName, LPCSTR ServerName, BOOL
EnableDLLBuffering);
HANDLE AddGroup(HANDLE hConnect, LPCSTR Name, DWORD *pRate, float
*pDeadBand);

And this one:
BOOL EnableNotification(HANDLE hConnect, NOTIFYPROC lpCallback);

void CALLBACK EXPORT OPCUpdateCallback(HANDLE hGroup, HANDLE hItem,
VARIANT *pVar, FILETIME timestamp, DWORD quality)
I know I must use delegates, but all help is wanted here.

Anyone ?
 
GTi,

Your declaration of GetServerName is wrong. You need to use a
StringBuilder as opposed to a string when you expect the string to be
written to, like so:

[DllImport("some.dll")]
private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder Buffer, int BufSize);

As for the rest:

[DllImport("some.dll")]
static extern IntPtr(
[MarshalAs(UnmanagedType.LPTStr)]
string MachineName,
[MarshalAs(UnmanagedType.LPTStr)]
string ServerName,
bool EnableDLLBuffering);

[DllImport("some.dll")]
static extern IntPtr(
IntPtr hConnect,
[MarshalAs(UnmanagedType.LPTStr)]
string Name,
[MarshalAs(UnmanagedType.U4)]
ref int pRate,
ref float pDeadBand);

delegate void OPCUpdateCallback(
IntPtr hGroup,
IntPtr hItem
ref object pVar,
FILETIME timestamp,
[MarshalAs(UnmanagedType.U4)]
int quality);

[DllImport("some.dll")]
static extern EnableNotification(IntPtr, OPCUpdateCallback lpCallback);

You can get the definition of FILETIME from http://www.pinvoke.net, or
if you are using .NET 2.0, you can use the one in the
System.Runtime.InteropServices.ComTypes namespace.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)
And this one:
BOOL EnableNotification(HANDLE hConnect, NOTIFYPROC lpCallback);

void CALLBACK EXPORT OPCUpdateCallback(HANDLE hGroup, HANDLE hItem,
VARIANT *pVar, FILETIME timestamp, DWORD quality)
I know I must use delegates, but all help is wanted here.


GTi said:
I have some functions that I want to Invoke in my C# project:

int NumberOfServers (BOOL UseENUM, LPCSTR MachineName);
BOOL GetServerName (int index, LPSTR Buffer, int BufSize);

can be used by:
[DllImport("some.dll")]
private static extern int NumberOfServers(bool UseENUM,
[MarshalAs(UnmanagedType.LPStr)]string MachineName);

[DllImport("some.dll")]
private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.LPTStr)]string Buffer, int BufSize);

But GetServerName just returns blanks:
string serverName = "
";
GetOPCServerName(index, serverName, serverName.Length);


And this one I have no idea:
HANDLE Connect(LPCSTR MachineName, LPCSTR ServerName, BOOL
EnableDLLBuffering);
HANDLE AddGroup(HANDLE hConnect, LPCSTR Name, DWORD *pRate, float
*pDeadBand);

And this one:
BOOL EnableNotification(HANDLE hConnect, NOTIFYPROC lpCallback);

void CALLBACK EXPORT OPCUpdateCallback(HANDLE hGroup, HANDLE hItem,
VARIANT *pVar, FILETIME timestamp, DWORD quality)
I know I must use delegates, but all help is wanted here.

Anyone ?
 
Ahhh tx Nicholas,
After some testing in the mean time I get this to work also:

private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.VBByRefStr)]ref string MachineName, int
BufSize);
Don't what VBByRefStr is (Visual Basic Type) ?

GTi
 
I get an runtime error (int the win32 dll) when using it with
StringBuilder:


[DllImport("some.dll")]
private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder Buffer, int BufSize);

public string ServerName(int index)
{
StringBuilder text = new StringBuilder("", 128);

try { GetServerName(index, text, text.MaxCapacity); }
catch (Exception e) { _lastError = e.Message; }
return (text.ToString());
}

Any idea why?
 
GTI,

You should not be using ref string, rather, StringBuilder is what is
guaranteed to work. The fact that it works with ref string is not a
supported mechanism to do what you are trying to do, and could change in the
future.
 
GTi,

It's not working because you are passing MaxCapacity in for your buffer
size. This value, when used with a StringBuilder as you created it, will be
0x7fffffff, which is a really big number.

You should pass in the capacity of the string, returned by the Capacity
property.
 
Thanks Nicholas,
I have changed it now to:

[DllImport("some.dll", EntryPoint = "GetServerName", CharSet =
CharSet.Ansi)]
private static extern bool GetServerName(int index, [MarshalAs(
UnmanagedType.LPTStr)] StringBuilder Buffer, int BufSize);

StringBuilder text = new StringBuilder(128);
try { GetServerName(index, text, text.Capacity); }
catch (Exception e) { lastError = e; }
return (text.ToString());

But now it just return ????????????? where the name shuld be. But the
length of the ???? string (looks like it) match the real names.

Any tips?
 
GTi,

You should change your declaration to this (if you are sure that you are
using the Ansi character set:

[DllImport("some.dll", EntryPoint = "GetServerName", CharSet =
CharSet.Ansi)]
private static extern bool GetServerName(int index,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder Buffer, int BufSize);

This should work.
 
Nicholas,
Was using
MarshalAs(UnmanagedType.LPTStr)
changed it to:
MarshalAs(UnmanagedType.LPStr)

and voila !
You are my hero !

GTi
 
OK - I don't remeber it now - I give up.
Simple question:

How can I referer to FILETIME to the
System.Runtime.InteropServices.ComTypes namespace instead of the
System.Runtime.InteropServices ?

delegate void OPCUpdateCallback(IntPtr hGroup, IntPtr hItem, ref object
pVar, FILETIME timestamp, [MarshalAs(UnmanagedType.U4)]int quality);
Gives this error:
'FILETIME' is an ambiguous reference between
'System.Runtime.InteropServices.FILETIME' and
'System.Runtime.InteropServices.ComTypes.FILETIME'

But I can't remember what the syntax is to referer to another
namespace:
System.Runtime.InteropServices.ComTypes.FILETIME timespamp
does not work at all....
 
I solved it (rare bug)

My name space name is:
namespace MyLib.System

So trying to spesify the correct type using:
System.Runtime.InteropServices.ComTypes.FILETIME timestamp
gives me an error saying that Runtime was unknown..

Renaming my namespace to:
namespace MyLib.Lib
solved the problem....

(And I was almost giving up C# for this!)
 
Back
Top