oneclick / rubyinstaller2

MSYS2 based RubyInstaller for Windows
https://rubyinstaller.org
BSD 3-Clause "New" or "Revised" License
661 stars 253 forks source link

win32ole fails. #161

Closed develowear closed 3 years ago

develowear commented 5 years ago

What problems are you experiencing?

2.3.x works, but the following errors are <=2.4.9, <=2.5.7 , and <=2.6.5 . For a long time, Ruby had been getting errors with win32ole since 2.4. Since 2.4 or later, I have been using 2.3.x for problems that cause the error.

Fails to control TTS application CeVIO Creative Studio 6 with win32ole. CeVIO Creative Studio 6 can do Japanese TTS and vocal music.

Steps to reproduce

Install CeVIO Creative Studio 6

CeVIO Creative Studio 6 (30-day free trial). The product page is as follows. http://cevio.jp/downloads/

  1. Download CeVIO_Creative_StudioSetup(6.X.XX.X).msi from [ CeVIO Creative Studio 6【無料体験版】ダウンロード ] of the above URL.

  2. Install CeVIO_Creative_StudioSetup(6.X.XX.X).msi. [ 次へ(N)> ] Next (Installation Guidance) ●同意する [ 次へ(N)> ] Next (I agree to the license.) [ 次へ(N)> ] Next (Install Folder) [ 次へ(N)> ] Next (Install Progress Bar) [ 閉じる(C) ] Close (The exit of the installation.)

  3. Start CeVIO CS6. Wait for a while (up to 80 seconds).

  4. ライセンス認証 dialog (Activation dialog) ●体験版を開始する (Start 30-day free trial) [OK]

You are now ready to call CeVIO from Ruby.

Write code for CeVIO TTS via Microsoft SAPI5

tts-sapi.rb

#! ruby -EUTF-8
# -*- mode:ruby; coding:utf-8 -*-

require "win32ole"

v = WIN32OLE.new('SAPI.SpVoice')

index = 0
v.GetVoices().each { |voice|
  puts "index = #{index}, #{voice.GetDescription}"
  index += 1
}

#index = 0    # Microsoft Haruka Desktop - Japanese
index = 1    # CeVIO-さとうささら    さSa-とTo-うu  さSa-さSa-らRa
#index = 2    # CeVIO-すずきつづみ    すSu-ずZu-きKi  つTsu-づZu-みMi
#index = 3    # CeVIO-タカハシ    タTa-カKa-ハHa-シShi
#index = 4    # Microsoft Zira Desktop - English (United States)
#index = 5    # CeVIO-ONE    O-Ne
v.Voice = v.GetVoices().Item(index)
description = v.Voice.GetDescription()
puts "The chosen voice: index = #{index}, #{description}"

# Volume 0..100
v.Volume = 50

# Rate -10..10
v.Rate = 0

en_jp = {
  "Thank you." => "ありがとうございました。"
}
v.Speak(en_jp["Thank you."])    # ★

Run tts_sapi.rb.

>ruby tts_sapi.rb

As a result, 2.4, 2.5, 2.6 errors are issued. However, it does not occur in 2.3.

>ruby tts-sapi.rb
index = 0, Microsoft Haruka Desktop - Japanese
index = 1, CeVIO-さとうささら
index = 2, CeVIO-すずきつづみ
index = 3, CeVIO-タカハシ
index = 4, Microsoft Zira Desktop - English (United States)
index = 5, CeVIO-ONE
The chosen voice: index = 1, CeVIO-さとうささら
tts-sapi.rb: (The part of the ★ mark above) :in `method_missing': (in OLE method `Speak': ) (WIN32OLERuntimeError)
    OLE error code:80004005 in <Unknown>
      <No Description>
    HRESULT error code:0x80020009
      Exception occurred.

Before the above error, the dialog of "Talker作成失敗 (Talker Creation Failure)" is displayed four times. Perhaps the four voices CeVIO-さとうささら, CeVIO-すずきつづみ, CeVIO-タカハシ, and CeVIO-ONE are related to those four error dialogs.

The index of the voice cast may vary depending on the language version of Windows.

Write code for CeVIO TTS without using Microsoft SAPI5

tts-cevio-simple.rb

#! ruby -EUTF-8
# -*- mode:ruby; coding:utf-8 -*-

require 'win32ole'

