0

I have a C++ dll file which contains an exported function named fn(double* p, int* pLength), where, p is a pointer (is an out array used in C#), pLength which is calculated in this function is the length (size) of p . Code here:

void _stdcall fn(double* p, int* pLength)
{
    int i=0;
    double p_=0;
    do
    {
        p[i]=p_;
        p_=an expression!!!!!;
        i++;
    }
    while (condition with p_);  //Condition of loop
 
    *pLength=i;
 
    return;
}

I compile to dll file successfuly. This file is named "testFile.dll" and move it to System32 folder. Now, I start C# console project and declare that exported function fn() from "testFile.dll", and this code is:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("testFile.dll")]
        public static extern void fn(double[] p, ref int pLength);
        static void Main(string[] args)
        {
            // I want to declare an array with unknown length (size),
            // because the length is calculated from fn() function!!!
            // And pass to fn() function to get p[i].....
            double[] p;
            int pLength;
            fn(p, ref pLength);
 
            // Display pLength and p[i]
            Console.WriteLine(pLength);
            for (int i = 0; i < pLength; i++)
                Console.WriteLine(p[i]);
            Console.ReadKey();
        }
    }
}

I run and get two errors:

Error 1 Use of unassigned local variable 'p'

Error 2 Use of unassigned local variable 'pLength'

How to fix them?, and I want to get pLength and p[i] fully from fn() function in "testFile.dll". Thanks in advance.

2
  • Thanks you for your idea, I'm new C#. How do I work now? Thanks. Commented Mar 31, 2014 at 4:34
  • 1
    Buy a copy of the New York Times, Sunday edition. Take it along when you visit the C++ programmer that wrote this function, ask him to fix his code. If he says "no" then slap him over the head with the paper. Repeat as often as necessary until you get a "yes". Commented Apr 1, 2014 at 11:39

2 Answers 2

3

As I understand it, you will need to call the function twice. Once you will pass an empty array and ask the function to calculate the required length. And then again you call with an allocated array which the function will populate.

The unmanaged code might look like this:

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p) p[i] = p_;
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

Note that the code checks whether or not p is assigned, and only writes to the array if it is.

On the managed side the code looks like this:

[DllImport(...)]
public static extern void fn(double[] p, out int pLength);
....
int pLength;
fn(null, out pLength);
double[] p = new double[pLength];
fn(p, out pLength);

A safer version of this would be to pass the length of the array to the function. That would allow the function to make sure that it does not write off the end.

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p)
        {
            if (i >= *pLength) return -1; // or some other error code
            p[i] = p_;
        }
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

And the managed side:

[DllImport(...)]
public static extern void fn(double[] p, ref int pLength);
....
int pLength = 0;
fn(null, ref pLength);
double[] p = new double[pLength];
fn(p, ref pLength);

If you only want to call the function once then you need to do the following:

  1. Allocate memory dynamically in the unmanaged code. Use GlobalAlloc so that the managed code can deallocate it.
  2. Be prepared to re-allocate in the unmanaged code if your initial allocation proved to be of insufficient length.
  3. Use an out parameter of type IntPtr in the managed code to get the pointer to unmanaged memory.
  4. Use Marshal.Copy to copy the array contents into your managed double[] object.
  5. Call Marshal.FreeHGlobal to free the unmanaged memory.

This technique is much more complex and involves a lot more boiler-plate. You only take this approach when there is a significant performance overhead in the first approach that I outlined.


An aside. Please don't put your files in the system directory. It belongs to the system and you are expected not to modify it. Place the DLL in the same directory as the host executable.

Sign up to request clarification or add additional context in comments.

12 Comments

Thanks you. Now I dont want to call fn() function twice, I want to call once. How to do this? Thanks.
You'd have to allocate the memory in the unmanaged code. Even that is not trivial because how would you know how much to allocate until you'd been round the loop. Why didn't you present that requirement in the question?
Sorry you about this, I'm bad in English and I havent noted that, thanks. In the unmanaged code I dont know the length of p, so I cant allocate the size of it. I dont ask you to code complete my code, can you help me a part of code.
If you don't know how large the array needs to be, how can you allocate memory for it? Allocating in the unmanaged code is something you do as a last resort. Why not call the function twice?
I dont want to call twice because I think that it has a way to call the function once. Unfortunity, it's no way to do that. Allocating memory for a pointer in unmanage code is easy with "new" operator, but I dont know the size of that pointer, if I allocate less than pLength after calculation, it will generate error. I want to get the size of it fully.
|
1

The error you are getting is to do with the fact that you are not assigning an array any value. Though the function doesn't care how large the array is it still needs to work on valid memory.

Try the following:

int pLength = 20;
double[] p = new double[pLength];
fn(p, ref pLength);

And see if the error goes away.

4 Comments

Thanks. When fn() is called, pLength can be up to 40, 50, or higher than 20, while the length of p is not changed (allways is 20), that does take place "out of range" of p array. I try! Hope you help me solve completely. Thanks.
In fact, I will call this function twice to get pLength and re-allocate memory space for p: <pre>double[] p = new double[2]; // Allocate with temporariness int pLength = 0; fn(p, ref pLength); // Get pLength correctly p = new double[pLength]; // Re-allocate p correctly fn(p, ref pLength); // Recall to get p.<code> But this work has loss "twice" with fn() function! I want to call once fn() function. Thanks in advance.
I'm sorry but I am struggling to understand what you are asking in that last comment?
Sorry, I edit my code above (please see again to help me)! The condition (p_<20) is an example, in fact, it is an expression of p_. So I have to need to calculate pLength. That mean is: I dont know the size of p pointer in fn() function, when this function is finished we know this size (is pLength). You can help me complete this. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.