# Talking to other applications on windows

**URL:** <https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968>\
**Category:** Ruby\
**Created:** [January 21, 2006, 9:27pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968 "2006-01-21T21:27:59Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![hotjuneshen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/f19dbf/32.png) [@hotjuneshen](https://www.ruby-forum.com/u/hotjuneshen)\
**Post date:** [January 21, 2006, 9:27pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968/1 "2006-01-21T21:27:59Z")

</div>

Dear list

For a customer I’m building a GUI for a analytical application. The  
analytical algorithm is confidential and implemented in a seperate .exe  
program. However I am very pleased to have the customer agreeing to  
build  
all of the surrounding application in Ruby.

The problem comes when calling the .exe program from my GUI-application.  
As of today I simply use the bactick operator to call the .exe with  
appropriate input:

```
 result = `calculate.exe 1,2,3,4,5,6 `

```

The result from calculate.exe is written to screen and stored as result.  
On a typical run, a couple hundred of these are executed, and everything  
works fine except one simple detail:

Every calculation opens and closes a unique DOS-window.

No need to elaborate, you all understand how 200 blinking DOS-windows  
does  
not look good. The number to aim for here is 0. How can this be done?

Ideas:  
I) Spawn each execution in the background.  
II) Don’t communicate over write to screen / read from screen  
- SOAP?  
- XML-RPC?  
- CORBA?  
III) Windows service?

Some degrees of freedom exist as the customer is quite skilled and  
willing  
to make _some_ modifications. calculate.exe is written in c#.

If anyone has any ideas, I would be very glad for all suggestions.

All the best  
Jon Egil S.

---

<div class="post-metadata">

