Avatar of deming
deming
 asked on

Calling C++ DLL from C#

I have a WORKING unmanaged DLL written in C++ that I am trying to call from C#.  Here are the declarations from C++:
__declspec(dllimport) BOOL __stdcall SaveStrData(const char *object, int index, const char *value);
__declspec(dllexport) BOOL __stdcall LoadStrData(const char *object, int index, char *retval);
__declspec(dllimport) char *__stdcall LoadStrData2(const char *object, int index);

Open in new window


Here is what I tried in C# in my Class1:
        [DllImport("IECGlobalVars32.dll", CharSet = CharSet.Ansi)]
        public static extern bool SaveStrData(string object1, int index, string sValue);

        [DllImport("IECGlobalVars32.dll", CharSet = CharSet.Ansi)]
        public static extern bool LoadStrData(string object1, int index, string sValue);

        [DllImport("IECGlobalVars32.dll", CharSet = CharSet.Ansi)]
        public static extern string LoadStrData2(string object1, int index);

Open in new window


The LoadStrData and LoadStrData2 both fail.

Here are my calls in C#:
        private void btnSaveStr_Click(object sender, EventArgs e)
        {
            String myStr;
            Int32 myIndex = 0;
            String myObj;
            myObj = tbObj.Text;
            myStr = tbValue.Text;
            myIndex = System.Convert.ToInt32(tbIndex.Text);
            Class1.SaveStrData(myObj, myIndex, myStr);
        }

        private void btnLoadStrData_Click(object sender, EventArgs e)
        {
            string myStr;
            Int32 myIndex = 0;
            String myObj;
            myObj = tbObj.Text;
            myStr = "nothing here";
            myIndex = System.Convert.ToInt32(tbIndex.Text);
            Class1.LoadStrData(myObj, myIndex, myStr);
            tbValue.Text = myStr;

        }

        private void btnLoadStrData2_Click(object sender, EventArgs e)
        {
            String myStr;
            Int32 myIndex = 0;
            String myObj;
            myObj = tbObj.Text;
            myStr = "nothing here";
            myIndex = System.Convert.ToInt32(tbIndex.Text);
            myStr = Class1.LoadStrData2(myObj, myIndex);
            tbValue.Text = myStr;

        }

Open in new window


QUESTION: What changes are necessary to make this work from C#?
.NET ProgrammingVisual C++.NETC#

Avatar of undefined
Last Comment
deming

8/22/2022 - Mon
AndyAinscow

C# strings are UNICODE (double byte), not single byte (as you have in the dll).  
Have a think which side will be simplest for you to make the changes to - the C# or the C++ side.
deming

ASKER
I can't make changes to the C++ side so they will have to be made on the C# side. Can you provide the code changes necessary?
Minh Võ Công

You can try with stringbuilder
http://stackoverflow.com/questions/6153466/calling-a-c-dll-function-with-char-parameters-with-p-invoke
or byte array
 [DllImport("IECGlobalVars32.dll", CharSet = CharSet.Ansi)]
 public static extern bool SaveStrData(byte[] object1, int index, byte[] sValue);

[DllImport("IECGlobalVars32.dll", CharSet = CharSet.Ansi)]
        public static extern int ENCRYPT([MarshalAs(UnmanagedType.LPArray)]byte[] object1, int index, [MarshalAs(UnmanagedType.LPArray)]byte[] sValue);
when call function

private void btnSaveStr_Click(object sender, EventArgs e)
        {
            String myStr;
            Int32 myIndex = 0;
            String myObj;
            myObj = tbObj.Text;
            myStr = tbValue.Text;
            myIndex = System.Convert.ToInt32(tbIndex.Text);
            byte[] myObjByte= System.Text.Encoding.ASCII.GetBytes (myObj );
            byte[] myStrByte= System.Text.Encoding.ASCII.GetBytes (myStr );
            /// note: Can you need to allocate the more memory for myObjByte if necessary
            Class1.SaveStrData(myObjByte, myIndex, myStrByte);
        }
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
ASKER CERTIFIED SOLUTION
AndyAinscow

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
deming

ASKER
Great job Andy.  That worked for "LoadStrData" but not for "LoadStrData2".  Any other ideas for "LoadStrData2" ?
jiangsheng

Change the return value of LoadStrData2 from String to IntPtr. Use Marshal.Copy when you need to copy data off the pointer. Ask the author of the dll if it could return null, and if so when. Also ask the author how much data can be safely copied starting from the returning address.

Ask the author of the dll if you need to free the memory pointed to by the returning char*, and if so, how. If the pointer is allocated on the C++ heap, there is no way for you to free the memory, and the author must provide a function that does a delete on the same heap. If the address is allocated on the COM heap via CoTaskMemAlloc you can Marshal.FreeCoTaskMem to free the memory.
deming

ASKER
It turns out the LoadStrData2 is for VB6 using BSTR so it is not going to work with C#. Thank you everyone for your input and expertise.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.