is_cevio_running = false
if is_cevio_running
  'C:\Program Files (x86)\CeVIO\CeVIO Creative Studio\CeVIO Creative Studio.exe'
end

service = WIN32OLE.new("CeVIO.Talk.RemoteService.ServiceControl")    # ▲

# ServiceControl version 4.0 Additional Features Interface: IServiceControlV40Part
service_v40p = service.ole_query_interface("{3CAEB0B2-9841-4D2D-BF9D-12BBE33C515F}")

service.StartHost(false)
talker = WIN32OLE.new("CeVIO.Talk.RemoteService.Talker")

# ServiceControl version 4.0 Additional Features Interface: ITalkerV40Part
talker_v40p = talker.ole_query_interface("{1746DA8E-49AC-46C2-9C72-6F089BCDD95B}")

cast_name = "さとうささら"
#cast_name = "すずきつづみ"
#cast_name = "タカハシ"
#cast_name = "ONE"

talker_values = {
  :emotion0 => 50,
  :emotion1 => 30,
  :emotion2 => 0,
  :emotion3 => 0,
  :volume => 60,
  :speed => 50,
  :tone => 50,
  :alpha => 80,
  :tone_scale => 55
}

# String to be uttered. "Hellow World. I am cast_name. Ruby can also speak."
str = "ハローワールド、#{cast_name}です。ルビーからも話せます。"

cast_names = []
casts = talker.AvailableCasts
0.step(casts.Length - 1) { |index|
  cast = casts.At(index)
  cast_names << cast.encode("UTF-8")
}
puts "Available cast name: #{cast_names.inspect}"

if !cast_names.include?(cast_name)
  raise "This cast name '#{cast_name}' cannot be specified. Specify an available cast name."
end

puts "Casts use '#{cast_name}'."
talker.Cast = cast_name

# Get emotional parameters.
emotions = []
components = talker.Components
0.step(components.Length - 1) { |index|
  emotion = components.At(index)
  emotions << emotion.Name.encode("UTF-8")
}
puts "Emotional parameters: #{emotions.inspect}"

# Setting emotional parameters.
components.ByName(emotions[0]).Value = talker_values[:emotion0].to_i
#   すずきつづみ           2 parameters.
components.ByName(emotions[1]).Value = talker_values[:emotion1].to_i
#   タカハシ               3 parameters.
components.ByName(emotions[2]).Value = talker_values[:emotion2].to_i   if 2 < emotions.length
#   さとうささら, ONE, IA    4 parameters.
components.ByName(emotions[3]).Value = talker_values[:emotion3].to_i   if 3 < emotions.length

# Volume 0..100
talker.Volume = talker_values[:volume].to_i

# Speed 0..100
talker.Speed = talker_values[:speed].to_i

# Tone 0..100
talker.Tone = talker_values[:tone].to_i

# Alpha 0..100
talker.Alpha = talker_values[:alpha].to_i

# ToneScale 0..100   ServiceControl version 4.0 Additional Features.
talker_v40p.ToneScale = talker_values[:tone_scale].to_i

state = talker.Speak(str)
state.wait

if is_cevio_running
  service.CloseHost(0)
end

Run tts-cevio-simple.rb.

>ruby tts-cevio-simple.rb

As a result, 2.4, 2.5, 2.6 errors are issued. However, it does not occur in 2.3.

>ruby tts-cevio-simple.rb
Traceback (most recent call last):
        2: from tts-cevio-simple.rb: (The part of the ▲ mark above) :in `<main>'
        1: from tts-cevio-simple.rb: (The part of the ▲ mark above) :in `new'
tts-cevio-simple.rb: (The part of the ▲ mark above) :in `initialize': failed to create WIN32OLE object from `CeVIO.Talk.RemoteService.ServiceControl' (WIN32OLERuntimeError)
    HRESULT error code:0x80070057
      The parameter is incorrect.

CeVIO CS6 Interface

http://guide2.project-cevio.com/interface

What's the output from ridk version?

2.4, 2.5, 2.6 any version fails.

Note

CeVIO Creative Studio 6 is now a 32-bit application. Therefore, Ruby uses the 32-bit version.

CeVIO Creative Studio 6 may take a lot of time to verify because the product deals with Japanese. Therefore, I hesitated to report it for a long time. Even under other circumstances that do not seem to be so, the following error is occurring with respect to win32ole is the same problem?

larskanis commented 5 years ago

