tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルvb6での標準出力
記事No16366
投稿日: 2017/09/28(Thu) 19:10
投稿者ミッフィー
いつもお世話になっております
vb6で作成したexe同士での連携を考えています。
そのときに標準出力が使えないかと考え検索したところ、
なにやらできそうな気配なので以下のコードを実行しました

Dim FSO As new Scripting.FileSystemObject
Dim TSOUT As Scripting.TextStream
Dim strBuffer As String
Set TSOUT = FSO.GetStandardStream(stdOUT, False)
strBuffer = "Hello"
TSOUT.Writeline strBuffer

ここで、「writelineメソッドは失敗しました,ITextStreamオブジェクト」
となってしまいます。
これはどういうことなのでしょうか、
そもそも、vb6では標準出力ができないという話もあります

API経由でも
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Const STDOUT_HANDLE = -11&

Std_Hdl = GetStdHandle(STDOUT_HANDLE)
ここで、std_hdlが常に0です。ハンドルって何らかの数字がはいりますよね

OSはWin10ですが、セキュリティの問題でしょうか

[ツリー表示へ]
タイトルRe: vb6での標準出力
記事No16367
投稿日: 2017/09/29(Fri) 11:51
投稿者魔界の仮面弁士
> vb6で作成したexe同士での連携を考えています。
起動時に情報を一方通行的に渡すだけなら、
Shell 関数でコマンドライン引数を渡し、
それを Command 関数で受け取るのが楽でしょう。

双方向的な通信が必要なら、16bit 時代からの古いテクノロジーですが、
DDE を使うという手もあります。Form やコントロールが持つ
「Link某」というプロパティ / メソッド / イベントを調べてみてください。
http://7ujm.net/VB/VB6DDE.html


> そのときに標準出力が使えないかと考え検索したところ
そもそも、呼び出し元のコンソールが無いからですね…。

逆に言えば、呼び出し元がコンソールでさえあれば良いので、
PowerShell から『C:\TEST\Project1.exe | Write-Host』あるいは
コマンド プロンプトから『C:\TEST\Project1 | MORE』のように呼び出した場合は、
FileSystemObject の GetStamdardStream を使った最初のコードだけで、
呼び出し元のコンソールに表示されると思います。API 等も不要です。


もしも EXE を単体で起動したときに、コンソールが表示されるようにしたいなら、
そのアプリが「コンソール アプリケーション」でなければなりません。

VB6 は CUI アプリを作るためのものではないので、基本的には無理ですが、
\Microsoft Visual Studio\vb98\LINK.EXE を利用することで、
無理矢理 CUI アプリにするという裏技はあります。
hhttps://www.xaprb.com/blog/2005/10/14/how-to-create-a-vb6-console-program/

興味がある場合は、Visual Basic Magazine 誌のバックナンバーを探してきて
『Stealrideの逆襲 [Visual Basicで標準入出力を扱う]』を読んでみてください。
(手元の記録が間違っていなければ、June 1998 の記事だったはず)

とはいえ、そうまでして標準出力にこだわっても仕方がないでしょう。
正攻法で標準入出力を扱いたいのであれば、VB6 で ActiveX DLL をつくり、
呼び出し元を VBScript にすることです。CScript.exe からの
VBScript 呼び出してであれば、標準入出力を扱えます。


> そのときに標準出力が使えないかと考え検索したところ、
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As OLE_HANDLE) As Long
ではなく
Private Declare Function AllocConsole Lib "kernel32" () As Long
を呼ぶようにすれば、先のコード(FileSystemObject の GetStandardStream メソッドで得た
TextStream への Write メソッド呼び出し)にてコンソール出力が可能となります。

ただし、AllocConsole API を呼び出した時点で、新たにコンソール ウィンドウが
開かれることになります。(CUI アプリとしてコンパイルされない限りは)

新たに開くのではなく、呼び出し元のコンソールがあって、そこに割り当てたい場合には、
AttachConsole API を使います。

逆に、コンソールから切り離す場合は、FreeConsole API です。

[ツリー表示へ]
タイトルRe^2: vb6での標準出力
記事No16368
投稿日: 2017/09/29(Fri) 13:26
投稿者ミッフィー
お返事ありがとうございます。

話の流れとしては、2つの独立したプログラム間を
関数のように扱って、戻り値を受け取れれば、
開発楽だなと思ったのが始まりです。

