pInvoke question + string arrays

M

M0

I am referencing a function in a evc++ dll that has the following info

//I can get this function to work fine.
function epNormalLaunchApp(UInt32 creator);

//issues with this function
function epLaunchApp(UInt32 creator, LPCWSTR arg[]);

sample c++ input:

LPCWSTR args[3] = { L"-d" , L"123" , NULL }

epLaunchApp(EP_APP_RX , args );


I am trying to pinvoke from a c# function but keep on getting
System.NotSupportedException

code is below:


[DllImport("epLauncherLib.dll", CharSet=CharSet.Unicode,
EntryPoint="epLaunchApp")]
public static extern int MyFunc(UInt32 creator, string[] parameter);


private void button1_Click(object sender, System.EventArgs e)
{
UInt32 creator = Convert.ToUInt32("6E633532",16); //nc52
string[] xx =new string[]{"-c", "11", null };
MyFunc(creator, xx );
}




is "LPCWSTR arg[]" not the same as "string[] arg" if not how should I
pass my string array to the dll.
 
C

Chris Tacke, eMVP

The marshaler isn't going to handle that one, and the workaround isn't fun.
Here's the general idea:

Your input is an array of LPCWSTR, or "long pointers to constant wide
character strings". This can be viewed in managed code as an array of uints
or and array on IntPtrs. Each element in the array must point to a valid
string, and those strings must not be movable by the CLR or the pointers
will become invalid, so they need to be either pinned or allocated with an
unmanaged call.

What I'd do is create a method that allocates a string with LocalAlloc and
returns the pointer to that string. Then create an array of IntPtrs that
you pooulate by calling this method, and then pass that array to your
unmanaged DLL.

Be very careful here, as the potential for memory leaks abounds.

--
Chris Tacke
Co-founder
OpenNETCF.org
Has OpenNETCF helped you? Consider donating to support us!
http://www.opennetcf.org/donate
 
M

M0

Wow, are there any good tutorials/examples for me to look at to do this
as this is new to me.

Thanks
 
P

Peter Foot [MVP]

A couple of useful functions would be StringToGlobalUni and FreeHGlobal
methods in OpenNETCF.Runtime.InteropServices namespace
http://vault.netcf.tv/VaultService/...penNETCF/Runtime/InteropServices/MarshalEx.cs
user: guest
pass: guest

You can either use the SDF as-is from your project or borrow these two
methods.

e.g. heres an example of how it might work:-

public IntPtr[] AllocStringArray(string[] vals)
{
IntPtr[] ptrs = new IntPtr[vals.Length];

for(int i = 0; i < vals.Length; i++)
{
ptrs = MarshalEx.StringToGlobalUni(vals);
}

return ptrs;
}

public void FreeStringArray(IntPtr[] ptrs)
{
for(int i = 0; i < ptrs.Length; i++)
{
if(ptrs!=IntPtr.Zero)
{
MarshalEx.FreeHGlobal(ptrs);
ptrs = IntPtr.Zero;
}
}
}

[DllImport("epLauncherLib.dll", CharSet=CharSet.Unicode,
EntryPoint="epLaunchApp")]
public static extern int MyFunc(UInt32 creator, IntPtr[] parameter);


private void button1_Click(object sender, System.EventArgs e)
{
UInt32 creator = Convert.ToUInt32("6E633532",16); //nc52
IntPtr[] xx = AllocStringArray(new string[]{"-c", "11", null });
MyFunc(creator, xx );
FreeStringArray(xx);
}

Peter
 
C

Chris Tacke, eMVP

Beautiful! I wasn't aware it was in there, but yes, that's the idea.

--
Chris Tacke
Co-founder
OpenNETCF.org
Has OpenNETCF helped you? Consider donating to support us!
http://www.opennetcf.org/donate


Peter Foot said:
A couple of useful functions would be StringToGlobalUni and FreeHGlobal
methods in OpenNETCF.Runtime.InteropServices namespace
http://vault.netcf.tv/VaultService/...penNETCF/Runtime/InteropServices/MarshalEx.cs
user: guest
pass: guest

You can either use the SDF as-is from your project or borrow these two
methods.

e.g. heres an example of how it might work:-

public IntPtr[] AllocStringArray(string[] vals)
{
IntPtr[] ptrs = new IntPtr[vals.Length];

for(int i = 0; i < vals.Length; i++)
{
ptrs = MarshalEx.StringToGlobalUni(vals);
}

return ptrs;
}

public void FreeStringArray(IntPtr[] ptrs)
{
for(int i = 0; i < ptrs.Length; i++)
{
if(ptrs!=IntPtr.Zero)
{
MarshalEx.FreeHGlobal(ptrs);
ptrs = IntPtr.Zero;
}
}
}

[DllImport("epLauncherLib.dll", CharSet=CharSet.Unicode,
EntryPoint="epLaunchApp")]
public static extern int MyFunc(UInt32 creator, IntPtr[] parameter);


private void button1_Click(object sender, System.EventArgs e)
{
UInt32 creator = Convert.ToUInt32("6E633532",16); //nc52
IntPtr[] xx = AllocStringArray(new string[]{"-c", "11", null });
MyFunc(creator, xx );
FreeStringArray(xx);
}

Peter

--
Peter Foot
Windows Embedded MVP
http://www.inthehand.com | http://www.peterfoot.net |
http://www.opennetcf.org

M0 said:
Wow, are there any good tutorials/examples for me to look at to do this
as this is new to me.

Thanks
 
M

M0

Ok I have gotten the values into my intptr[xx] and tested to make sure
they were there with
string s = MarshalEx.PtrToStringUni(xx); and they are. My next
question is this.

LPCWSTR args[3] = { L"-d" , L"123" , NULL } inserts a null at the
end. Is this equivilant to "\0". I get IntPtr[] xx through to the dll
and it doesn't crash on me but it also doesnt do what it's supposed to
do which is open to a specific part. It opens to the default which
would be like me inputting MyFunc(creator, null); So I am not sure if
the dll is reading IntPtr[]
 
P

Paul G. Tobey [eMVP]

No, one is a pointer value of NULL, one is a pointer to a string containing
just a single, 0, character. Not equivalent!

Paul T.
 
M

M0

I figured it out, the problem was that I have been staring at the
screen to long and had a typo that didnt bring up an error. Thank you
all very, very much for your help. It is appreciated.
 

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