如何在 Windows 和/或 Mac 上的 Java 应用程序中找到我的“计算机描述”?

Posted

技术标签:

【中文标题】如何在 Windows 和/或 Mac 上的 Java 应用程序中找到我的“计算机描述”?【英文标题】:How do I find my "computer description" in a Java application on Windows and/or Mac? 【发布时间】:2011-04-25 11:08:40 【问题描述】:

我一直在努力寻找运行我的 Java 应用程序的计算机的“描述”。

我要的是在本地网络上为我的计算机做广告时用于 DNS 的名称(以下屏幕截图中的“iMac Mattijs”)。

在 Windows XP 上,此名称可在此处找到:控制面板 -> 系统 -> 计算机名称 -> 计算机描述。

在 Mac OS 10.6 上,可以在此处找到此名称:系统偏好设置 -> 共享 -> 计算机名称

下面的方法不提供我正在寻找的名称。看看这段代码:

    System.out.println("COMPUTERNAME environment variable: " + System.getenv("COMPUTERNAME"));
    try  System.out.println("localhost name: " + InetAddress.getLocalHost().getHostName());  
    catch (UnknownHostException e1) 

    try 
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) 
            NetworkInterface thisInterface = interfaces.nextElement();
            Enumeration<InetAddress> addresses = thisInterface.getInetAddresses();

            System.out.println("* network interface: " + thisInterface.getDisplayName());
             while (addresses.hasMoreElements()) 
                 InetAddress address = addresses.nextElement();
                 System.out.println(" - address: " + address.getCanonicalHostName());
             
                   
     catch (SocketException e) 

在 Windows 上,这会打印:

COMPUTERNAME environment variable: ARTTECH-51CA5F5
localhost name: arttech-51ca5f5
* network interface: MS TCP Loopback interface
 - address: localhost
* network interface: NVIDIA nForce Networking Controller - Packet Scheduler Miniport
* network interface: Broadcom 802.11n Network Adapter - Packet Scheduler Miniport
 - address: arttech-51ca5f5.lan
* network interface: Bluetooth Device (Personal Area Network)

在 Mac 上,我得到:

COMPUTERNAME environment variable: null
localhost name: imac-mattijs.lan 
* network interface: en1
 - address: imac-mattijs.lan
 - address: imac-mattijs.local
* network interface: lo0
 - address: localhost
 - address: fe80:0:0:0:0:0:0:1%1
 - address: localhost

但我正在寻找完整的字符串“iMac Mattijs”。

欢迎提供任何线索!

谢谢, 马蒂斯

【问题讨论】:

“描述”应该与DNS无关 嗨,Matt,当我在本地网络上找到我的计算机时,我看到了这个“计算机描述”(Windows)/“计算机名称”(Mac OS)。显然,这个手动输入的名称是 Bonjour/DNSSD 宣传的,你不这么认为吗? 这似乎是特定于平台的,因此您必须为您想要在 Java 应用程序中支持的每个平台以不同的方式检索您想要的计算机名称。 @Bernard:从缺乏这方面的专业知识来看,我认为你是对的。对于 Mac,使用 bonjour API 可能会有所帮助,在 Windows 上,除了 Andy 下面提到的 MAST 项目之外,我没有任何线索。 【参考方案1】:

这是我在一些实验中发现的。计算机描述存储在注册表项中

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters\srvcomment

所以,如果我们有任何 API 可以用来获取 reg 键值,我们可以找到它。

另外,找到以下链接,它提供了一个很好的类来查询 reg 键值:

http://www.rgagnon.com/javadetails/java-0630.html

而且,使用上面网站中给出的类 WinRegistry,我可以使用代码成功地找到计算机描述:

String computerName = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\services\\LanmanServer\\Parameters", "srvcomment");

【讨论】:

这是一个很好的答案,它完美无缺!尽管我将 Jeremy 的 Mac 答案标记为“最佳”答案,但这个答案解决了我在 Windows 上的问题,而且您是新用户,所以我奖励了您!谢谢! 请,请,请,不要这样做。此注册表项是technically documented,但这不是支持的查询此信息的方式。使用 NetServerGetInfoSERVER_INFO_101 - 这将通过 C/C++、Pinvoke 或 JNI 提供。特别是,一些 AV 产品锁定了 reg 密钥,但 Net API 继续工作。【参考方案2】:

