0

I've done this before, but it has been a while and I am having issues finding any relevant examples. I have this legacy code:

namespace LegacyUtil {    
    public ref class Calc
    {
    public:
        static int Combos(int s)
        {
            int t = 0;
            // bunch of irrelevant loops
            printf("%c%d %c%d D%d\n", m, b, a, d, z);
            t++;
            return t;
        }
    };
}

Note: I have the ability to edit/recompile this in Visual C++ if neeeded but I will have to jump through at least one hoop.

My question: how do I capture the output of the C++ calls made to printf() from within my C# code? I have this code:

int test = LegacyUtil.Calc.Combos(1040);

Executes successfully but I only get the integer returned, and I want the string output. Please help!

Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • Have you tried: `std::stringstream`, `snprintf`? – Thomas Matthews Jun 27 '17 at 00:41
  • @ThomasMatthews have not tried modifying legacy code at all and was hoping it was possible to capture output without having to modify this code – Josh Stodola Jun 27 '17 at 00:41
  • What values within `Combos` are you trying to return? – Evan Weissburg Jun 27 '17 at 00:43
  • @EvanWeissburg do you see the call to printf()? That currently outputs a string that is 11 characters long with a line feed at the end. It does this hundreds of times within a loop and I need C# to be able to access that string – Josh Stodola Jun 27 '17 at 00:44
  • Great. So why not return the string instead of t? Unless I'm missing something. – Evan Weissburg Jun 27 '17 at 00:47
  • Have you looked at [this thread](https://social.msdn.microsoft.com/Forums/en-US/5da6cdb2-bc2b-4fff-8adf-752b32143dae/printf-from-dll-in-console-app-in-visual-studio-c-2010-express-does-not-output-to-console-window?forum=Vsexpressvcs)? – Orkhan Alikhanov Jun 27 '17 at 00:49
  • @EvanWeissburg seems so simple doesn't it? – Josh Stodola Jun 27 '17 at 00:50
  • @EvanWeissburg I take it you don't have much experience dealing with legacy code :) lucky guy – Josh Stodola Jun 27 '17 at 00:51
  • @JoshStodola You should clarify that returning the values necessary is not an option - modification of legacy code isn't always an impossibility. – Evan Weissburg Jun 27 '17 at 00:55
  • @EvanWeissburg it is an option. But again, it is not as simple as writing C# code and changing int to string[] and returning it (LOL). There is a bunch of crap I would have to do with char buffers. If you want to suggest a C++ alternative that would return my desired string, I would love to see it! That's what I am here for! – Josh Stodola Jun 27 '17 at 01:05
  • @ThomasMatthews any good examples I could look at? I basically need to take the formatting power of printf and somehow get this function to return a string. I really hate C++ – Josh Stodola Jun 27 '17 at 01:12
  • The problem is that the C++ code is outputting {directly} to the console. Unless you modify the operating system or have the User pipe the data, you are out of luck. If you are allowed to modify legacy code, you can print to a stream. Pass it a string stream, then you can extract the data from the string stream. – Thomas Matthews Jun 27 '17 at 01:28
  • @ThomasMatthews "Pass it a string stream, then you can extract the data from the string stream" this is what I cannot remember how to even begin to do – Josh Stodola Jun 27 '17 at 01:32
  • 1
    Can you replace printf with fprinf? Because fprintf will redirect the output to a file then you can read that file to get the output. – Jun Ge Jun 27 '17 at 04:24
  • @JunGe yes and I have actually accomplished that before asking this question, but I thought it would be most efficient to try and capture it in memory – Josh Stodola Jun 27 '17 at 06:24
  • @JunGe I didn't even change the C++ code, just spun up Process.Start in C# with a `>` to put the output to a file. It definitely works! But leaves me feeling like I need a shower – Josh Stodola Jun 27 '17 at 06:26

3 Answers3

1

The output of printf goes to stdout, which is a C filestream (or FILE*). You basically need to map stdout for your C++ code to a C# compatible stream.

This answer to another question should help you do that.

To just redirect your C++ stream into your C# console output, you can try (see: Redirecting Console.Out):

// courtesy of Reed Copsey
[DllImport("Kernel32.dll", SetLastError = true) ]
public static extern int SetStdHandle(int device, IntPtr handle);
...
consoleStream = new FileStream(Console.OpenStandardOutput());
SetStdHandle(-11, consoleStream.handle);

(note: I didn't test this at all)

Tasgall
  • 334
  • 1
  • 5
  • Now we're talkin! Thank you, I will be back – Josh Stodola Jun 27 '17 at 00:52
  • I tried Reed's solution, but unfortunately it does not work. It does not throw any errors, but my resulting .txt file is empty (yes I made sure to flush and close the stream). I think his solution is geared towards capturing output of a c# console app – Josh Stodola Jun 27 '17 at 01:31
0

If you're determined not to change the original source code, you can hack (I'm happy to call it that) your own code into the place of printf. But do so with caution, and anticipate issues.

printf is a library call. If you write your own printf, and make sure it is in the link order before the system library, your version will be called in preference to the system one.

Alternatively, it may be enough to #define the system printf to your own: so

#define printf my_print_func

although this kind of textual replacement is error prone, and things will come unstuck of there are other mentions that aren't plain printf calls (e.g. sprintf, snprintf, or some other function defined in the original code)

Finlay McWalter
  • 1,222
  • 1
  • 10
  • 12
  • Not 100% opposed to changing it, it *is* possible to do, but I can't for the life of me remember how to do strings in C++ and the length this function's output varies *greatly* – Josh Stodola Jun 27 '17 at 00:53
  • If I had to change the source code, what would I change it to? I think I could take a stab at getting sprintf() to work with a char buffer, but I can't for the life of me remember how to *return* that to C#. – Josh Stodola Jun 27 '17 at 01:06
  • 1
    I used to do it with two calls to a C style wrapper function I'd write that takes a byte array and returns the length of whatever it writes, but doesn't actually write anything if the input buffer is null. So the first call would get the length (which you could get with printf in this case, since it returns the length written), then set the size of the C# byte array before again calling the marshaled C style wrapper that writes to it. – Tasgall Jun 27 '17 at 01:28
0

So as far as my understanding goes, basically you want the output from one program to be captured in other.

Create an executable using:

#include <stdio.h>

int main()
{
   char line[BUFSIZ];
   while ( fgets(line, BUFSIZ, stdin) != NULL )
   {
      /* Do something with the line of text
   }
}

Then you can pipe the output of any program to it, read the contents line by line, do something with each line of text.

CocoCrisp
  • 807
  • 1
  • 9
  • 26