Thank you @develowear for this very detailed report. I'm sorry for the trouble you've got, but I'm uncertain if I can help you.

The issue seems to be very similar to #108 . To that time we tried a Ruby-2.3.4 compiled with a modern msys2-mingw-gcc and it showed the same error as all newer rubies. So there's some incompatibility between OLE and recent MINGW toolchain. However I didn't dig deeper into the generated assembly code.

Did you already file an issue on http://bugs.ruby-lang.org ?

develowear commented 5 years ago

I should have written the version of Ruby 2.3.x I was using. I usually used the following. rubyinstaller-2.3.1.exe ruby 2.3.1p112 (2016-04-26 revision 54768) [i386-mingw32]

I tried to use the following in CeVIO CS6. ruby-2.3.3-i386-mingw32.7z ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]

I've never used Ruby 2.3.4 or later.

I have not reported any problems to http://bugs.ruby-lang.org. To me, a similar problem seemed to have already been reported about win32ole. Also, it didn't seem to solve. Therefore, I thought that the report destination was a RubyInstaller site, and I reported it here.

I don't have an account with bugs.ruby-lang.org yet and I haven't reported it yet. Also, the reason I reported it here was that it was difficult to understand how to report to bugs.ruby-lang.org.

If the accuracy of the machine translation of the WEB did not improve, I think that I did not report anywhere.

asm256 commented 5 years ago

In my test If you use ruby ​​built in vagrant, you can call CeVIO successfully.

vagrant_2.2.6_i686\HashiCorp\Vagrant\embedded\mingw32\bin\ruby -v
ruby 2.4.9p362 (2019-10-02 revision 67824) [i386-mingw32]

However, even if you port win32ole.so from vagrant, rubyinstaller2 still fails.

I don't understand why.

develowear commented 5 years ago

win32ole.so(V): Vagrant_2.2.6_i686.msi win32ole.so win32ole.so(R): rubyinstaller-2.4.9-1-x86.7z win32ole.so It is abbreviated as described above. Both are ruby 2.4.9p362 (2019-10-02 revision 67824) [i386-mingw32].

I also tried the following in the same way. I copied win32ole.so(V) to the rubyinstaller-2.4.9-1-x86\lib\ruby\2.4.0\i386-mingw32 folder. Result: An error was issued. Therefore, TTS was not able to be done by CeVIO.

I also tried the following. I copied win32ole.so(R) to the Vagrant\embedded\mingw32\lib\ruby\2.4.0\i386-mingw32 folder. Result: There were no errors. Therefore, TTS was able to be done with CeVIO.

larskanis commented 5 years ago

RubyInstaller-2.4+ makes use of a new DLL loading mechanism, that was introduced with Windows-7: https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers#user-content-dll-loading

Possibly the Speak method tries to load a DLL internally and fails. This was solved in #71 per RUBY_DLL_PATH .

develowear commented 5 years ago
RubyInstaller::Runtime.add_dll_directory("C:\\Program Files (x86)\\CeVIO\\CeVIO Creative Studio")

or

set RUBY_DLL_PATH="C:\Program Files (x86)\CeVIO\CeVIO Creative Studio"

I tried with tts-sapi.rb and tts-cevio-simple.rb as above, but RubyInstaller 2.4, 2.5, 2,6 failed in win32ole and couldn't TTS in CeVIO.

larskanis commented 5 years ago

Neither RUBY_DLL_PATH nor add_dll_directory support quoted paths, so you must use something like

set RUBY_DLL_PATH=C:\Program Files (x86)\CeVIO\CeVIO Creative Studio;c:/next/path

But you can use forward slashs if you like.

Maybe CeVIO has several directories for DLL or expects some third party DLL. You can debug Windows DLL loading as described here. The DLL loader output is very verbose and not so easy to read, but can help to track the issue down.

develowear commented 3 years ago

243

After removing lib\ruby\3.0.0\rubygems\defaults\operating_system.rb as per the above method, it now works without any errors in win32ole.

The same method worked for Ruby 2.6. Probably the same for 2.4 and above.

CeVIO Creative Studio 7 is a 64-bit version, but it worked in the same way using the 64-bit version of Ruby.

Cevio DL site http://guide2.project-cevio.com/

Download of CeVio CS6 32-bit version can be obtained from the link in the string below on the above site. "CeVIO CS6以前のバージョンはこちら"