09-01-2017 08:41 AM
If you use AllocConsole, be warned. If you close the window, LabVIEW disappears as well. No warnings whatsoever.
09-05-2017 08:50 AM
@rolfk wrote:
A DLL doesn't have a stdin/stdout/stderr in itself. it inherits the stdin/stdout/stderr of whatever process the DLL is called from. But LabVIEW is a standard Windows GUI application and Windows does not allocate any stdIO handles for GUI applications by default.
I believe you can assign them later by a calling some Windows API functions but am not sure. Another option is to hack the PE header of your LabVIEW executable to indicate to Windows that it should allocate stdIO handles anyhow. Most likely there is also a possibility to add something in a manifest file to achieve the same.
What I usually do is adding a function to the DLL that can be called from LabVIEW to pass a user even refnum to it and in the DLL have a replacement printf() macro that checks this refnum and sends the string to LabVIEW through PosLVUserEvent() if it is not NULL, otherwise calls the normal printf(). The difficulty with that is that achieving fully variadic operation like the printf() function has is not really possible with standard C macro logic.
Thank you for this response. This clears up a lot. So, within LabVIEW if I perform an AllocConsole and get the handle for STDOUT and STDERR. At that point a call into a DLL should allow the DLL to inherit the created STDIO from LabVIEW? Is it really that easy?
I like solution you said that you used, but the DLL is using standard C currently. I think it might be possible to modify this, but at the very least it would mean a special build of our API specifically for LabVIEW use.
09-05-2017 08:58 AM
scorn001 wrote:
Thank you for this response. This clears up a lot. So, within LabVIEW if I perform an AllocConsole and get the handle for STDOUT and STDERR. At that point a call into a DLL should allow the DLL to inherit the created STDIO from LabVIEW? Is it really that easy?
If you use AllocConsole, writing to StdOut ends up in the new console. I didn't use a dll, but a .net function, but since dll's use the process's StdOut that should be the same.
I wasn't able to reading from that console, back into LV, or to redirect the console's stdout to something that I could read in LV.
09-05-2017 09:07 AM
At least this sounds like a good temporary solution to let me troubleshoot what is happening if it works this way with a dll. It would be really nice to have all of this output appear in a LabVIEW debug window of course.
I'm going to give this a try.
09-05-2017 10:24 AM
I too am very interested in a solution to this. I've tried a few things but no success so far. If another poster figures this out please post your solution. I'll do the same.
Thanks
09-06-2017 10:35 AM - edited 09-06-2017 10:36 AM
For those interested, I have made some progress on this. I've found that if I use the code below in my DLL, I am able to read the printf messages from within LabVIEW by reading a pipe, using the stdio.zip example code provided previously. If any of you are interested, I'll happily share it.
The issue I'm running into now, if I attempt to use a '\n' for a CR/LF in a printf within the DLL, and then use another printf after, the Call Library Function Node call will not return. It just hangs somewhere within the called function. I've attempted to add a 'flush(stdout)' between the two printfs and it does not help.
Interestingly, if I either reduce the two printfs to one - still using the '\n' to separate the lines -OR- just remove the '\n' and have the two printfs not use a CR/LF, then it seems to work fine, the call to the DLL returns normally and I'm able to read the text out.
extern "C" __declspec(dllexport)int testPrintf(VOID )
{
HANDLE hStdout;
int fStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
fStdout = _open_osfhandle((intptr_t)hStdout, 0);
FILE* f = _fdopen(fStdout, "w");
_dup2(_fileno(f), _fileno(stdout));
printf("This was generated with printf.\n\nSo was this");
fflush(stdout);
return(10);
}
09-06-2017 11:22 AM
For those interested in this, I have made some progress.
Using the code below in the DLL, I have been able to get a printf(s) within the DLL to output text that is readable from a pipe within LabVIEW, which I can then put into a text window. Just using a slightly modified version of the Example Output.vi provided previously in the STDIO.zip.
It's a little bit clumsy right now having to use the extra code in the DLL. I'd prefer to be able to get all of that done outside of the DLL so that it doesn't need to be modified for LabVIEW purposes.
extern "C" __declspec(dllexport)int testReadParams(VOID )
{
HANDLE hStdout;
int fStdout;
int a;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
fStdout = _open_osfhandle((intptr_t)hStdout, 0);
FILE* f = _fdopen(fStdout, "w");
_dup2(_fileno(f), _fileno(stdout));
a = 50 + 100;
printf("I wonder if this will work.\n ");
printf(" The answer is %d....", a);
fflush(stdout);
return(10);
}
09-07-2017 04:45 AM - edited 09-07-2017 04:55 AM
Success!!!
I think I got it! With .NET it does not seem to be that difficult (if you know how).
It could be worked out a little bit. Closing those refs is a good idea. Also, every read now reads the entire buffer. Note that the buffer "scrolls": when more data is added, the data at the begin is flushed if the buffer is full. I used 50 just to test. And I have no idea how this behaves when two processes read\write very fast (Position might set the write position as well).
But it seems like a good start. And it's flexible. Redirecting to a file stream is easy, separate StdOut and StdError is easy. StdIn should be similar.
I used this to write:
09-07-2017 06:06 AM
Awesome. I'm glad you got it working with .NET. With C, I have got it working, but right now it looks like I'm going to have to either make modifications to the existing DLL, or add DLL in the middle to setup the pipes and STDOUT/STDERR redirect. I was really hoping I could do all of that in LabVIEW and just call into the existing, unmodified DLL but at this point I'm not able to make it work.
I'm attempting to duplicate this code(which works) in LabVIEW:
... hStdout = GetStdHandle(STD_OUTPUT_HANDLE); unsigned long bytesWritten = 0; fStdout = _open_osfhandle((intptr_t)hStdout, 0); FILE* f = _fdopen(fStdout, "w"); _dup2(_fileno(f), _fileno(stdout));
<EXTERNAL DLL CALL>...
fflush(stdout);
...
09-07-2017 06:12 AM
But why do you still need that? If you run the .NET code, the dll's stdout will end up in the string... At least, that's the plan.