[Java] 纯文本查看 复制代码
package com;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.text.ParseException;
import java.util.prefs.Preferences;
public class WeixinMore extends JFrame {
private final JTextArea textArea = new JTextArea();
private String currentFilePath = null;
private static final String PREF_KEY = "wechat_shortcut_path";
private final Preferences prefs = Preferences.userNodeForPackage(WeixinMore.class);
public WeixinMore() {
super("微信多开小助手");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setLocationRelativeTo(null);
// 加载上次保存的路径
loadSavedPath();
JPanel dropPanel = createDropPanel();
JPanel bottomPanel = createBottomPanel();
setLayout(new BorderLayout(10, 10));
add(dropPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.SOUTH);
setVisible(true);
}
private void loadSavedPath() {
String savedPath = prefs.get(PREF_KEY, null);
if (savedPath != null && !savedPath.isEmpty()) {
File file = new File(savedPath);
if (file.exists() && (file.getName().toLowerCase().endsWith("wechat.exe")
|| file.getName().toLowerCase().endsWith("weixin.exe"))) {
currentFilePath = savedPath;
updateTextArea();
} else {
// 如果保存的路径无效,清除它
prefs.remove(PREF_KEY);
}
}
}
private void savePath(String path) {
if (path != null && !path.isEmpty()) {
prefs.put(PREF_KEY, path);
try {
prefs.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private JPanel createDropPanel() {
JPanel panel = new JPanel(new GridBagLayout()) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// 绘制虚线边框
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.GRAY);
g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 1, new float[]{5}, 0));
g2d.drawRect(5, 5, getWidth() - 11, getHeight() - 11);
g2d.dispose();
}
};
panel.setBackground(new Color(240, 245, 250));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JLabel label = new JLabel("<html><div style='text-align:center;'>"
+ "拖拽微信快捷方式到此处<br><font size='2' color='#888'>(仅支持快捷方式文件)</font></div></html>");
label.setFont(new Font("微软雅黑", Font.BOLD, 18));
panel.add(label);
// 设置拖拽目标
new DropTarget(panel, new DropTargetAdapter() {
@Override
public void drop(DropTargetDropEvent dtde) {
try {
dtde.acceptDrop(DnDConstants.ACTION_COPY);
// 获取拖拽的文件列表
java.util.List<File> files = (java.util.List<File>)
dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
// 验证文件
if (files.size() == 0) {
JOptionPane.showMessageDialog(panel, "未接收到文件", "错误", JOptionPane.ERROR_MESSAGE);
} else if (files.size() > 1) {
JOptionPane.showMessageDialog(panel, "仅支持拖拽单个文件", "错误", JOptionPane.WARNING_MESSAGE);
} else {
File file = files.get(0);
String fileName = file.getName().toLowerCase();
// 验证文件扩展名
if (!fileName.endsWith(".lnk")) {
JOptionPane.showMessageDialog(panel,
"只支持快捷方式文件 (.lnk)\n" +
"您拖拽的是: " + fileName,
"文件类型错误",
JOptionPane.ERROR_MESSAGE);
dtde.rejectDrop();
return;
}
// 更新文件路径并保存
currentFilePath = file.getAbsolutePath();
currentFilePath = WindowsShortcut.getLinkTargetPath(currentFilePath);
savePath(currentFilePath);
updateTextArea();
// 添加视觉反馈
panel.setBackground(new Color(230, 245, 255)); // 反馈色
new Timer(500, e -> panel.setBackground(new Color(240, 245, 250))).start();
}
dtde.dropComplete(true);
} catch (Exception ex) {
dtde.dropComplete(false);
JOptionPane.showMessageDialog(panel, "错误: " + ex.getMessage(), "读取失败",
JOptionPane.ERROR_MESSAGE);
}
}
});
return panel;
}
private JPanel createBottomPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
// 左侧文本区域
JScrollPane scrollPane = new JScrollPane(textArea);
textArea.setEditable(false);
textArea.setFont(new Font("微软雅黑", Font.PLAIN, 14));
textArea.setLineWrap(true);
panel.add(scrollPane, BorderLayout.CENTER);
// 右侧按钮区域
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
// 清除路径按钮
JButton clearButton = new JButton("清除路径");
clearButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
clearButton.setPreferredSize(new Dimension(90, 30));
clearButton.addActionListener(e -> {
currentFilePath = null;
prefs.remove(PREF_KEY);
updateTextArea();
JOptionPane.showMessageDialog(this, "已清除保存的路径", "提示", JOptionPane.INFORMATION_MESSAGE);
});
buttonPanel.add(clearButton);
// 微信双开按钮
JButton wechatButton = new JButton("启动微信双开");
wechatButton.setFont(new Font("微软雅黑", Font.BOLD, 14));
wechatButton.setPreferredSize(new Dimension(130, 35));
wechatButton.setBackground(new Color(7, 193, 96)); // 微信绿
wechatButton.setForeground(Color.WHITE);
wechatButton.setFocusPainted(false);
buttonPanel.add(wechatButton);
panel.add(buttonPanel, BorderLayout.EAST);
// 添加按钮点击事件
wechatButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startDoubleWeChat();
}
});
return panel;
}
private void updateTextArea() {
if (currentFilePath != null) {
textArea.setText("当前微信路径:\n" + currentFilePath);
} else {
textArea.setText("");
}
}
private void startDoubleWeChat() {
try {
// 如果当前没有路径,尝试加载保存的路径
if (currentFilePath == null) {
String savedPath = prefs.get(PREF_KEY, null);
if (savedPath != null && !savedPath.isEmpty()) {
currentFilePath = WindowsShortcut.getLinkTargetPath(savedPath);
updateTextArea();
}
}
// 尝试通过文件路径启动微信
if (currentFilePath != null && (currentFilePath.toLowerCase().endsWith("wechat.exe")
|| currentFilePath.toLowerCase().endsWith("weixin.exe"))) {
// 直接使用cmd命令启动快捷方式两次
Runtime.getRuntime().exec(currentFilePath);
Thread.sleep(1000); // 等待1秒
Runtime.getRuntime().exec(currentFilePath);
// 成功提示
JOptionPane.showMessageDialog(this,
"微信双开已启动成功!",
"操作成功",
JOptionPane.INFORMATION_MESSAGE);
return;
} else {
// 错误处理
int choice = JOptionPane.showConfirmDialog(this,
(currentFilePath == null ? "未设置微信路径" : "路径无效: " + currentFilePath) +
"\n\n是否尝试手动定位微信程序或快捷方式?",
"微信启动失败",
JOptionPane.YES_NO_OPTION,
JOptionPane.ERROR_MESSAGE);
// 如果用户选择手动定位
if (choice == JOptionPane.YES_OPTION) {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("选择微信程序或快捷方式");
// 默认打开微信可能的安装位置
chooser.setCurrentDirectory(new File("C:\\Program Files (x86)\\Tencent\\WeChat"));
chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() ||
f.getName().equalsIgnoreCase("WeChat.exe") ||
f.getName().equalsIgnoreCase("Weixin.exe");
}
@Override
public String getDescription() {
return "微信程序或快捷方式 (*.exe, *.lnk)";
}
});
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File selectedFile = chooser.getSelectedFile();
String selectedPath = selectedFile.getAbsolutePath();
// 如果是快捷方式,获取真实路径
if (selectedPath.toLowerCase().endsWith(".lnk")) {
currentFilePath = WindowsShortcut.getLinkTargetPath(selectedPath);
savePath(currentFilePath);
} else {
currentFilePath = selectedPath;
}
textArea.setText("已选择: " + currentFilePath);
// 尝试再次启动
try {
Runtime.getRuntime().exec(currentFilePath);
Thread.sleep(1000); // 等待1秒
Runtime.getRuntime().exec(currentFilePath);
JOptionPane.showMessageDialog(this,
"微信双开已成功启动!",
"操作成功",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception ex2) {
JOptionPane.showMessageDialog(this,
"启动失败: " + ex2.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
} catch (Exception e) {
JOptionPane.showMessageDialog(this,
"启动失败: " + e.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
WeixinMore frame = new WeixinMore();
frame.setVisible(true);
});
}
public static class WindowsShortcut {
private boolean isDirectory;
private boolean isLocal;
private String real_file;
public static boolean isPotentialValidLink(File file) throws IOException {
final int minimum_length = 0x64;
InputStream fis = new FileInputStream(file);
boolean isPotentiallyValid;
try {
isPotentiallyValid = file.isFile()
&& file.getName().toLowerCase().endsWith(".lnk")
&& fis.available() >= minimum_length
&& isMagicPresent(getBytes(fis, 32));
} finally {
fis.close();
}
return isPotentiallyValid;
}
public WindowsShortcut(File file) throws IOException, ParseException {
try (InputStream in = new FileInputStream(file)) {
parseLink(getBytes(in));
}
}
public String getRealFilename() { return real_file; }
public boolean isLocal() { return isLocal; }
public boolean isDirectory() { return isDirectory; }
private static byte[] getBytes(InputStream in) throws IOException { return getBytes(in, null); }
private static byte[] getBytes(InputStream in, Integer max) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buff = new byte[256];
while (max == null || max > 0) {
int n = in.read(buff);
if (n == -1) break;
bout.write(buff, 0, n);
if (max != null) max -= n;
}
in.close();
return bout.toByteArray();
}
private static boolean isMagicPresent(byte[] link) {
final int magic = 0x0000004C;
return link.length >= 32 && bytesToDword(link) == magic;
}
private void parseLink(byte[] link) throws ParseException {
try {
if (!isMagicPresent(link)) throw new ParseException("Invalid shortcut : magic is missing", 0);
byte flags = link[0x14];
byte file_attrs = link[0x18];
isDirectory = (file_attrs & 0x10) > 0;
final byte has_shell_mask = (byte) 0x01;
int shell_len = 0;
if ((flags & has_shell_mask) > 0) shell_len = bytesToWord(link, 0x4c) + 2;
int file_start = 0x4c + shell_len;
int file_location_info_flag = link[file_start + 0x08];
isLocal = (file_location_info_flag & 2) == 0;
int finalName_offset = link[file_start + 0x18] + file_start;
String finalName = getNullDelimitedString(link, finalName_offset);
if (isLocal) {
int baseName_offset = link[file_start + 0x10] + file_start;
String baseName = getNullDelimitedString(link, baseName_offset);
real_file = baseName + finalName;
} else {
int networkVolumeTable_offset = link[file_start + 0x14] + file_start;
int shareName_offset = link[networkVolumeTable_offset + 0x08] + networkVolumeTable_offset;
String shareName = getNullDelimitedString(link, shareName_offset);
real_file = shareName + "\\" + finalName;
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new ParseException("Could not be parsed, probably not a valid WindowsShortcut", 0);
}
}
private static String getNullDelimitedString(byte[] bytes, int off) {
int len = 0;
while (bytes[off + len] != 0) len++;
return new String(bytes, off, len);
}
private static int bytesToWord(byte[] bytes, int off) {
return ((bytes[off + 1] & 0xff) << 8) | (bytes[off] & 0xff);
}
private static int bytesToDword(byte[] bytes) {
return (bytesToWord(bytes, 2) << 16) | bytesToWord(bytes, 0);
}
public static String getLinkTargetPath(String linkPath) {
File file = new File(linkPath);
WindowsShortcut windowsShortcut;
try {
windowsShortcut = new WindowsShortcut(file);
} catch (IOException | ParseException e) {
return "";
}
return windowsShortcut.getRealFilename();
}
}
}