0

I want to use a function written in C in C# application. The function is exported to dll file. C function code:

    #include <stdio.h>
    #include <stdlib.h>
    extern "C" __declspec(dllexport) char * Encrypt(char plainText[],int height,long inputLength)
    {
        char *encryptedText=(char*)malloc(sizeof(plainText));
        char **cipherArray;


        cipherArray=(char**)malloc(height*sizeof(char *));
        for(long i=0; i<height; i++)
        {
            cipherArray[i]=(char*)malloc(inputLength*sizeof(char));
            for (long j=0; j<inputLength ; j++)
                cipherArray[i][j]='#';
        }






bool addRow=true;
long row=0;
long column = 0;
long arrayIterator = 0;
while(arrayIterator<inputLength){
    cipherArray[row][column] = plainText[arrayIterator];

            column++;
            if(addRow)row++;
            else row--;
            if (row >= height)
            {
                row--;
                row--;
                addRow=false;
            }
            else if (row < 0)
            {
                row++;
                row++;
                addRow = true;
            }
            arrayIterator++;
}



long iterator=0;
for (long i=0; i< height; i++)
    for(long j=0; j<inputLength;j++){
        if(cipherArray[i][j]!='#'){
            encryptedText[iterator]=cipherArray[i][j];
            iterator++;
        }
    }

for(int i=0; i<height; i++)
    free(cipherArray[i]);
free(cipherArray);
cipherArray = NULL; 

return encryptedText;
    }

In C# app, I've created class to use this function:

namespace RailFenceCipher
{
public class CCipher
   {
     [DllImport("CCipher.dll", CharSet = CharSet.Unicode)]
        unsafe public static extern char* Encrypt(char[] plainText, int height, long inputLength);

    }
}

Now it's the hard part... The C function returns char* object (char array). My question is how can I assign the function's result to C# string?

So far I've been trying to menage it on my own but it still doesn't work...

Call for the dll function:

private void cipherC()
        {
            this.fileOutputC = "";
            unsafe
            {
                string cEncrypted =  new string(((CCipher.Encrypt(this.fileInput.ToCharArray(), this.height,fileInput.Length))));
             this.fileOutputC = cEncrypted;
            }
     }

Thanks for help in advance!

EDIT:

I've reorganized my code like this:

C code in dll:

    struct Wrapper{
        unsigned char* plainText;
        int height;
        long inputLength;
        unsigned char* result;
    };
    void Encrypt(unsigned char plainText[],int height,long inputLength,unsigned char result[])
    {
        unsigned char *encryptedText=(unsigned char*)malloc(sizeof(plainText));
        unsigned char **cipherArray;


        cipherArray=(unsigned char**)malloc(height*sizeof(unsigned char *));
        for(long i=0; i<height; i++)
        {
            cipherArray[i]=(unsigned char*)malloc(inputLength*sizeof(char));
            for (long j=0; j<inputLength ; j++)
                cipherArray[i][j]='#';
        }






        bool addRow=true;
        long row=0;
        long column = 0;
        long arrayIterator = 0;
        while(arrayIterator<inputLength){
            cipherArray[row][column] = plainText[arrayIterator];

                    column++;
                    if(addRow)row++;
                    else row--;
                    if (row >= height)
                    {
                        row--;
                        row--;
                        addRow=false;
                    }
                    else if (row < 0)
                    {
                        row++;
                        row++;
                        addRow = true;
                    }
                    arrayIterator++;
        }



        long iterator=0;
        for (long i=0; i< height; i++)
            for(long j=0; j<inputLength;j++){
                if(cipherArray[i][j]!='#'){
                    encryptedText[iterator]=cipherArray[i][j];
                    iterator++;
                }
            }

        long j=0;
        while(j<inputLength){
            result[j]=encryptedText[j];
            j++;
        }

        for(long i=0; i<height; i++)
            free(cipherArray[i]);
        free(cipherArray);
        cipherArray = NULL; 


    }

    extern "C" __declspec(dllexport) void CreateCWrapper(struct Wrapper **myWrapper,string plainText, long height, string result,long inputLength){


        *myWrapper=(struct Wrapper*)malloc(sizeof(struct Wrapper));
        (*myWrapper)->height = height;
        (*myWrapper)->inputLength= inputLength;
        (*myWrapper)->plainText= (unsigned char*)malloc(inputLength * sizeof(char));
         if ((*myWrapper)->plainText != NULL)
          for (long i = 0; i < inputLength; ++i)
              (*myWrapper)->plainText[i] = plainText[i];
        (*myWrapper)->result= (unsigned char*)malloc(inputLength * sizeof(char));



    }


    extern "C" __declspec(dllexport) void EncryptWithWrapper(Wrapper *myWrapper){
        unsigned char *table=(unsigned char*)malloc(sizeof(char)*myWrapper->inputLength);
        for(long i=0;i<myWrapper->inputLength;i++){
            table[i]=myWrapper->plainText[i];
        }
        unsigned char *res=(unsigned char*)malloc(sizeof(char)*myWrapper->inputLength);
        Encrypt(table,myWrapper->height,myWrapper->inputLength,res);
        for(long i=0;i<myWrapper->inputLength;i++){
            myWrapper->result[i]=res[i];

        }
        free(table);
        free(res);
    }

    extern "C" __declspec(dllexport) string getStrResultFromWrapper(Wrapper *myWrapper){
        string stringres;
        for(long i=0;i<myWrapper->inputLength;i++){
            stringres+=myWrapper->result[i];
        }
        return stringres;
    }

