Tech Off Thread

7 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

P/Invoke with char* gives AccessViolationException

Back to Forum: Tech Off
  • User profile image
    bugsy_malone

    I've been stuck on this one for days, I'm hoping that someone in here has been through this hurdle before and remembers how to get past it.

    Background:  I'm trying to access some logic in a Win32 C EXE.  I've
    gotten 1 _very_ simple test function to work, but as soon as I try to
    do anything with pointers nothing will work (I keep getting AccessViolationExceptions).


    Here's the C code for the test function that works:

    int __declspec(dllexport) myAdd(int a, int b)
    {
         return a + b;
    }

    then in .Net I use the following:

            [DllImport(@"c:\myCCode.exe",
                EntryPoint = "myAdd",
                ExactSpelling = false,
                CallingConvention = CallingConvention.Cdecl)]
            static extern int c_add(int a, int b);

    I can call "c_add(5, 2)" and get 7 no problem.

    My next test was to do some text manipulation.

    void __declspec(dllexport) myText(char* output)
    {
        sprintf(output, "Hello world!");
    }

    The .net code:

            [DllImport(@"c:\myCCode.exe",
                EntryPoint = "myText",
                ExactSpelling = false,
                CallingConvention = CallingConvention.Cdecl)]
            static extern void c_text(StringBuilder output);

    StringBuilder sb = new StringBuilder(15);//plenty of room
    myText(sb); <-- throws an AccessViolationException

    How am I supposed to do text manipulation?  If it makes a difference, here are the commands I'm using to compile the C code:
    Compile: "cl -Zi -Od -c -W2 -DWIN32 myCcode.c"
    Link: "link -debug -out:myCcode.exe myCcode.obj"

    Thank you so much for your help, this has really been a hassle.

  • User profile image
    bugsy_malone

    The function calls don't have a problem being exported.  I don't know what the difference is between C and C++ in this regard, but without the "extern "c"" the program compiles fine and a dumpbin shows my function great.  .Net doesn't complain about not finding the entry point either.

    As soon as I add the "extern "c"" then I get the following compile error:
    "error C2059: syntax error : 'string'

    Like I said, I don't know what the difference is between my C not needing/wanting/accepting the 'extern "c"' vs. your c++ requiring it to have a nicely exported function name.  (my guess is that cl.exe is automatically creating the .def definitions file)

    What's next?

  • User profile image
    Cannot​Resolve​Symbol

    Two ideas:

    * Use String instead of StringBuilder as your argument
    * Use Char[] as the argument and use the method as so:

    String s = "something";
    c_text(s.ToCharArray());

  • User profile image
    Antitorgo

    Hmm... Only problem I can see offhand (and I tested it to be sure just in case) was that you didn't use:

    extern "C"

    In your C function definitions which left the function calls decorated. By adding that everything seemed to work fine using:

    [DllImport(@"c:\test.exe", EntryPoint = "myText")]

    If I left the extern "C" off and used the decorated name (via dumpbin) that also worked.

    [DllImport(@"C:\test.exe", EntryPoint = "?myText@@YAXPAD@Z")]

    So it looks like your problem was more in the decorated names in C++ than anything.

    You can read more about it here:
    http://msdn2.microsoft.com/en-us/library/aa446532.aspx

  • User profile image
    Sven Groot

    In C++ you can use extern "C" to indicate the function uses C linkage instead of the default C++ linkage which has the effect of removing the name decoration (C does not allow overloaded functions so it doesn't need name decoration to distinguish functions). This is usually done if you are linking C and C++ files together and want the C files to call functions in the C++ files.
     
    If you're already using C, there's no reason to use it (and as you found out, you can't anyway). I usually find it easier to just write a .def file instead of using __declspec(dllexport), that way you never have to worry about decorated names.

    As for your problem. I would indeed recommend using string and not StringBuilder. You only need StringBuilder if the C function writes to the buffer. The second thing I would do is specify CharSet=CharSet.Ansi on the DllImport attribute. And if that doesn't work, I'd also try putting a [MarshalAs(UnmanagedType.LPStr)] on the parameter.

    Lastly, although I don't think it's really related to your problem, I would switch to using __stdcall calling convention. It's the default calling convention in Windows for DLL exported functions, and also the default convention for PInvoke (so you don't have to specify the CallingConvention on the DllImport anymore). All you need is to do is add __stdcall to the C function declaration.

    EDIT: Sorry, I only just noticed you are using sprintf. In that case, you do need a StringBuilder. The points about specifying the character set still stand though.

    EDIT2: I just made a little test with exactly your code (no changes) and it works fine. The only difference is that I'm using a DLL and not an EXE.

    EDIT3: I just switched to an EXE and now I get an error. Any reason why you're using an EXE and not a DLL? You're not really supposed to use EXEs for this.

  • User profile image
    Sven Groot

    I think I know what's going on. It has nothing to do with strings or not, it's to do with the sprintf call.

    If you use a DLL as you're supposed to, Windows invokes the DLL entry point function (DllMain) before calling any exported functions. Even if your own DllMain is empty, VC (and most other C++ compilers) use this time to initialize the C standard library.

    But you're using an EXE which isn't meant to be used this way. It has no DLL entry point so nothing is executed when it's loaded like this. The C standard library is not properly initialized, and so the myText function, which accesses a C library function, doesn't work.

    Just add a "printf("%i", a);" (or any other C library call) to the add function and you'll see it fails too.

    So the answer is, use a DLL. There's no other way around this.

  • User profile image
    bugsy_malone

    Sven,

    Would it be possible for me to contact you through email, so I can send you actual screenshots of what's going on?

    You can reach me at jallen [at] americansavingslife *dot* _com_

    Thanks!

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.