**Author:** ![hotjuneshen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/f19dbf/32.png) [@hotjuneshen](https://www.ruby-forum.com/u/hotjuneshen)\
**Post date:** [January 21, 2006, 10:05pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968/2 "2006-01-21T22:05:42Z")

</div>

Pau

Thank you for your reply.

> It’s easier than that, just make use of cmdow:  
> [http://www.commandline.co.uk/cmdow/](http://www.commandline.co.uk/cmdow/)

Looks nice, but swallows output from the .EXE.

> But I think it would be better if you had a DLL instead of a .EXE and you  
> could call the functions in the DLL instead of running the .EXE.

OK, I can try, but how do I call DLLs from within Ruby? Through  
WIN32OLE?

All the best

---

<div class="post-metadata">

**Author:** ![hotjuneshen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/f19dbf/32.png) [@hotjuneshen](https://www.ruby-forum.com/u/hotjuneshen)\
**Post date:** [January 21, 2006, 9:43pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968/3 "2006-01-21T21:43:29Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

On Saturday 21 January 2006 21:26, Jon Egil S. wrote:

It’s easier than that, just make use of cmdow:  
[http://www.commandline.co.uk/cmdow/](http://www.commandline.co.uk/cmdow/)

But I think it would be better if you had a DLL instead of a .EXE and  
you  
could call the functions in the DLL instead of running the .EXE.

> I) Spawn each execution in the background.
> 
> All the best  
> Jon Egil S.

* * *

Pau Garcia i Quiles  
[http://www.elpauer.org](http://www.elpauer.org)  
(En general no puedo contestar antes de 10 días)  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFD0pyE/DzYv9iGJzsRArU0AJ4kk9FFlYEmfIt7x7nevUD/+PIhZgCgkWS+  
bFrLrrzqhuWY3CSVACyfszU=  
=4ZEo  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![hotjuneshen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/f19dbf/32.png) [@hotjuneshen](https://www.ruby-forum.com/u/hotjuneshen)\
**Post date:** [January 22, 2006, 9:41pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968/4 "2006-01-22T21:41:43Z")

</div>

Jon Egil S. wrote:  
…

> Some degrees of freedom exist as the customer is quite skilled and willing  
> to make _some_ modifications. calculate.exe is written in c#.
> 
> If anyone has any ideas, I would be very glad for all suggestions.

Add an XML-RPC (or SOAP, though probably overkill) API to the C# app and  
have it run as a service?

James B.

–

[http://www.ruby-doc.org](http://www.ruby-doc.org) - Ruby Help & Documentation  
[Ruby Code & Style](http://www.artima.com/rubycs/) - The Journal By & For Rubyists  
[http://www.rubystuff.com](http://www.rubystuff.com) - The Ruby Store for Ruby Stuff  
[http://www.jamesbritt.com](http://www.jamesbritt.com) - Playing with Better Toys  
[http://www.30secondrule.com](http://www.30secondrule.com) - Building Better Tools

---

<div class="post-metadata">

**Author:** ![hotjuneshen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/f19dbf/32.png) [@hotjuneshen](https://www.ruby-forum.com/u/hotjuneshen)\
**Post date:** [January 22, 2006, 10:03pm UTC](https://www.ruby-forum.com/t/talking-to-other-applications-on-windows/52968/5 "2006-01-22T22:03:04Z")

</div>

Jon Egil S. wrote:

> […]  
> No need to elaborate, you all understand how 200 blinking DOS-windows does  
> not look good. The number to aim for here is 0. How can this be done?

The windows are your complete problem?

look at this, you can uses it like

io = popen(‘ver’)  
puts io.read\_all

or

io = popen(‘cmd’)  
io.write(“ping localhost\nexit\n”)

while !(buffer = io.read).empty?  
print buffer.gsub("\r", ‘’)  
end

and there is no window poping up. (does work for windows only, but that  
seems to be ok for you, right?)

Here is the complete code, i posted this 11.09.2005 on this list.

cheers

## Simon

require ‘Win32API’

$stdout.sync = true

NORMAL\_PRIORITY\_CLASS = 0x00000020  
STARTUP\_INFO\_SIZE = 68  
PROCESS\_INFO\_SIZE = 16  
SECURITY\_ATTRIBUTES\_SIZE = 12

ERROR\_SUCCESS = 0x00  
FORMAT\_MESSAGE\_FROM\_SYSTEM = 0x1000  
FORMAT\_MESSAGE\_ARGUMENT\_ARRAY = 0x2000

HANDLE\_FLAG\_INHERIT = 1  
HANDLE\_FLAG\_PROTECT\_FROM\_CLOSE =2

STARTF\_USESHOWWINDOW = 0x00000001  
STARTF\_USESTDHANDLES = 0x00000100

def raise\_last\_win\_32\_error  
errorCode = Win32API.new(“kernel32”, “GetLastError”, [], ‘L’).call  
if errorCode != ERROR\_SUCCESS  
params = [  
‘L’, # IN DWORD dwFlags,  
‘P’, # IN LPCVOID lpSource,  
‘L’, # IN DWORD dwMessageId,  
‘L’, # IN DWORD dwLanguageId,  
‘P’, # OUT LPSTR lpBuffer,  
‘L’, # IN DWORD nSize,  
‘P’, # IN va\_list \*Arguments  
]

```
 formatMessage = Win32API.new("kernel32", "FormatMessage", params, 

```

‘L’)  
msg = ’ ’ \* 255  
msgLength = formatMessage.call(FORMAT\_MESSAGE\_FROM\_SYSTEM +  
FORMAT\_MESSAGE\_ARGUMENT\_ARRAY, ‘’, errorCode, 0, msg, 255, ‘’)

```
 msg.gsub!(/\000/, '')
 msg.strip!
 raise msg

```

else  
raise ‘GetLastError returned ERROR\_SUCCESS’  
end  
end

def create\_pipe # returns read and write handle  
params = [  
‘P’, # pointer to read handle  
‘P’, # pointer to write handle  
‘P’, # pointer to security attributes  
‘L’] # pipe size

createPipe = Win32API.new(“kernel32”, “CreatePipe”, params, ‘I’)

read\_handle, write\_handle = [0].pack(‘I’), [0].pack(‘I’)  
sec\_attrs = [SECURITY\_ATTRIBUTES\_SIZE, 0, 1].pack(‘III’)

raise\_last\_win\_32\_error if createPipe.Call(read\_handle,  
write\_handle, sec\_attrs, 0).zero?

[read\_handle.unpack(‘I’)[0], write\_handle.unpack(‘I’)[0]]  
end

def set\_handle\_information(handle, flags, value)  
params = [  
‘L’, # handle to an object  
‘L’, # specifies flags to change  
‘L’] # specifies new values for flags

setHandleInformation = Win32API.new(“kernel32”,  
“SetHandleInformation”, params, ‘I’)  
raise\_last\_win\_32\_error if setHandleInformation.Call(handle,  
flags, value).zero?  
nil  
end

def close\_handle(handle)  
closeHandle = Win32API.new(“kernel32”, “CloseHandle”, [‘L’], ‘I’)  
raise\_last\_win\_32\_error if closeHandle.call(handle).zero?  
end

def create\_process(command, stdin, stdout, stderror)  
params = [  
‘L’, # IN LPCSTR lpApplicationName  
‘P’, # IN LPSTR lpCommandLine  
‘L’, # IN LPSECURITY\_ATTRIBUTES lpProcessAttributes  
‘L’, # IN LPSECURITY\_ATTRIBUTES lpThreadAttributes  
‘L’, # IN BOOL bInheritHandles  
‘L’, # IN DWORD dwCreationFlags  
‘L’, # IN LPVOID lpEnvironment  
‘L’, # IN LPCSTR lpCurrentDirectory  
‘P’, # IN LPSTARTUPINFOA lpStartupInfo  
‘P’] # OUT LPPROCESS\_INFORMATION lpProcessInformation

startupInfo = [STARTUP\_INFO\_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
STARTF\_USESTDHANDLES | STARTF\_USESHOWWINDOW, 0,  
0, 0, stdin, stdout, stderror].pack(‘IIIIIIIIIIIISSIIII’)

processInfo = [0, 0, 0, 0].pack(‘IIII’)  
command \<\< 0

createProcess = Win32API.new(“kernel32”, “CreateProcess”, params,  
‘I’)  
raise\_last\_win\_32\_error if createProcess.call(0,  
command, 0, 0, 1, 0, 0, 0, startupInfo, processInfo).zero?

hProcess, hThread, dwProcessId, dwThreadId =  
processInfo.unpack(‘LLLL’)

close\_handle(hProcess)  
close\_handle(hThread)

[dwProcessId, dwThreadId]  
end

def write\_file(hFile, buffer)  
params = [  
‘L’, # handle to file to write to  
‘P’, # pointer to data to write to file  
‘L’, # number of bytes to write  
‘P’, # pointer to number of bytes written  
‘L’] # pointer to structure for overlapped I/O

written = [0].pack(‘I’)  
writeFile = Win32API.new(“kernel32”, “WriteFile”, params, ‘I’)

raise\_last\_win\_32\_error if writeFile.call(hFile, buffer, buffer.size,  
written, 0).zero?

written.unpack(‘I’)[0]  
end

def read\_file(hFile)  
params = [  
‘L’, # handle of file to read  
‘P’, # pointer to buffer that receives data  
‘L’, # number of bytes to read  
‘P’, # pointer to number of bytes read  
‘L’] #pointer to structure for data

number = [0].pack(‘I’)  
buffer = ’ ’ \* 255

readFile = Win32API.new(“kernel32”, “ReadFile”, params, ‘I’)  
return ‘’ if readFile.call(hFile, buffer, 255, number, 0).zero?

buffer[0…number.unpack(‘I’)[0]]  
end

def peek\_named\_pipe(hFile)  
params = [  
‘L’, # handle to pipe to copy from  
‘L’, # pointer to data buffer  
‘L’, # size, in bytes, of data buffer  
‘L’, # pointer to number of bytes read  
‘P’, # pointer to total number of bytes available  
‘L’] # pointer to unread bytes in this message

available = [0].pack(‘I’)  
peekNamedPipe = Win32API.new(“kernel32”, “PeekNamedPipe”, params,  
‘I’)

return -1 if peekNamedPipe.Call(hFile, 0, 0, 0, available, 0).zero?

available.unpack(‘I’)[0]  
end

class Win32popenIO  
def initialize (hRead, hWrite)  
@hRead = hRead  
@hWrite = hWrite  
end

def write data  
write\_file(@hWrite, data.to\_s)  
end

def read  
sleep(0.01) while peek\_named\_pipe(@hRead).zero?  
read\_file(@hRead)  
end

def read\_all  
all = ‘’  
while !(buffer = read).empty?  
all \<\< buffer  
end  
all  
end  
end

def popen(command)

# create 3 pipes

child\_in\_r, child\_in\_w = create\_pipe  
child\_out\_r, child\_out\_w = create\_pipe  
child\_error\_r, child\_error\_w = create\_pipe

# Ensure the write handle to the pipe for STDIN is not inherited.

set\_handle\_information(child\_in\_w, HANDLE\_FLAG\_INHERIT, 0)  
set\_handle\_information(child\_out\_r, HANDLE\_FLAG\_INHERIT, 0)  
set\_handle\_information(child\_error\_r, HANDLE\_FLAG\_INHERIT, 0)

processId, threadId = create\_process(ENV[‘ComSpec’] + ’ /C ’ +  
command, child\_in\_r, child\_out\_w, child\_error\_w)

# we have to close the handles, so the pipes terminate with the

process  
close\_handle(child\_in\_r)  
close\_handle(child\_out\_w)  
close\_handle(child\_error\_w)

Win32popenIO.new(child\_out\_r, child\_in\_w)  
end

if $0 == **FILE**  
io = popen(‘ver’)  
puts io.read\_all

io = popen(‘cmd’)  
io.write(“ping localhost\nexit\n”)

while !(buffer = io.read).empty?  
print buffer.gsub("\r", ‘’)  
end  
end