Mac OS X 将计算机名称存储在系统配置动态存储中。对此的标准接口是通过系统配置框架。执行此 API 的命令行工具是 scutil:

$ scutil --get computerName
Hermes is awesome!

(我暂时将我的计算机名称更改为带有空格和标点符号的名称,以便可以很容易地与主机名区分开来,在这种情况下,主机名类似于hermes-is-awesome.local。)

您可以使用 JNI 轻松地与之交互:

class SCDynamicStore 
  public native String copyComputerName();
  static 
    System.loadLibrary("SCDynamicStore");
  


class HostnameSC 
  public static void
  main(String[] args) 
    SCDynamicStore store = new SCDynamicStore();
    String computerName = store.copyComputerName();
    System.out.format("computer name: %s\n", computerName);
  

现在是javac FILE.java,然后是javah SCDynamicStore。这会产生SCDynamicStore.h。将此复制到SCDynamicStore.c 并编辑为:

#include "SCDynamicStore.h"
#include <SystemConfiguration/SystemConfiguration.h>

JNIEXPORT jstring JNICALL
Java_SCDynamicStore_copyComputerName(JNIEnv *env, jobject o)

  SCDynamicStoreRef store = NULL;
  CFStringRef computerName = NULL;
  CFStringEncoding UTF8 = kCFStringEncodingUTF8;
  CFIndex length;
  Boolean ok;
  jstring computerNameString = NULL;
  CFStringRef process = CFSTR("com.me.jni.SCDynamicStore");

  store = SCDynamicStoreCreate(NULL, process, NULL/*callout*/, NULL/*ctx*/);
  if (!store) 
    fprintf(stderr, "failed to get store\n");
    goto CantCreateStore;
  

  computerName = SCDynamicStoreCopyComputerName(store, NULL);
  if (!computerName) 
    fprintf(stderr, "failed to copy computer name\n");
    goto CantCopyName;
  

  length = CFStringGetLength(computerName);
  length = CFStringGetMaximumSizeForEncoding(length, UTF8);
  
    char utf8[length];
    if (!CFStringGetCString(computerName, utf8, sizeof(utf8), UTF8)) 
      fprintf(stderr, "failed to convert to utf8\n");
      goto CantConvert;
    
    computerNameString = (*env)->NewStringUTF(env, utf8);
  

CantConvert:
  CFRelease(computerName);
CantCopyName:
  CFRelease(store), store = NULL;
CantCreateStore:
  return computerNameString;

(您可以通过使用 Obj-C 免费桥接并利用 -[NSString UTF8String] 来简化代码。在某些错误情况下,可能需要抛出异常而不是仅返回 NULL。)

然后您可以使用 clang -shared -I/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Headers/ -framework CoreFoundation -framework SystemConfiguration SCDynamicStore.c -o libSCDynamicStore.dylib 编译它。

现在,如果libSCDynamicStore.dylibLD_LIBRARY_PATH 一起,当它在当前目录中时,你可以运行应用程序:

$ java HostnameSC
computer name: Hermes is awesome!

【讨论】:

这是一个很好的答案,非常全面,而且有效!!非常感谢!为了完整起见,也许您可​​以将 java FILE.java 更改为 javac FILE.java (假设这就是您的意思)。再次感谢您的帮助!【参考方案3】:

您应该知道,一台计算机可以有多个 DNS 名称。

试试这个来获得一个名字:

调用java.net.NetworkInterface.getNetworkInterfaces()获取所有网络接口; 对于返回的每个NetworkInterface,调用java.net.NetworkInterface.getInetAddresses()获取一个接口的所有IP地址; 对于返回的每个 IP 地址,调用 java.net.InetAddress.getCanonicalHostName() 以获取关联的主机名; 选择其中一个主机名。

【讨论】:

您好史蒂夫,感谢您的回复。我尝试了您的建议,但不幸的是,这条路线没有提供我在问题中描述的我需要的计算机名称,而是提供完整的计算机名称。 @Mattijs 奇数。 InetAddress.getCanonicalHostName() 上的文档表明,如果可能,它会返回完全限定的主机名。它返回什么? 嗨,史蒂夫,我在原始帖子中添加了屏幕截图来说明问题。 InetAddress.getCanonicalHostName() 返回 arttech-51ca5f5,但我正在寻找名称“iMac Mattijs” @Mattijs 我描述的方法只返回一个名称吗?如果不是,您要在其他名称中查找的名称是什么? @Steve:我将您的建议连同结果一起添加到了我的原始帖子中。不幸的是,返回的名称都不代表文字的计算机描述,包括大写字母等。【参考方案4】:

