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?

4
  • 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. Commented Oct 27, 2013 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. Commented Oct 27, 2013 at 14:20
  • The code here may help: stackoverflow.com/questions/17549123/… Commented Oct 27, 2013 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(). Commented Oct 27, 2013 at 16:31

0

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.