|
Hi,
I'm trying to communicate with an unmanaged c++ dll from c# that takes two 2d
float arrays, one as input with data in it and the other will have the
result of the operation in it as follows:
bool Evaluate(float** input,float** output,int nFrames, int
featureWidth);
note: nFrames and featureWidth will determine the sizes of input and
output arrays in the c++ code.
Using this method in c# requires you to use float multidimensional
arrays. However I keep on getting exceptions thrown by the dll while
the same code works fine in a normal console application!
Trying to debug the dll as much as i can i figured out that the arrays
are not being passed correctly. can anybody help me out here, how
would I pass a 2 dimentional array to unmanaged c++ function?
Thanks
Fahd
|
|
|
|
|
Hi
how did you define the Call in c# (any MarshalAs usage or something..?)
what kind of exceptions do you get? access violations or others..?
f4hd wrote: dll while
the same code works fine in a normal console application!
do you mean you have a c# console application that successfully handles the dll?
greets
m@u
|
|
|
|
|
Hi M@u
thanks for the reply.
here is my definition
[DllImportAttribute(@".\xyz_MFC.dll")]
public static extern bool Evaluate(float [,] input, float[,] output, int nFrames,int featureWidth);
in unmanaged c++ it is
bool xyz_MFCApp::Evaluate(float** input, float **output,int nFrames,int featureWidth);
The exception that I get is System.NullReferenceException. Which is access violation I assume.
>>do you mean you have a c# console application that successfully handles the dll?
I have a legacy c++ code that im making into a dll in order to use it with c#
wen accessed using a c++ console app the code works fine. but wen i convert the code into a dll and use the exposed function in c# it throws the exception i just mentioned. on further investigating i figured out its the problem with the passing of 2d float arrays.
so if i pass the input array and access the first row i.e input[0][0] in the dll its fine but when i access input[1][0] the exception is thrown!
Thus i think i need to find out the correct way to pass the 2d array such that the memory it holds isnt affected.
hope I havent confused things further
Fahd
|
|
|
|
|
f4hd wrote: The exception that I get is System.NullReferenceException. Which is access violation I assume
No the Null Reference exception only says that you're passing a parameter that is null and is not supposed to be null
f4hd wrote: [DllImportAttribute(@".\xyz_MFC.dll")]
public static extern bool Evaluate(float [,] input, float[,] output, int nFrames,int featureWidth);
that with the multi-dimensional arrays might be a big problem.. i read something about it once and i think the central statement there was, that passing multi-dimensional arrays is not supported / only possible by using dirty tricks..
what you could try would be to mark the output array as ref or out.
[DllImportAttribute(@".\xyz_MFC.dll")]
public static extern bool Evaluate(float [,] input, [In,Out] ref float[,] output, int nFrames, int featureWidth);
or
[DllImportAttribute(@".\xyz_MFC.dll")]
public static extern bool Evaluate(float [,] input, [Out] out float[,] output, int nFrames, int featureWidth);
i find it a bit strange that nFrames is not a pointer, do you decide how many entrys per dimension the dll will return?
|
|
|
|
|
>No the Null Reference exception only says that you're passing a parameter that is null and is not >supposed to be null
well data is passed but incorrectly. see I can access the first row of the 2d array but not any other.
mebe you are right its not supported so one way, not quite elegant, is to convert the 2d arrays into 1d arrays during passing and receiving... Can there be any better way I wonder?
the In and out dont help much because of the same issue i mentioned above.
>>i find it a bit strange that nFrames is not a pointer, do you decide how many entrys per dimension >>the dll will return?
Yes I know it from before and is fixed for this Dll call and using it I do know the dimensions being returned
|
|
|
|
|
f4hd wrote: not quite elegant, is to convert the 2d arrays into 1d arrays during passing and receiving... Can there be any better way I wonder?
well if you can make it work that way i think that's a good way. an other way you could try would be to pass an array of intptrs that point each to an array of float.
it's ugly and i don't really know if it'll work at all but it *might* work
that it would look like this:
DllImportAttribute(@".\xyz_MFC.dll")]
public static extern bool Evaluate(IntPtr [] input, IntPtr[] output, int nFrames,int featureWidth);
private float[,] foo()
{
int nFrames = 3;
int featurWidth = 5;
float[,] myArray = new float[2,nFrames];
IntPtr[] input = writeArray(myArray);
IntPtr[] output = allocArray(featurWidth);
bool ok = Evaluate(input, output, nFrames, featurWidth);
freeArray(input);
return readArray(output,featurWidth);
}
private float[,] readArray(IntPtr[] Items, int featureWidth)
{
float[,] RetVal = new float[2,featureWidth];
readMemArray(Items[0],RetVal,0,featureWidth);
readMemArray(Items[1],RetVal,1,featureWidth)
freeArray(Items);
return RetVal;
}
private void readMemArray(IntPtr Pointer, Float[,] Target, int Dimension, int featureWidth)
{
float[] Dummy = new float[featureWidth];
Marshal.Copy(Pointer,Dummy,0,featureWidth);
copyArray(Dummy, Target, Dimension);
}
private void freeArray(IntPtr[] Items)
{
Marshal.FreeHGlobal(Items[0]);
Marshal.FreeHGlobal(Items[1]);
}
private IntPtr[] allocArray(int ItemCount)
{
IntPtr RetVal = new IntPtr[2];
int Count = Marshal.SizeOf(typeof(float)) * ItemCount;
RetVal[0] = Marshal.AllocHGlobal(Count);
RetVal[1] = Marshal.AllocHGlobal(Count);
return RetVal;
}
private IntPtr[] writeArray(float[,] Array)
{
IntPtr[] RetVal = allocArray(Array.GetLength(1));
float[] Dummy = new float[Array.GetLength(1)];
copyArray(Array, Dummy, 0);
Marshal.Copy(Dummy,0,RetVal[0],Dummy.Length);
copyArray(Array, Dummy, 1);
Marshal.Copy(Dummy,0,RetVal[1],Dummy.Length);
}
private void copyArray(float[] Source, float[,] Destination, int zDimIndex)
{
for(int i = 0; i< Source.Length; i++)
{
Destination[zDimIndex,i] = Source[i];
}
}
private void copyArray(float[,] Source, float[] Destination, int zDimIndex)
{
for(int i = 0; i < Destination.Length; i++)
{
Destination[i] = Source[zDimIndex,i];
}
}
the code is untested so maybe you'll have to change something but generally it could work.
however.. if you can make it work with an 1-dimensional array do it that way
greets
m@u
|
|
|
|
|
Thanks a lot for the code m@u
I havent tried it yet but I have tried the 2D to 1D method which worked as expected. I am worried about the speed impact of this method as it will be called many times and each time there is this conversion, its going to be slow. So if you can comment about the speed impact of the code you've mention in comparison to it that will be great.
Typical values of arrays will be something like 5000x40 and this dll will be called about a 1000 times! so if you think using Intptr might be quicker please let me know. Thanks
|
|
|
|
|
Hi
i don't really know because i didn't thest the posted code but i think the conversion will be quite slow for such big arrays and since you can make it work with the 2d to 1d conversion i'd say keep it like that.
greets
m@u
|
|
|
|
|
Ok, here are a few ideas for you to try:
1. Change the C# import declaration type from float[,] to float[][] (they are NOT equivalent types)
2. Change the C++ method signiture to take parameters of type float[][] instead of float**
3. Convert the float[][] to a float[] in your c# code, and change your method to either float* or float[] in your C++ code
4. Convert the float[][] to an IntPtr pointing to the address of the array
5. Convert the float[][] to a float* (requires unsafe code in C#)
6. Try combinations of the above, where you attempt a method signature in C++ using float[][], float[], float**, float*, and change the type you are sending from C# between IntPtr, float[], float*, float[][], float[,], float**, and in addition try mixing in the keywords out and ref as well
7. Do the same as you did in #6, but try copying the data to public memory using Marshal.Copy prior to making all the above calls
The above suggestions give you hundreds of combinations to try, and my guess is that at least one of them will work. Let us know if you get this figured out,
Sounds like somebody's got a case of the Mondays
-Jeff
|
|
|
|
|
Hi Jeff
Thanks for your answers.
1. Change the C# import declaration type from float[,] to float[][] (they are NOT equivalent types A:I know )
A: tried that before, gives a marshalling error.
2. Change the C++ method signiture to take parameters of type float[][] instead of float**
A: this doesnt work too, C++ gives lots of error if using flaot[][] instead of float**
3. Convert the float[][] to a float[] in your c# code, and change your method to either float* or float[] in your C++ code
A: I think this will work so if I got it right ill do the following:
float[,] --> float[] in c#
float* --> float** once in c++
float** --> float* when exiting from the function in c++
float[] --> float[][] in c#
it should work but isnt desireable.
4. Convert the float[][] to an IntPtr pointing to the address of the array
A:Can you help me with this please.
5. Convert the float[][] to a float* (requires unsafe code in C#)
A:Im not sure about this but perhaps dont want to try it right now.
6. Try combinations of the above, where you attempt a method signature in C++ using float[][], float[], float**, float*, and change the type you are sending from C# between IntPtr, float[], float*, float[][], float[,], float**, and in addition try mixing in the keywords out and ref as well
A have tried many combinations already including Out and Ref but in all ive noticed that because memory isnt properly handled i can only access part of the 2d array accessing other parts causes access violation.
7. Do the same as you did in #6, but try copying the data to public memory using Marshal.Copy prior to making all the above calls
A: I dont know about this. Need to dig in to it.
I did read about pinning pointers and stuff but all that is for C++ not C#, if Im not mistaken 'ref' takes care of it, but i may be wrong.
>>The above suggestions give you hundreds of combinations to try, and my guess is that at least one >>of them will work. Let us know if you get this figured out,
A: sure ill let u all know
kind regards
|
|
|
|
|
I want to know how the side by side versioning is maintain in dotnet.
1) if i used
<configuration>
<runtime>
<assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentassembly>
<assemblyidentity name="ClassLibraryversioning">
publicKeyToken="f690ee21283c8415"
culture="neutral"/>
<bindingredirect oldversion="1.0.0.0">
newVersion= "1.0.0.1"/>
</bindingredirect></assemblyidentity></dependentassembly>
</assemblybinding>
</runtime>
</configuration>
then it is always show same version(no compilation errors)
mean it always show the function in dll which i refered to the project.
even i specify bindingredirect
2) if i used following code then everthing is fine
{
Assembly objm = Assembly.Load("ClassLibraryversioning, Version=1.0.0.1,Culture=neutral, PublicKeyToken = f690ee21283c8415");
Type objmycom = objm.GetType("ClassLibraryversioning.Class1", true, true);
BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public
| BindingFlags.Static | BindingFlags.Instance |
BindingFlags.DeclaredOnly);
MethodInfo m = objmycom.GetMethod("version", flags);
object myobj = Activator.CreateInstance(objmycom, false);
object result = m.Invoke(myobj, BindingFlags.InvokeMethod, null, null, CultureInfo.CurrentCulture);
MessageBox.Show(result.ToString());
}
tell me why it happened?
My problem is
|
|
|
|
|
Tell you what. Pick one of these posts and stick with it then delete the others by using the Delete link at the bottom of the message.
|
|
|
|
|
What about posting-to-forums hell?
|
|
|
|
|
This site badly needs message versioning and a difference tool.
|
|
|
|
|
soryy i am new to post a question. i missed out the ignore html check so my email post wrongly i post again and again. Now i posted correctly
|
|
|
|
|
Hi all,
I am looking for reference related to using the Enterprise library for configuring elements of my application.
I can find many sources for configuring enterprise library elements such as logging for example, but as I have included the Ent Lib in my app. My implementation team will be required to use the EntLib configuration. But they will currently also be required to manually edit the app.config file to set application specific settings. I would like to be able to avoid this.
I can see how to add value key pairs, but I also need to use a custom configuration class within this.
Is anybody able to point me to a good source of info?
Many thanks
Paul
|
|
|
|
|
Hi,
I am adding a column to a datatable.
dt.Columns.Add("PriceCode", typeof(String));
How do I set the size for this column please?
vb.net or c# sample will do.
Thanks
|
|
|
|
|
DataColumn.MaxLength gets/sets the maximum length of a text column.
Paul Marfleet
"No, his mind is not for rent
To any God or government"
Tom Sawyer - Rush
|
|
|
|
|
Hi all i am trying to execute a SSIS package from C# code the code is like this..
Application app = new Application();
Package package = app.LoadPackage("d:\\Main.dtsx", null);
package.ImportConfigurationFile("d:\\Main.dtsConfig");
try
{
DTSExecResult result = package.Execute();
}
but it not giving the desired result...
can anybody help me here to getin the problem..
Thanks in advance...
T@SU
|
|
|
|
|
tasumisra wrote: but it not giving the desired result...
Why not? What is happening?
Unless you provide specific details of your problem, i.e. error information, no one is going to be able to help you.
Paul Marfleet
"No, his mind is not for rent
To any God or government"
Tom Sawyer - Rush
|
|
|
|
|
The following is the exact message I am getting when running the application from Visual Studio 2005, trying to load a .dtsx package. I could not add a screen shot here. The code is so simple that I cannot understand what the path problem is.
Failed to open package file "\Serv37\wwwroot\AS-MIS\LoadBeaPayroll\LoadBeaPayroll\package.dtsx" due to error 0x80070003 "The system cannot find the path specified.". This happens when loading a package and the file cannot be opened or loaded correctly into the XML document. This can be the result of either providing an incorrect file name was specified when calling LoadPackage or the XML file was specified and has an incorrect format.
The. ,dtsx package and code are both located on the server. I can run the .dtsx package fine in BIDS and get the required result. When the code runs to the line "pkg = app.LoadPackage(pkgLocation, eventListener);" that is when I get the "Failed to open package file" error.
Below is a re-posting of the actual code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Dts.Runtime;
namespace DocBeaEntry
{
class MyEventListener : DefaultEvents
{
public override bool OnError(DtsObject source, int errorCode, string subComponent, string description, string helpFile, int helpContext, string idofInterfaceWithError)
{
// Add application-specific diagnostics here.
Console.WriteLine("Error in {0}/{1} : {2}", source, subComponent, description);return false;
}
}
public class clsSSIS
{
public static void RunDTSX()
{
string pkgLocation;
Package pkg;
Application app;
DTSExecResult pkgResults;
MyEventListener eventListener = new MyEventListener();
pkgLocation = @"\Serv37\wwwroot\AS-MIS\LoadBeaPayroll\LoadBeaPayroll\package.dtsx";
app = new Application();
pkg = app.LoadPackage(pkgLocation, eventListener);
pkgResults = pkg.Execute(null, null, eventListener, null, null);Console.WriteLine(pkgResults.ToString());
}
}
}
|
|
|
|
|
Hi,
How can I limit the number of digits entered into the cells of a column in datagridview?
For example, in column 10 of the datagridview, I would like users to be able to enter up to 8 characters.
Thanks
|
|
|
|
|
How to download attachment from POP3 mail?
i have problem of finding attachment in a mail from pop3 server and saving the attachment from mail in to my local drive please help me to resolve the issue...
|
|
|
|
|
hi
take a look at these articles[^] there are some good pop client libs around..
greets
m@u
|
|
|
|
|
I have created given below method which saves xml file and passes xml file name to database through client but there is an error message::::
which states like this::Server was unable to process request. ---> Cannot open database "client_server" requested by the login. The login failed.
Login failed for user 'WLINKCOMP3\ASPNET'.
wlinkcomp3 is the comp where web service is residing.......
[WebMethod]
public void ret_xml(XmlDocument file, string file_name)
{
int hi = 0;
string total_file_name = "Client_Information_" + file_name+".xml";
string path_image = "images/" + total_file_name;
file.Save(Server.MapPath(path_image));
thisConnection = new SqlConnection(connection);
SqlCommand myCommand = new SqlCommand("SELECT * FROM client_name", thisConnection);
thisConnection.Open();
myCommand.ExecuteNonQuery();
rdr = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
while (rdr.Read())
{
string present = rdr["client_name"].ToString();
if (present == file_name)
{
hi = 1;
}
// thisConnection.Open();
}
rdr.Close();
if (hi == 1)
{
SqlCommand myCommand1 = new SqlCommand("INSERT into client_name(client_name) values ('" + file_name + "') ", thisConnection);
myCommand1.ExecuteNonQuery();
}
thisConnection.Close();
}
now given below is the client part
which generates xml files and passes the file name to web server....
Service aaa2 = new Service();
aaa2.ret_xml(xml_doc, StrFileName2);
could anybody help me...
thanking in advance
|
|
|
|
|