C# class:

    public class CCipher
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct Wrapper
            {
                public IntPtr plainText;
                public int height;
                public IntPtr inputLength;
                public string result;
            }

            [DllImport("CCipher.dll")]
            public static extern void CreateCWrapper(out IntPtr myWrapper, string plainText, long height, string result, long inputLength);

            [DllImport("CCipher.dll")]
            public static extern void EncryptWithWrapper(IntPtr myWrapper);

            [DllImport("CCipher.dll")]
            public static extern string getStrResultFromWrapper(IntPtr myWrapper);
       }

and calling function:

       private void cipherC()
               {

                   IntPtr myWrapper;
                   CCipher.CreateCWrapper(out myWrapper, this.fileInput, this.height, this.fileOutputC, this.fileInput.Length);
                   CCipher.EncryptWithWrapper(myWrapper);

                   CCipher.Wrapper dataWrapper=(CCipher.Wrapper) Marshal.PtrToStructure(myWrapper,typeof(CCipher.Wrapper));
               }

The problem is when calling:

   CCipher.CreateCWrapper(out myWrapper, this.fileInput, this.height, this.fileOutputC, this.fileInput.Length);

The app just stops. Any hint?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
sliwkacz
  • 387
  • 2
  • 4
  • 18
  • I think P/Invoke should be able to do some sort of marshalling. Check the docs for that, an older tutorial I found says it'll automatically convert `string` to a `LPTSTR`. Remember that a C `char` is really a byte, while C# works with Unicode strings, so you can't encode things that way. – millimoose Oct 27 '13 at 13:51
  • Also int and long in C are often the same and can depend on how the code it compiled while in C# they are of an explicit size. – Dweeberly Oct 27 '13 at 14:20
  • The code here may help: http://stackoverflow.com/questions/17549123/c-sharp-performance-using-unsafe-pointers-instead-of-intptr-and-marshal – kol Oct 27 '13 at 15:01
  • 3
    You cannot pinvoke this function. The returned string buffer must be released. That requires calling the C runtime's free() function, releasing the memory that was allocated by your malloc() call. You cannot call this function from C#, it doesn't know what CRT library you use. Get ahead by improving this function so it doesn't allocate memory (allow the caller to pass the buffer) or write a wrapper in the C++/CLI language or export a function that calls free(). – Hans Passant Oct 27 '13 at 16:31

0 Answers0