我认为如果不采用原生方式,就不可能得到这个。如果你能找到一个允许你访问 WMI 的 java 库,那么你可以从字段 Description 中的对象 Win32_OperatingSystem 中获取它。

谷歌搜索提供了一些可能的选择;

http://henryranch.net/software/jwmi-query-windows-wmi-from-java/ 如果有点 hacky,非常简单(而且免费)。似乎可以通过将 .vbs 脚本写入临时目录并使用 Runtime.getRuntime().exec() 和 cscript.exe 调用它们来工作。

https://com4j.dev.java.net/

http://sourceforge.net/projects/jacob-project/ Java COM 桥接器。

我认为 Microsoft JVM 中包含的本机位也可能有所帮助。

【讨论】:

感谢您的指点!我去看看能不能找到办法:)【参考方案5】:

    获取com4j(直接下载链接) 这是一个可以调用的 Java 库 通讯。

    解压缩并在示例文件夹中 会找到一个 WMI 样本。

    将 Main.java 更改为以下内容,您应该进行设置。

package wmi; import com4j.Com4jObject; import wmi.events.ISWbemSinkEvents; public class Main public static void main(String[] args) throws Exception System.out.println("Connecting to WMI repository"); ISWbemLocator wbemLocator = ClassFactory.createSWbemLocator(); ISWbemServices wbemServices = wbemLocator.connectServer( "localhost","Root\\CIMv2","","","","", 0,null); System.out.println("connected"); System.out.println("Query Computer Description"); ISWbemObjectSet result = wbemServices.execQuery( "Select Description from Win32_OperatingSystem", "WQL",48,null); for( Com4jObject obj : result ) ISWbemObject wo = obj.queryInterface(ISWbemObject.class); System.out.println(wo.getObjectText_(0));

【讨论】:

虽然这似乎比直接查询注册表项稍微复杂一些,但这可能是在 Windows 上执行此操作的官方方式。这是一个很好的例子!我希望我可以两次奖励赏金,或者至少将多个答案标记为已接受的答案。我对此进行了测试,并且可以正常工作!谢谢!!【参考方案6】:

使用InetAddress.getHostName()怎么样?

System.out.println(
 "Name: " + java.net.InetAddress.getLocalHost().getHostName() );

编辑:所以上面的答案显然不是你想要的。但是...MAST 项目确实提供了一种检索计算机描述的方法。请参阅SysUtils.getComputerDescription()。此方法是特定于操作系统的。项目主页说 OSX 版本正在开发中。

【讨论】:

确实,看看 API,MAST 似乎找到了一种在 Windows 上做我需要的方法。不幸的是,他们的来源似乎没有开放。 是的,我注意到该项目已关闭。很不幸。我想他们只是编写了一个 JNI 库来完成所有繁琐的工作,所以如果你需要它,你可以半轻松地做同样的事情。【参考方案7】:

您确定您不只是在 COMPUTERNAME 环境变量之后,即您在该控制面板窗口中看到的内容吗?

【讨论】:

嗨迈克尔,感谢您的回复。 COMPUTERNAME 变量返回完整的计算机名称,这是一个有点神秘的字符串,包括一些看似随机的数字和字符。我需要的是更易读的计算机描述(windows)/计算机名称(mac os),如上所述。 @Mathijs:该名称通常不在 DNS 中。【参考方案8】:

MAC 的“纯”计算机名称:

private static String getComputerName() 
            String s = "";
            try 
                Process proc = Runtime.getRuntime().exec("scutil --get ComputerName");
                InputStream in = proc.getInputStream();
                int b;
                while ( (b = in.read()) >= 0) 
                    s += (char)b;
                
                in.close();
             catch (IOException e) 
                e.printStackTrace();
            
            return s;
        

【讨论】:

【参考方案9】:

