如何在 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,但这不是支持的查询此信息的方式。使用NetServerGetInfo
和 SERVER_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.dylib
与LD_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 应用程序中找到我的“计算机描述”?的主要内容,如果未能解决你的问题,请参考以下文章
在 Windows/Linux/Mac 上的 Java 程序中对全局热键做出反应?
Windows Vista/7 上的 SDL_Mixer MIDI 音量问题