で、ここまでの経験
(1)activex.dllですが、一部この方法も使っていますが
仕様変更(設計ミスですが)が頻発なので、都度コンパイルでレジストリも汚れるのが問題
安定稼働まではexeで作った方がいいかなと。

(2)vb.netのexeは標準出力ができるので
vb.net exe->vb6:WshShell:strResult = objExec.StdOut.ReadAll
といった感じで、結果を受け取ることができました
これに味を占めて、vb6.exe -> vb6が実現できないかなと考えたわけです。
(3)formを使わない sub main -> end ->end subのプログラムはコンソールアプリだと
持っていましたが、間違いなのですね。

とりとめのない返事になってしまい申し訳ないです

[ツリー表示へ]
タイトルRe^3: vb6での標準出力
記事No16369
投稿日: 2017/09/29(Fri) 14:24
投稿者魔界の仮面弁士
> お返事ありがとうございます。
すれ違いで、先の回答 ( No16367 ) を少し追記修正しています。m(_ _)m


> (1)activex.dllですが、一部この方法も使っていますが
レジストリを汚したくないのなら、先の DDE も検討してみてください。
ちなみに DDE は、Excel の読み書き制御にも使えます。(Excel 本体は必要ですが)


> 仕様変更(設計ミスですが)が頻発なので、
呼ばれる DLL に手を加えるのではなく、呼び出す EXE 側のマニフェスト保守が可能ならば、
Side-by-Side を使って非互換性の問題を回避する手もあります。(レジストリ登録不要)
https://msdn.microsoft.com/ja-jp/library/cc482775.aspx#vbxp2-3
https://msdn.microsoft.com/ja-jp/library/ms811700.aspx#sidebyside_topic8


> (2) vb.netのexeは標準出力ができるので
Console クラスの内部実装を読んでみるとか。
https://referencesource.microsoft.com/#mscorlib/system/console.cs


> (3)formを使わない sub main -> end ->end subのプログラムはコンソールアプリだと
> 持っていましたが、間違いなのですね。
「Form を表示するコンソールアプリ」なら、EXE をダブルクリックするとコンソールが表示されます。
しかし、「Form を表示しない Windows アプリ」では、コンソールは表示されませんね。

ちなみに EXE ファイル内の IMAGE_OPTIONAL_HEADER32.Subsystem という領域に、
コンソールアプリ(IMAGE_SUBSYSTEM_WINDOWS_CUI)なのか
Windows アプリ(IMAGE_SUBSYSTEM_WINDOWS_GUI) なのかが記録されています。
https://codezine.jp/article/detail/412
https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547.aspx

 0x0000 : unknown subsystem
 0x0001 : device driver / native system processes
 0x0002 : Windows GUI subsystem (普通に作るとこれ)
 0x0003 : Windows CUI subsystem (コンソールアプリはこれ)
 0x0005 : OS/2 CUI SubSystem
 0x0007 : Posix CUI subsystm
 0x0008 : native Windows 9x driver
 0x0009 : Windows CE system
 0x000A : EFI application
 0x000B : EFI driver(boot services)
 0x000C : EFI driver(run-time services)
 0x000D : EFI ROM image
 0x000E : XBOX system
 0x0010 : Boot application

[ツリー表示へ]
タイトルRe^2: vb6での標準出力
記事No16370
投稿日: 2017/09/29(Fri) 14:33
投稿者ミッフィー
ありがとうございます。とりあえず解決です
さきにテストしてから投稿すればよかったですね

関数的exe------------
Private Declare Function AllocConsole Lib "kernel32" () As Long
private Declare Function FreeConsole Lib "kernel32" () As Long

'ストリームの呼び出し前に
call allocConsole

TS.WriteLine ("dummy") '<=これでコマンドラインにテキスト表示
'またはapi経由でも
buffer = "APIDummy"
Std_Hdl = GetStdHandle(STDOUT_HANDLE)
API_Result = WriteFile(Std_Hdl, buffer, StdOut_Length, Written_Bytes, ByVal 0&)
'↑これでもテキスト表示
call freeconsole
---------終了

これで呼び出し側VB6から、strResult = objExec.StdOut.ReadAll で受取可能です。\(^o^)/

やりたいことは、
exe間の文字列受け渡しなので「標準出力」という表現は違うのかもしれません。
これで、問題ないでしょうか、メモリに残骸が残るとか。。
これでメモリに残骸が残ったりしませんか

[ツリー表示へ]