在 windows 上的 Eclipse RCP 应用程序中使用时如何禁用 swt 浏览器点击声音?

How to disable the swt Browser clicking sound when used in Eclipse RCP application on windows?

我在我的 Eclipse RCP 应用程序中嵌入了一个 swt 浏览器。我的问题是,在 Windows 上,浏览器的 setUrl()dispose() 方法会导致(恼人的)Internet Explorer 导航声音('click'),这是不受欢迎的。

我找到了这段成功关闭点击声音的代码

OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);

但由于这是受限制的 API 我在使用 Maven/Tycho 构建应用程序时遇到了问题。

[ERROR] OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
[ERROR] ^^
[ERROR] OS cannot be resolved to a variable
[ERROR] 4 problems (4 errors)
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.eclipse.tycho:tycho-compiler-plugin:0.22.0:compile (default-compile) on project com.myapp: Compilation failure
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)...

有没有办法让 Maven/Tycho 在使用这个受限制的 API 时进行编译?

或者有其他方法可以在 Windows 上禁用 IE 浏览器导航声音吗?

我最终成功破解了这个,方法如下。

由于这个限制性 API 存在于特定于平台的插件中,即 SWT 32 位和 SWT 64 位,我创建了两个特定于平台的片段来保存代码。

要让 Maven 编译片段,需要将以下行添加到文件 build.properties:

中的 32 位片段
extra.. = platform:/fragment/org.eclipse.swt.win32.win32.x86

以及以下 64 位片段 build.properties

extra.. = platform:/fragment/org.eclipse.swt.win32.win32.x86_64

maven pom 配置文件也应该是平台特定的,这是通过在 32 位片段 pom.xml 中添加以下部分来完成的

<build>
    <plugins>
        <plugin>
            <groupId>org.eclipse.tycho</groupId>
            <artifactId>target-platform-configuration</artifactId>

            <configuration>
                <environments>
                    <environment>
                        <os>win32</os>
                        <ws>win32</ws>
                        <arch>x86</arch>
                    </environment>
                </environments>
            </configuration>
        </plugin>
    </plugins>
</build>

这是 64 位版本。

<build>
    <plugins>
        <plugin>
            <groupId>org.eclipse.tycho</groupId>
            <artifactId>target-platform-configuration</artifactId>
            <configuration>
                <environments>
                    <environment>
                        <os>win32</os>
                        <ws>win32</ws>
                        <arch>x86_64</arch>
                    </environment>
                </environments>
            </configuration>
        </plugin>
    </plugins>
</build>

另外不要忘记在片段清单中设置相应的平台过滤器,如此处所示

Eclipse-PlatformFilter: (& (osgi.os=win32) (osgi.arch=x86))
Eclipse-PlatformFilter: (& (osgi.os=win32) (osgi.arch=x86_64))

然后我们将沉默代码放在每个片段的 Class 中。 class 应该在主机插件中实现一个接口。 主机插件定义了一个扩展点,它采用 class 实现主机插件中的接口。然后片段声明一个扩展并在片段中提供 class 名称。

当主机代码需要 运行 静音代码时,它需要检查扩展并实例化并调用静音代码。

示例:

package com.mypackage;

import javax.inject.Inject;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.e4.core.di.annotations.Creatable;

import com.mypackage.ISilencer;

@Creatable
public class BrowserSilencer {

    private static final Logger LOGGER = Logger.getLogger(BrowserSilencer.class);

    @Inject
    IExtensionRegistry exReg;

    public void silence=() {
        IConfigurationElement[] config = exReg.getConfigurationElementsFor("com.mypackage.silencer");
        try {
            for (IConfigurationElement e : config) {
                final Object o = e.createExecutableExtension("class");
                if (o instanceof ISilencer) {
                    executeExtension(o);
                }
            }
        } catch (CoreException ex) {
            LOGGER.error("Error finding the com.mypackage.silencer extension");
        }
    }

    private void executeExtension(final Object o) {
        ISafeRunnable runnable = new ISafeRunnable() {
            @Override
            public void handleException(Throwable e) {
                LOGGER.error("Exception while attempting to silence browser");
            }

            @Override
            public void run() throws Exception {
                ((ISilencer) o).silence();
            }
        };
        SafeRunner.run(runnable);
    }
}

主机插件中的接口

package com.mypackage;
public interface ISilencer {
   public void silence();
}

以及 64 位插件中的代码示例。 32位几乎一样

package com.mypackage.fragment.win64;

import org.apache.log4j.Logger;
import org.eclipse.swt.internal.win32.OS;   // yes i DO mean win32 here

import com.mypackage.ISilencer;

@SuppressWarnings("restriction")
public class Silencer implements ISilencer {

    private static final Logger LOGGER = Logger.getLogger(Silencer.class);

    @Override
    public void silence() {
        // removes the annoying browser clicking sound!
        try {
            OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
        } catch (Throwable e1) {
            // I am just catching any exceptions that may come off this one since it is using restricted API so that if in any case it fail well it will just click.
            LOGGER.error("Caught exception while setting FEATURE_DISABLE_NAVIGATION_SOUNDS.");
        }
    }
}

由于 BrowserSilencer 被标记为 @Creatable,您只需将其注入 class 并调用 silence() 方法

如果不清楚如何创建和扩展点,我可以在随后的 post.

中展示

在 Windows(使用 IE)中使用 SWT 浏览器时,我必须解决(可能)相同的导航声音问题,并且我能够找到需要更改代码的解决方案 w/o。

我发现可以通过在 Windows 控制面板中禁用 None 特定声音来改变它。我只在 Win 7 中验证过:

Control Panel => Sound => Sounds => Windows Explorer => Start Navigation
FROM: Windows Navigation Start.wav
TO: NONE

我希望这对正在寻找非代码解决方案的任何人有所帮助。

// Silence Windows SWT.browser widget from making awful clicks. 
// For windows 32 and 64 bit SWT applications. 
// Uses reflection to call OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
// Without importing platform specific 
// #import org.eclipse.swt.internal.win32.OS  
private void silenceWindowsExplorer() {
    try {
        Class<?> c = Class.forName("org.eclipse.swt.internal.win32.OS");
        java.lang.reflect.Method method = c.getDeclaredMethod("CoInternetSetFeatureEnabled", Integer.TYPE, Integer.TYPE, Boolean.TYPE);
        method.invoke(null, new Object[] {21, 2, true});
    } catch (Throwable th)
    {
        // Might fail.. but probably will never do harm.
        th.printStackTrace();
    }
}