该计算机描述/名称恰好是本地主机的主机名。您可以通过检查您的终端提示符来验证这一点,该提示符通常显示ComputerName:CurrentDirectory User$ 对应于默认的bash 提示符export PS1="\u@\h\w: "

所以使用:

try  
     InetAddress addr = InetAddress.getLocalHost();

     // Get hostname 
     String hostname = addr.getHostName();
 catch (UnknownHostException e)   

您应该能够根据需要获取本地主机名称。 我希望这会有所帮助。

参考:

http://osxdaily.com/2006/12/11/how-to-customize-your-terminal-prompt/ http://www.exampledepot.com/egs/java.net/Local.html

`

【讨论】:

这与我发布的答案有何不同? 除了小段没有特别的区别...我可能错过了,我的坏.. 正如您在我的问题中看到的那样,不幸的是,此方法没有返回我需要的名称。 @Mathijs:我明白了.. 看来我不仅错过了@Andy 的回复,还错过了你问题的细节......我真的应该更加注意阅读...... :)【参考方案10】:

好的,我自己找到了一种方法,但仅限于 Mac OS。对于那些想出办法在 Windows 上回答我的问题的人来说,赏金仍然是开放的。

运行此应用返回Computer Description: iMac Mattijs

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;

import com.apple.dnssd.*;

/**
 * Example of finding your computer description. Tested on Mac OS 10.6, Java 1.6
 * 
 * Note: make sure you're not compiling with JavaSE-1.6 but with JVM 1.6.0 (MacOS X Default), otherwise access to DNSSD libraries will be restricted.
 * 
 * @author mattijskneppers
 */

public class DescriptionFinder implements BrowseListener, ResolveListener 
    InetAddress local = null;
    HashMap<DNSSDService, String> fileSharingNameMap = new HashMap<DNSSDService, String>();

    public static void main(String[] args) 
        new DescriptionFinder();
       

    public DescriptionFinder() 
        try  local = InetAddress.getLocalHost();  catch (UnknownHostException e)  System.out.println("Error, couldn't resolve local host"); 

        try 
            DNSSD.browse("_afpovertcp._tcp", this);
         catch (DNSSDException e) 
            System.out.println("DeviceFinder: problem browsing for new file sharing");
            e.printStackTrace();
               
    

    @Override
    public void operationFailed(DNSSDService arg0, int arg1) 

    @Override
    public void serviceResolved(DNSSDService resolver, int flags, int ifIndex, String fullName, String hostName, int port, TXTRecord txtRecord) 
        InetAddress[] addresses = null;
        try 
            addresses = InetAddress.getAllByName(hostName);
         catch (UnknownHostException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        

        InetAddress ip = null;
        for (InetAddress address : addresses) 
            if (!address.isLinkLocalAddress()) 
                ip = address;
                break;
            
        

        String fileSharingName = fileSharingNameMap.get(resolver);
        if (fileSharingName != null) 
            if (ip.equals(local)) 
                System.out.println("Computer Description: " + fileSharingName);
            
               
    

    @Override
    public void serviceFound(DNSSDService service, int flags, int ifIndex, String serviceName, String regType, String domain) 
        //System.out.println("found file sharing: " + serviceName + ", domain: " + domain + ", regType: " + regType + ", flags: " + flags);
        try 
            DNSSDService resolver = DNSSD.resolve(flags, ifIndex, serviceName, regType, domain, this);
            fileSharingNameMap.put(resolver, serviceName);
         catch (DNSSDException e) 
            System.out.println("DeviceFinder: problem resolving new filesharing device");
            e.printStackTrace();
                   
    

    @Override
    public void serviceLost(DNSSDService service, int flags, int ifIndex, String serviceName, String regType, String domain) 

【讨论】:

@Jeremy:你是对的。您的解决方案绝对是可行的方法。

以上是关于如何在 Windows 和/或 Mac 上的 Java 应用程序中找到我的“计算机描述”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在PC或Mac上安装ISO文件

mac studio可以搭配windows嘛

在 Windows/Linux/Mac 上的 Java 程序中对全局热键做出反应?

Windows Vista/7 上的 SDL_Mixer MIDI 音量问题

如何从 Windows 7 pc 访问 Mac Osx 上的 localhost XAMPP?

使 Windows 上的字体像 Mac/Linux 一样渲染:禁用字体提示和/或在客户端处理抗锯齿