'commit'
BIN
Test/Screenshots/chat_result_20260125_085757.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
Test/Screenshots/chat_result_20260125_085757_analyzed.jpg
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
Test/Screenshots/chat_result_20260125_085849.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
Test/Screenshots/chat_result_20260125_085849_analyzed.jpg
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
Test/Screenshots/chat_result_20260125_090600.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
Test/Screenshots/chat_result_20260125_090600_analyzed.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 76 KiB |
BIN
Test/Screenshots/debug_send_check_20260125_085804.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
Test/Screenshots/debug_send_check_20260125_090610.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
@@ -1,271 +0,0 @@
|
|||||||
# coding=utf-8
|
|
||||||
import uiautomator2 as u2
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# 配置日志
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
||||||
logger = logging.getLogger("TestWeChat")
|
|
||||||
|
|
||||||
def analyze_chat_image(image_path, output_path):
|
|
||||||
"""
|
|
||||||
识别微信聊天截图中的头像并画框
|
|
||||||
"""
|
|
||||||
logger.info(f"正在分析图片: {image_path}")
|
|
||||||
|
|
||||||
# 读取图片
|
|
||||||
# 注意:cv2.imread 不支持中文路径,需要用 np.fromfile 读取
|
|
||||||
try:
|
|
||||||
img_data = np.fromfile(image_path, dtype=np.uint8)
|
|
||||||
img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"读取图片失败: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
if img is None:
|
|
||||||
logger.error("图片读取为空")
|
|
||||||
return
|
|
||||||
|
|
||||||
height, width = img.shape[:2]
|
|
||||||
logger.info(f"图片尺寸: {width}x{height}")
|
|
||||||
|
|
||||||
# 1. 预处理
|
|
||||||
# 转为灰度图
|
|
||||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
||||||
|
|
||||||
# 使用自适应阈值二值化
|
|
||||||
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
|
||||||
cv2.THRESH_BINARY_INV, 11, 2)
|
|
||||||
|
|
||||||
# 形态学操作:闭运算,填充内部空洞
|
|
||||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
|
||||||
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
|
|
||||||
|
|
||||||
# 2. 轮廓查找
|
|
||||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
||||||
logger.info(f"检测到轮廓数量: {len(contours)}")
|
|
||||||
|
|
||||||
# 收集所有符合条件的头像
|
|
||||||
avatars = []
|
|
||||||
|
|
||||||
# 3. 筛选轮廓
|
|
||||||
for contour in contours:
|
|
||||||
# 获取外接矩形
|
|
||||||
x, y, w, h = cv2.boundingRect(contour)
|
|
||||||
|
|
||||||
# 筛选条件优化:
|
|
||||||
# 1. 形状接近正方形 (放宽宽高比限制: 0.8 ~ 1.2)
|
|
||||||
aspect_ratio = float(w) / h
|
|
||||||
|
|
||||||
# 2. 尺寸适中
|
|
||||||
# 假设头像宽度在屏幕宽度的 6% 到 15% 之间
|
|
||||||
min_w = width * 0.06
|
|
||||||
max_w = width * 0.15
|
|
||||||
|
|
||||||
# 3. 位置筛选
|
|
||||||
# 排除底部输入框区域 (假设底部 10% 为输入区域)
|
|
||||||
if y > height * 0.9:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 左侧头像:靠左边 (x < width * 0.18)
|
|
||||||
# 右侧头像:靠右边 (x > width * 0.82)
|
|
||||||
is_left = x < width * 0.18
|
|
||||||
is_right = x > width * 0.82
|
|
||||||
|
|
||||||
if 0.8 <= aspect_ratio <= 1.2 and min_w < w < max_w:
|
|
||||||
if is_left or is_right:
|
|
||||||
side = "Left" if is_left else "Right"
|
|
||||||
avatars.append({
|
|
||||||
'x': x, 'y': y, 'w': w, 'h': h,
|
|
||||||
'side': side
|
|
||||||
})
|
|
||||||
|
|
||||||
# 按 y 坐标排序
|
|
||||||
avatars.sort(key=lambda a: a['y'])
|
|
||||||
|
|
||||||
logger.info(f"找到有效头像数量: {len(avatars)}")
|
|
||||||
|
|
||||||
# 4. 绘制对话内容框 (Green/Red Boxes)
|
|
||||||
# 策略:按顺序遍历头像,如果发现同侧连续,则视为一组。
|
|
||||||
# 从当前组的第一个头像上方开始,直到下一个不同侧的头像上方(或底部)。
|
|
||||||
|
|
||||||
if avatars:
|
|
||||||
i = 0
|
|
||||||
while i < len(avatars):
|
|
||||||
current_group_start = i
|
|
||||||
current_side = avatars[i]['side']
|
|
||||||
|
|
||||||
# 找到当前组的结束位置 (即下一个不同侧头像的索引)
|
|
||||||
j = i + 1
|
|
||||||
while j < len(avatars) and avatars[j]['side'] == current_side:
|
|
||||||
j += 1
|
|
||||||
|
|
||||||
# 当前组范围: avatars[i] ... avatars[j-1]
|
|
||||||
# 确定绘制区域的 Y 轴范围
|
|
||||||
|
|
||||||
# Start Y: 当前组第一个头像的上方 (例如 -10px)
|
|
||||||
start_y = max(0, avatars[i]['y'] - 10)
|
|
||||||
|
|
||||||
# End Y: 下一组第一个头像的上方 (减去较大间距,例如 -30px),或者当前组最后一个头像的底部加上边距
|
|
||||||
# 为了让框之间有明显间隔,我们采取策略:
|
|
||||||
# 如果有下一组,End Y = 下一组第一个头像的 y - 30 (留出间隙)
|
|
||||||
# 如果没有下一组,End Y = 屏幕底部区域上方
|
|
||||||
|
|
||||||
if j < len(avatars):
|
|
||||||
end_y = max(start_y + 10, avatars[j]['y'] - 30)
|
|
||||||
else:
|
|
||||||
end_y = int(height * 0.9) # 到底部输入框上方
|
|
||||||
|
|
||||||
# 绘制大框
|
|
||||||
# 左侧 (Left) -> 对方 -> 绿色 (0, 255, 0)
|
|
||||||
# 右侧 (Right) -> 我 -> 红色 (0, 0, 255)
|
|
||||||
# 注意 OpenCV 颜色是 BGR
|
|
||||||
box_color = (0, 255, 0) if current_side == "Left" else (0, 0, 255)
|
|
||||||
|
|
||||||
# 绘制矩形 (空心,线宽 5)
|
|
||||||
# X 轴范围:0 到 width
|
|
||||||
cv2.rectangle(img, (0, start_y), (width, end_y), box_color, 5)
|
|
||||||
|
|
||||||
logger.info(f"绘制内容框: 侧别={current_side}, 范围 Y={start_y} to {end_y}")
|
|
||||||
|
|
||||||
# 移动到下一组
|
|
||||||
i = j
|
|
||||||
|
|
||||||
# 5. 绘制头像框 (Blue/Yellow Boxes) - 画在内容框之上
|
|
||||||
for av in avatars:
|
|
||||||
x, y, w, h = av['x'], av['y'], av['w'], av['h']
|
|
||||||
# 左侧:蓝色 (BGR: 255, 0, 0)
|
|
||||||
# 右侧:黄色 (BGR: 0, 255, 255)
|
|
||||||
color = (255, 0, 0) if av['side'] == "Left" else (0, 255, 255)
|
|
||||||
|
|
||||||
cv2.rectangle(img, (x, y), (x + w, y + h), color, 10)
|
|
||||||
logger.info(f"绘制头像: 位置=({x},{y}), 侧别={av['side']}")
|
|
||||||
|
|
||||||
logger.info(f"共标记了 {len(avatars)} 个头像")
|
|
||||||
|
|
||||||
# 6. 保存结果
|
|
||||||
try:
|
|
||||||
# cv2.imwrite 不支持中文路径,使用 imencode + tofile
|
|
||||||
ext = os.path.splitext(output_path)[1]
|
|
||||||
cv2.imencode(ext, img)[1].tofile(output_path)
|
|
||||||
logger.info(f"✅ 分析结果已保存至: {output_path}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"保存分析图片失败: {e}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
logger.info("开始执行微信搜索测试...")
|
|
||||||
|
|
||||||
# 连接设备
|
|
||||||
try:
|
|
||||||
d = u2.connect()
|
|
||||||
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"设备连接失败: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 1. 启动微信
|
|
||||||
logger.info("步骤 1: 启动微信...")
|
|
||||||
d.app_start("com.tencent.mm", stop=True)
|
|
||||||
# 等待微信启动完成
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
# 获取屏幕尺寸
|
|
||||||
w, h = d.window_size()
|
|
||||||
logger.info(f"屏幕尺寸: {w}x{h}")
|
|
||||||
|
|
||||||
# 2. 点击搜索按钮 (参考 Opener.py 的坐标比例: w * 0.84, h * 0.08)
|
|
||||||
search_x = int(w * 0.84)
|
|
||||||
search_y = int(h * 0.08)
|
|
||||||
logger.info(f"步骤 2: 点击搜索按钮 (坐标: {search_x}, {search_y})...")
|
|
||||||
d.click(search_x, search_y)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 3. 输入 "糖豆爸爸"
|
|
||||||
target_name = "糖豆爸爸"
|
|
||||||
logger.info(f"步骤 3: 输入搜索内容 '{target_name}'...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 启用 FastInputIME 以支持中文输入
|
|
||||||
d.set_input_ime(True)
|
|
||||||
|
|
||||||
# 点击搜索框获取焦点 (参考 Opener.py: w * 0.4, h * 0.08)
|
|
||||||
d.click(int(w * 0.4), int(h * 0.08))
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# 输入文字
|
|
||||||
d.send_keys(target_name)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 恢复输入法
|
|
||||||
d.set_input_ime(False)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"输入文字失败: {e}")
|
|
||||||
try:
|
|
||||||
d(focused=True).set_text(target_name)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 4. 点击搜索结果
|
|
||||||
logger.info("步骤 4: 查找并点击搜索结果...")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
found = False
|
|
||||||
|
|
||||||
# 策略 A: 精确匹配文本
|
|
||||||
if d(text=target_name).exists:
|
|
||||||
logger.info(f"找到文本为 '{target_name}' 的元素,点击...")
|
|
||||||
d(text=target_name).click()
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
logger.warning(f"未找到文本为 '{target_name}' 的元素,尝试模糊匹配或坐标点击...")
|
|
||||||
|
|
||||||
# 策略 B: 坐标点击 (参考 Opener.py 点击第一个结果: w * 0.5, h * 0.18)
|
|
||||||
result_x = int(w * 0.5)
|
|
||||||
result_y = int(h * 0.18)
|
|
||||||
logger.info(f"尝试点击第一个搜索结果位置 ({result_x}, {result_y})...")
|
|
||||||
d.click(result_x, result_y)
|
|
||||||
found = True
|
|
||||||
|
|
||||||
if found:
|
|
||||||
logger.info("✅ 已执行点击操作,应该已进入对话框。")
|
|
||||||
|
|
||||||
# 5. 截图保存结果
|
|
||||||
logger.info("步骤 5: 截图并分析...")
|
|
||||||
# 等待界面加载稳定
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
# 创建截图目录
|
|
||||||
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
|
||||||
if not os.path.exists(screenshot_dir):
|
|
||||||
os.makedirs(screenshot_dir)
|
|
||||||
|
|
||||||
# 生成文件名
|
|
||||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
|
||||||
filename = f"chat_result_{timestamp}.jpg"
|
|
||||||
save_path = os.path.join(screenshot_dir, filename)
|
|
||||||
|
|
||||||
try:
|
|
||||||
d.screenshot(save_path)
|
|
||||||
logger.info(f"✅ 原始截图已保存: {save_path}")
|
|
||||||
|
|
||||||
# 6. 分析截图并标记头像
|
|
||||||
logger.info("步骤 6: 自动标记头像...")
|
|
||||||
analyzed_filename = f"chat_result_{timestamp}_analyzed.jpg"
|
|
||||||
analyzed_path = os.path.join(screenshot_dir, analyzed_filename)
|
|
||||||
|
|
||||||
analyze_chat_image(save_path, analyzed_path)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ 截图或分析失败: {e}")
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.error("❌ 未能定位到搜索结果,跳过截图。")
|
|
||||||
|
|
||||||
logger.info("测试结束。")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
94
WeiXin/T1_OpenChat.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import uiautomator2 as u2
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 添加项目根目录到 sys.path
|
||||||
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
if project_root not in sys.path:
|
||||||
|
sys.path.append(project_root)
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs")
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler(os.path.join(log_dir, "T1_OpenChat.log"), encoding='utf-8'),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger = logging.getLogger("T1_OpenChat")
|
||||||
|
|
||||||
|
def open_chat(target_name="糖豆爸爸"):
|
||||||
|
logger.info(f"开始执行 T1: 打开微信并进入 '{target_name}' 的对话框...")
|
||||||
|
|
||||||
|
# 连接设备
|
||||||
|
try:
|
||||||
|
d = u2.connect()
|
||||||
|
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"设备连接失败: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 1. 启动微信
|
||||||
|
logger.info("步骤 1: 启动微信...")
|
||||||
|
d.app_start("com.tencent.mm", stop=True)
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# 获取屏幕尺寸
|
||||||
|
w, h = d.window_size()
|
||||||
|
logger.info(f"屏幕尺寸: {w}x{h}")
|
||||||
|
|
||||||
|
# 2. 点击搜索按钮
|
||||||
|
search_x = int(w * 0.84)
|
||||||
|
search_y = int(h * 0.08)
|
||||||
|
logger.info(f"步骤 2: 点击搜索按钮 (坐标: {search_x}, {search_y})...")
|
||||||
|
d.click(search_x, search_y)
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# 3. 输入搜索内容
|
||||||
|
logger.info(f"步骤 3: 输入搜索内容 '{target_name}'...")
|
||||||
|
try:
|
||||||
|
d.set_input_ime(True)
|
||||||
|
d.click(int(w * 0.4), int(h * 0.08))
|
||||||
|
time.sleep(1)
|
||||||
|
d.send_keys(target_name)
|
||||||
|
time.sleep(2)
|
||||||
|
d.set_input_ime(False)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"输入文字失败: {e}")
|
||||||
|
try:
|
||||||
|
d(focused=True).set_text(target_name)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 4. 点击搜索结果
|
||||||
|
logger.info("步骤 4: 查找并点击搜索结果...")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
found = False
|
||||||
|
if d(text=target_name).exists:
|
||||||
|
logger.info(f"找到文本为 '{target_name}' 的元素,点击...")
|
||||||
|
d(text=target_name).click()
|
||||||
|
found = True
|
||||||
|
else:
|
||||||
|
logger.warning(f"未找到文本为 '{target_name}' 的元素,尝试模糊匹配或坐标点击...")
|
||||||
|
result_x = int(w * 0.5)
|
||||||
|
result_y = int(h * 0.18)
|
||||||
|
logger.info(f"尝试点击第一个搜索结果位置 ({result_x}, {result_y})...")
|
||||||
|
d.click(result_x, result_y)
|
||||||
|
found = True
|
||||||
|
|
||||||
|
if found:
|
||||||
|
logger.info("✅ T1 执行完成: 已进入对话框。")
|
||||||
|
else:
|
||||||
|
logger.error("❌ T1 执行失败: 未能进入对话框。")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
open_chat()
|
||||||
69
WeiXin/T2_GetHistory.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import uiautomator2 as u2
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
if project_root not in sys.path:
|
||||||
|
sys.path.append(project_root)
|
||||||
|
|
||||||
|
from WeiXin.WxUtil import analyze_chat_image
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs")
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler(os.path.join(log_dir, "T2_GetHistory.log"), encoding='utf-8'),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger = logging.getLogger("T2_GetHistory")
|
||||||
|
|
||||||
|
def get_history(target_name="对方"):
|
||||||
|
logger.info("开始执行 T2: 获取当前屏幕对话历史...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
d = u2.connect()
|
||||||
|
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"设备连接失败: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 截图
|
||||||
|
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
||||||
|
if not os.path.exists(screenshot_dir):
|
||||||
|
os.makedirs(screenshot_dir)
|
||||||
|
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
filename = f"T2_history_{timestamp}.jpg"
|
||||||
|
save_path = os.path.join(screenshot_dir, filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
d.screenshot(save_path)
|
||||||
|
logger.info(f"截图已保存: {save_path}")
|
||||||
|
|
||||||
|
analyzed_filename = f"T2_history_{timestamp}_analyzed.jpg"
|
||||||
|
analyzed_path = os.path.join(screenshot_dir, analyzed_filename)
|
||||||
|
|
||||||
|
# 调用 WxUtil 中的分析函数
|
||||||
|
dialogue_log = analyze_chat_image(save_path, analyzed_path, target_name=target_name)
|
||||||
|
|
||||||
|
logger.info("✅ T2 执行完成。历史对话如下:")
|
||||||
|
if dialogue_log:
|
||||||
|
for log in dialogue_log:
|
||||||
|
print(log) # 打印到控制台
|
||||||
|
else:
|
||||||
|
logger.info("未提取到对话内容或当前屏幕无对话气泡。")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ T2 执行失败: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
get_history()
|
||||||
88
WeiXin/T3_MarkInputBox.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import uiautomator2 as u2
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
if project_root not in sys.path:
|
||||||
|
sys.path.append(project_root)
|
||||||
|
|
||||||
|
from WeiXin.WxUtil import find_input_box_center
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs")
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler(os.path.join(log_dir, "T3_MarkInputBox.log"), encoding='utf-8'),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger = logging.getLogger("T3_MarkInputBox")
|
||||||
|
|
||||||
|
def mark_input_box():
|
||||||
|
logger.info("开始执行 T3: 标识输入框位置...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
d = u2.connect()
|
||||||
|
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"设备连接失败: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
||||||
|
if not os.path.exists(screenshot_dir):
|
||||||
|
os.makedirs(screenshot_dir)
|
||||||
|
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
filename = f"T3_input_{timestamp}.jpg"
|
||||||
|
save_path = os.path.join(screenshot_dir, filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
d.screenshot(save_path)
|
||||||
|
logger.info(f"截图已保存: {save_path}")
|
||||||
|
|
||||||
|
# 调用 WxUtil 识别输入框
|
||||||
|
center_point, rect_box = find_input_box_center(save_path)
|
||||||
|
|
||||||
|
if center_point and rect_box:
|
||||||
|
# 读取图片进行绘制
|
||||||
|
img_data = np.fromfile(save_path, dtype=np.uint8)
|
||||||
|
img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
|
||||||
|
|
||||||
|
x, y, w, h = rect_box
|
||||||
|
cx, cy = center_point
|
||||||
|
|
||||||
|
# 要求:绿色框,模块点击点处标识小红点
|
||||||
|
# 绿色框 (Green): BGR (0, 255, 0)
|
||||||
|
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 5)
|
||||||
|
|
||||||
|
# 小红点 (Red): BGR (0, 0, 255)
|
||||||
|
# 半径 10, 实心
|
||||||
|
cv2.circle(img, (cx, cy), 10, (0, 0, 255), -1)
|
||||||
|
|
||||||
|
output_filename = f"T3_input_{timestamp}_marked.jpg"
|
||||||
|
output_path = os.path.join(screenshot_dir, output_filename)
|
||||||
|
|
||||||
|
# 保存
|
||||||
|
ext = os.path.splitext(output_path)[1]
|
||||||
|
cv2.imencode(ext, img)[1].tofile(output_path)
|
||||||
|
logger.info(f"✅ T3 执行完成: 标记图片已保存至 {output_path}")
|
||||||
|
logger.info(f"输入框区域: {rect_box}, 点击中心点: {center_point}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.warning("❌ T3 执行结果: 未能识别到输入框。")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ T3 执行失败: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
mark_input_box()
|
||||||
@@ -16,8 +16,9 @@ if project_root not in sys.path:
|
|||||||
from Util.EasyOcrKit import get_easyocr_reader
|
from Util.EasyOcrKit import get_easyocr_reader
|
||||||
|
|
||||||
# 配置日志
|
# 配置日志
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
# 注意:作为库模块,不应直接调用 basicConfig,以免干扰调用者的日志配置
|
||||||
logger = logging.getLogger("TestWeChat")
|
# 调用者应自行配置日志(包括 FileHandler 等)
|
||||||
|
logger = logging.getLogger("WxUtil")
|
||||||
|
|
||||||
def find_input_box_center(image_path):
|
def find_input_box_center(image_path):
|
||||||
"""
|
"""
|
||||||
@@ -48,8 +49,7 @@ def find_input_box_center(image_path):
|
|||||||
|
|
||||||
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
|
||||||
best_cnt = None
|
candidates = []
|
||||||
max_area = 0
|
|
||||||
|
|
||||||
for cnt in contours:
|
for cnt in contours:
|
||||||
x, y, w, h = cv2.boundingRect(cnt)
|
x, y, w, h = cv2.boundingRect(cnt)
|
||||||
@@ -61,15 +61,36 @@ def find_input_box_center(image_path):
|
|||||||
global_y = crop_y_start + y + h // 2
|
global_y = crop_y_start + y + h // 2
|
||||||
|
|
||||||
# 排除过于靠下的区域 (导航栏/手势条),通常在最后 2%
|
# 排除过于靠下的区域 (导航栏/手势条),通常在最后 2%
|
||||||
if global_y > height * 0.98:
|
if global_y > height * 0.99:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if w * h > max_area:
|
candidates.append({
|
||||||
max_area = w * h
|
'x': x, 'y': y, 'w': w, 'h': h,
|
||||||
best_cnt = (x, y, w, h)
|
'global_y': global_y,
|
||||||
|
'area': w * h
|
||||||
if best_cnt:
|
})
|
||||||
x, y, w, h = best_cnt
|
|
||||||
|
best_candidate = None
|
||||||
|
if candidates:
|
||||||
|
# 优先选择最靠下的候选框 (Y 坐标最大)
|
||||||
|
# 同时考虑宽度不能太离谱
|
||||||
|
candidates.sort(key=lambda c: c['global_y'], reverse=True)
|
||||||
|
|
||||||
|
# 检查最靠下的候选框是否合理
|
||||||
|
# 正常情况下输入框应该在屏幕底部 92% - 98% 之间
|
||||||
|
# 如果最靠下的候选框 Y < 92%,说明可能识别错了 (可能是倒数第二条消息)
|
||||||
|
for cand in candidates:
|
||||||
|
if cand['global_y'] > height * 0.92:
|
||||||
|
best_candidate = cand
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果没有找到足够靠下的,但有候选框,尝试放宽条件或者使用最靠下的那个
|
||||||
|
if not best_candidate and candidates:
|
||||||
|
logger.warning("未找到 >92% 高度的输入框,尝试使用最靠下的候选框")
|
||||||
|
best_candidate = candidates[0]
|
||||||
|
|
||||||
|
if best_candidate:
|
||||||
|
x, y, w, h = best_candidate['x'], best_candidate['y'], best_candidate['w'], best_candidate['h']
|
||||||
center_x = x + w // 2
|
center_x = x + w // 2
|
||||||
center_y = crop_y_start + y + h // 2
|
center_y = crop_y_start + y + h // 2
|
||||||
logger.info(f"找到输入框(CV-Canny): ({center_x}, {center_y}), 尺寸: {w}x{h}")
|
logger.info(f"找到输入框(CV-Canny): ({center_x}, {center_y}), 尺寸: {w}x{h}")
|
||||||
@@ -80,27 +101,33 @@ def find_input_box_center(image_path):
|
|||||||
cv2.THRESH_BINARY_INV, 11, 2)
|
cv2.THRESH_BINARY_INV, 11, 2)
|
||||||
contours_thresh, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
contours_thresh, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
|
||||||
|
candidates_thresh = []
|
||||||
for cnt in contours_thresh:
|
for cnt in contours_thresh:
|
||||||
x, y, w, h = cv2.boundingRect(cnt)
|
x, y, w, h = cv2.boundingRect(cnt)
|
||||||
if width * 0.4 < w < width * 0.95 and 20 < h < bottom_h * 0.8:
|
if width * 0.4 < w < width * 0.95 and 20 < h < bottom_h * 0.8:
|
||||||
global_y = crop_y_start + y + h // 2
|
global_y = crop_y_start + y + h // 2
|
||||||
if global_y > height * 0.98:
|
if global_y > height * 0.99:
|
||||||
continue
|
continue
|
||||||
if w * h > max_area:
|
candidates_thresh.append({
|
||||||
max_area = w * h
|
'x': x, 'y': y, 'w': w, 'h': h,
|
||||||
best_cnt = (x, y, w, h)
|
'global_y': global_y
|
||||||
|
})
|
||||||
if best_cnt:
|
|
||||||
x, y, w, h = best_cnt
|
if candidates_thresh:
|
||||||
center_x = x + w // 2
|
candidates_thresh.sort(key=lambda c: c['global_y'], reverse=True)
|
||||||
center_y = crop_y_start + y + h // 2
|
best = candidates_thresh[0]
|
||||||
logger.info(f"找到输入框(CV-Adaptive): ({center_x}, {center_y}), 尺寸: {w}x{h}")
|
# 同样应用 > 92% 规则
|
||||||
return (center_x, center_y), (x, crop_y_start + y, w, h)
|
if best['global_y'] > height * 0.92:
|
||||||
|
x, y, w, h = best['x'], best['y'], best['w'], best['h']
|
||||||
|
center_x = x + w // 2
|
||||||
|
center_y = crop_y_start + y + h // 2
|
||||||
|
logger.info(f"找到输入框(CV-Adaptive): ({center_x}, {center_y}), 尺寸: {w}x{h}")
|
||||||
|
return (center_x, center_y), (x, crop_y_start + y, w, h)
|
||||||
|
|
||||||
# 兜底策略:使用更靠下的默认坐标 (94%)
|
# 兜底策略:使用更靠下的默认坐标 (96% - 微信输入框通常很靠下)
|
||||||
# 之前的 90.5% 用户反馈偏上
|
# 之前的 94% 可能还是偏高
|
||||||
logger.warning("未找到明显输入框轮廓,使用更靠下的默认坐标 (94%)")
|
logger.warning("未找到明显输入框轮廓,使用更靠下的默认坐标 (96.5%)")
|
||||||
default_y = int(height * 0.94)
|
default_y = int(height * 0.965)
|
||||||
center_x = width // 2
|
center_x = width // 2
|
||||||
|
|
||||||
# 构造假想框
|
# 构造假想框
|
||||||
@@ -357,6 +384,13 @@ def perform_input_action(coords, text):
|
|||||||
d.send_keys(text)
|
d.send_keys(text)
|
||||||
except Exception as sk_e:
|
except Exception as sk_e:
|
||||||
logger.error(f"send_keys 失败: {sk_e}")
|
logger.error(f"send_keys 失败: {sk_e}")
|
||||||
|
|
||||||
|
# 尝试广播 input
|
||||||
|
try:
|
||||||
|
escaped_text = text.replace("'", "\\'").replace(" ", "%s")
|
||||||
|
d.shell(f"input text '{escaped_text}'")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# 3. 截图:输入文本后
|
# 3. 截图:输入文本后
|
||||||
take_debug_screenshot(d, "coord_03_after_input_text")
|
take_debug_screenshot(d, "coord_03_after_input_text")
|
||||||
@@ -596,130 +630,4 @@ def analyze_chat_image(image_path, output_path, target_name="对方"):
|
|||||||
logger.info(line)
|
logger.info(line)
|
||||||
logger.info("="*30 + "\n")
|
logger.info("="*30 + "\n")
|
||||||
|
|
||||||
def main():
|
return dialogue_log
|
||||||
logger.info("开始执行微信搜索测试...")
|
|
||||||
|
|
||||||
# 连接设备
|
|
||||||
try:
|
|
||||||
d = u2.connect()
|
|
||||||
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"设备连接失败: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 1. 启动微信
|
|
||||||
logger.info("步骤 1: 启动微信...")
|
|
||||||
d.app_start("com.tencent.mm", stop=True)
|
|
||||||
# 等待微信启动完成
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
# 获取屏幕尺寸
|
|
||||||
w, h = d.window_size()
|
|
||||||
logger.info(f"屏幕尺寸: {w}x{h}")
|
|
||||||
|
|
||||||
# 2. 点击搜索按钮 (参考 Opener.py 的坐标比例: w * 0.84, h * 0.08)
|
|
||||||
search_x = int(w * 0.84)
|
|
||||||
search_y = int(h * 0.08)
|
|
||||||
logger.info(f"步骤 2: 点击搜索按钮 (坐标: {search_x}, {search_y})...")
|
|
||||||
d.click(search_x, search_y)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 3. 输入 "糖豆爸爸"
|
|
||||||
target_name = "糖豆爸爸"
|
|
||||||
logger.info(f"步骤 3: 输入搜索内容 '{target_name}'...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 启用 FastInputIME 以支持中文输入
|
|
||||||
d.set_input_ime(True)
|
|
||||||
|
|
||||||
# 点击搜索框获取焦点 (参考 Opener.py: w * 0.4, h * 0.08)
|
|
||||||
d.click(int(w * 0.4), int(h * 0.08))
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# 输入文字
|
|
||||||
d.send_keys(target_name)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 恢复输入法
|
|
||||||
d.set_input_ime(False)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"输入文字失败: {e}")
|
|
||||||
try:
|
|
||||||
d(focused=True).set_text(target_name)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 4. 点击搜索结果
|
|
||||||
logger.info("步骤 4: 查找并点击搜索结果...")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
found = False
|
|
||||||
|
|
||||||
# 策略 A: 精确匹配文本
|
|
||||||
if d(text=target_name).exists:
|
|
||||||
logger.info(f"找到文本为 '{target_name}' 的元素,点击...")
|
|
||||||
d(text=target_name).click()
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
logger.warning(f"未找到文本为 '{target_name}' 的元素,尝试模糊匹配或坐标点击...")
|
|
||||||
|
|
||||||
# 策略 B: 坐标点击 (参考 Opener.py 点击第一个结果: w * 0.5, h * 0.18)
|
|
||||||
result_x = int(w * 0.5)
|
|
||||||
result_y = int(h * 0.18)
|
|
||||||
logger.info(f"尝试点击第一个搜索结果位置 ({result_x}, {result_y})...")
|
|
||||||
d.click(result_x, result_y)
|
|
||||||
found = True
|
|
||||||
|
|
||||||
if found:
|
|
||||||
logger.info("✅ 已执行点击操作,应该已进入对话框。")
|
|
||||||
|
|
||||||
# 5. 截图保存结果
|
|
||||||
logger.info("步骤 5: 截图并分析...")
|
|
||||||
# 等待界面加载稳定
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
# 创建截图目录
|
|
||||||
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
|
||||||
if not os.path.exists(screenshot_dir):
|
|
||||||
os.makedirs(screenshot_dir)
|
|
||||||
|
|
||||||
# 生成文件名
|
|
||||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
|
||||||
filename = f"chat_result_{timestamp}.jpg"
|
|
||||||
save_path = os.path.join(screenshot_dir, filename)
|
|
||||||
|
|
||||||
try:
|
|
||||||
d.screenshot(save_path)
|
|
||||||
logger.info(f"✅ 原始截图已保存: {save_path}")
|
|
||||||
|
|
||||||
# 6. 分析截图并标记头像
|
|
||||||
logger.info("步骤 6: 自动标记头像和识别内容...")
|
|
||||||
analyzed_filename = f"chat_result_{timestamp}_analyzed.jpg"
|
|
||||||
analyzed_path = os.path.join(screenshot_dir, analyzed_filename)
|
|
||||||
|
|
||||||
analyze_chat_image(save_path, analyzed_path, target_name=target_name)
|
|
||||||
|
|
||||||
# 7. 查找输入框并执行自动化操作
|
|
||||||
logger.info("步骤 7: 自动回复...")
|
|
||||||
# 注意:analyze_chat_image 内部已经调用了 find_input_box_center 并且画在图上了
|
|
||||||
# 但我们需要返回值来执行操作。analyze_chat_image 并没有返回坐标。
|
|
||||||
# 为了简单,再次调用一次 (或者修改 analyze_chat_image 返回坐标,但改动较大)
|
|
||||||
# 这里直接再次调用 find_input_box_center 获取坐标
|
|
||||||
coords, _ = find_input_box_center(save_path)
|
|
||||||
|
|
||||||
if coords:
|
|
||||||
logger.info(f"输入框坐标: {coords}")
|
|
||||||
perform_input_action(coords, "AI助手我现在可以开始和你聊天了!")
|
|
||||||
else:
|
|
||||||
logger.warning("未找到输入框坐标,跳过回复")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ 截图或分析失败: {e}")
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.error("❌ 未能定位到搜索结果,跳过截图。")
|
|
||||||
|
|
||||||
logger.info("测试结束。")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
116
WordAddIn/WordAddIn/CreateOutlineForm.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace WordAddIn
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建大纲输入窗体。
|
||||||
|
/// 功能描述:
|
||||||
|
/// 1. 提供一个文本框,让用户输入大纲的主题、关键词或详细描述。
|
||||||
|
/// 2. 作为生成大纲的前置步骤,获取用户的初始意图。
|
||||||
|
/// </summary>
|
||||||
|
public class CreateOutlineForm : Form
|
||||||
|
{
|
||||||
|
private TextBox txtTopic;
|
||||||
|
private Button btnGenerate;
|
||||||
|
private Button btnCancel;
|
||||||
|
private Label lblTopic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取用户输入的主题内容。
|
||||||
|
/// </summary>
|
||||||
|
public string Topic { get; private set; }
|
||||||
|
|
||||||
|
public CreateOutlineForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化窗体组件。
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.lblTopic = new System.Windows.Forms.Label();
|
||||||
|
this.txtTopic = new System.Windows.Forms.TextBox();
|
||||||
|
this.btnGenerate = new System.Windows.Forms.Button();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// lblTopic
|
||||||
|
//
|
||||||
|
this.lblTopic.AutoSize = true;
|
||||||
|
this.lblTopic.Location = new System.Drawing.Point(20, 20);
|
||||||
|
this.lblTopic.Name = "lblTopic";
|
||||||
|
this.lblTopic.Size = new System.Drawing.Size(191, 12);
|
||||||
|
this.lblTopic.TabIndex = 0;
|
||||||
|
this.lblTopic.Text = "请输入文档主题或描述 (支持多行):";
|
||||||
|
//
|
||||||
|
// txtTopic
|
||||||
|
//
|
||||||
|
this.txtTopic.Location = new System.Drawing.Point(20, 50);
|
||||||
|
this.txtTopic.Multiline = true;
|
||||||
|
this.txtTopic.Name = "txtTopic";
|
||||||
|
this.txtTopic.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtTopic.Size = new System.Drawing.Size(440, 240);
|
||||||
|
this.txtTopic.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// btnGenerate
|
||||||
|
//
|
||||||
|
this.btnGenerate.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||||
|
this.btnGenerate.Location = new System.Drawing.Point(240, 310);
|
||||||
|
this.btnGenerate.Name = "btnGenerate";
|
||||||
|
this.btnGenerate.Size = new System.Drawing.Size(100, 35);
|
||||||
|
this.btnGenerate.TabIndex = 2;
|
||||||
|
this.btnGenerate.Text = "生成大纲";
|
||||||
|
this.btnGenerate.UseVisualStyleBackColor = true;
|
||||||
|
this.btnGenerate.Click += new System.EventHandler(this.BtnGenerate_Click);
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(360, 310);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(100, 35);
|
||||||
|
this.btnCancel.TabIndex = 3;
|
||||||
|
this.btnCancel.Text = "取消";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// CreateOutlineForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.CancelButton = this.btnCancel;
|
||||||
|
this.ClientSize = new System.Drawing.Size(500, 370);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.Controls.Add(this.btnGenerate);
|
||||||
|
this.Controls.Add(this.txtTopic);
|
||||||
|
this.Controls.Add(this.lblTopic);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "CreateOutlineForm";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
this.Text = "创建大纲 - AI助手";
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成按钮点击事件。
|
||||||
|
/// 验证输入是否为空,若通过则设置 Topic 属性并关闭窗体。
|
||||||
|
/// </summary>
|
||||||
|
private void BtnGenerate_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Topic = txtTopic.Text.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(Topic))
|
||||||
|
{
|
||||||
|
MessageBox.Show("请输入主题或描述内容。");
|
||||||
|
this.DialogResult = DialogResult.None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
177
WordAddIn/WordAddIn/OutlineSettingsForm.cs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WordAddIn.Models;
|
||||||
|
using WordAddIn.Properties;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace WordAddIn
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 大纲样式配置窗体。
|
||||||
|
/// 功能描述:
|
||||||
|
/// 1. 允许用户为大纲的不同层级(主标题、一级目录、二级目录、三级目录)配置样式。
|
||||||
|
/// 2. 使用 TabControl 组织不同层级的样式编辑器(StyleEditorControl)。
|
||||||
|
/// 3. 支持保存配置到本地设置(Settings.Default.OutlineStyles)和加载已有配置。
|
||||||
|
/// </summary>
|
||||||
|
public class OutlineSettingsForm : Form
|
||||||
|
{
|
||||||
|
private TabControl tabControl;
|
||||||
|
private Button btnSave;
|
||||||
|
private Button btnCancel;
|
||||||
|
|
||||||
|
private StyleEditorControl mainTitleEditor;
|
||||||
|
private StyleEditorControl h1Editor;
|
||||||
|
private StyleEditorControl h2Editor;
|
||||||
|
private StyleEditorControl h3Editor;
|
||||||
|
|
||||||
|
public OutlineSettingsForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
InitializeCustomControls();
|
||||||
|
LoadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化基本窗体组件。
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.tabControl = new System.Windows.Forms.TabControl();
|
||||||
|
this.btnSave = new System.Windows.Forms.Button();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// tabControl
|
||||||
|
//
|
||||||
|
this.tabControl.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.tabControl.Name = "tabControl";
|
||||||
|
this.tabControl.SelectedIndex = 0;
|
||||||
|
this.tabControl.Size = new System.Drawing.Size(410, 280);
|
||||||
|
this.tabControl.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// btnSave
|
||||||
|
//
|
||||||
|
this.btnSave.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||||
|
this.btnSave.Location = new System.Drawing.Point(210, 310);
|
||||||
|
this.btnSave.Name = "btnSave";
|
||||||
|
this.btnSave.Size = new System.Drawing.Size(100, 35);
|
||||||
|
this.btnSave.TabIndex = 1;
|
||||||
|
this.btnSave.Text = "保存配置";
|
||||||
|
this.btnSave.UseVisualStyleBackColor = true;
|
||||||
|
this.btnSave.Click += new System.EventHandler(this.BtnSave_Click);
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(320, 310);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(100, 35);
|
||||||
|
this.btnCancel.TabIndex = 2;
|
||||||
|
this.btnCancel.Text = "取消";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// OutlineSettingsForm
|
||||||
|
//
|
||||||
|
this.AcceptButton = this.btnSave;
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.CancelButton = this.btnCancel;
|
||||||
|
this.ClientSize = new System.Drawing.Size(450, 360);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.Controls.Add(this.btnSave);
|
||||||
|
this.Controls.Add(this.tabControl);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "OutlineSettingsForm";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
this.Text = "大纲样式配置";
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化自定义样式编辑器控件,并添加到 Tab 页中。
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeCustomControls()
|
||||||
|
{
|
||||||
|
mainTitleEditor = new StyleEditorControl("主标题", true);
|
||||||
|
h1Editor = new StyleEditorControl("一级目录", false);
|
||||||
|
h2Editor = new StyleEditorControl("二级目录", false);
|
||||||
|
h3Editor = new StyleEditorControl("三级目录", false);
|
||||||
|
|
||||||
|
AddTab("主标题", mainTitleEditor);
|
||||||
|
AddTab("一级目录", h1Editor);
|
||||||
|
AddTab("二级目录", h2Editor);
|
||||||
|
AddTab("三级目录", h3Editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 辅助方法:添加一个新的 Tab 页。
|
||||||
|
/// </summary>
|
||||||
|
private void AddTab(string title, Control content)
|
||||||
|
{
|
||||||
|
TabPage page = new TabPage(title);
|
||||||
|
content.Dock = DockStyle.Fill;
|
||||||
|
page.Controls.Add(content);
|
||||||
|
tabControl.TabPages.Add(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从 Settings 中加载保存的样式配置。
|
||||||
|
/// </summary>
|
||||||
|
private void LoadSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string json = Settings.Default.OutlineStyles;
|
||||||
|
OutlineStyleConfig config = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(json))
|
||||||
|
{
|
||||||
|
config = JsonConvert.DeserializeObject<OutlineStyleConfig>(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == null)
|
||||||
|
{
|
||||||
|
config = new OutlineStyleConfig(); // Use defaults
|
||||||
|
}
|
||||||
|
|
||||||
|
mainTitleEditor.SetStyle(config.MainTitle);
|
||||||
|
h1Editor.SetStyle(config.Heading1);
|
||||||
|
h2Editor.SetStyle(config.Heading2);
|
||||||
|
h3Editor.SetStyle(config.Heading3);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("加载配置失败: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存按钮点击事件。
|
||||||
|
/// 将当前配置序列化为 JSON 并保存到 Settings。
|
||||||
|
/// </summary>
|
||||||
|
private void BtnSave_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OutlineStyleConfig config = new OutlineStyleConfig();
|
||||||
|
config.MainTitle = mainTitleEditor.GetStyle();
|
||||||
|
config.Heading1 = h1Editor.GetStyle();
|
||||||
|
config.Heading2 = h2Editor.GetStyle();
|
||||||
|
config.Heading3 = h3Editor.GetStyle();
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(config);
|
||||||
|
Settings.Default.OutlineStyles = json;
|
||||||
|
Settings.Default.Save();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("保存配置失败: " + ex.Message);
|
||||||
|
this.DialogResult = DialogResult.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
WordAddIn/WordAddIn/StyleEditorControl.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WordAddIn.Models;
|
||||||
|
|
||||||
|
namespace WordAddIn
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 样式编辑器控件。
|
||||||
|
/// 功能描述:
|
||||||
|
/// 1. 提供可复用的用户界面,用于配置文本样式(字体、字号、加粗、对齐方式)。
|
||||||
|
/// 2. 封装了 WinForms 控件(ComboBox, NumericUpDown, CheckBox),简化样式设置。
|
||||||
|
/// 3. 支持数据绑定:SetStyle() 设置界面状态,GetStyle() 获取用户配置。
|
||||||
|
/// </summary>
|
||||||
|
public class StyleEditorControl : UserControl
|
||||||
|
{
|
||||||
|
private ComboBox cmbFont;
|
||||||
|
private NumericUpDown numSize;
|
||||||
|
private CheckBox chkBold;
|
||||||
|
private ComboBox cmbAlign;
|
||||||
|
private bool _showAlign;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认构造函数 (设计器支持)。
|
||||||
|
/// </summary>
|
||||||
|
public StyleEditorControl()
|
||||||
|
{
|
||||||
|
// Default constructor for designer support
|
||||||
|
_showAlign = false;
|
||||||
|
Initialize("样式");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 带参数的构造函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="labelText">分组标题文本 (如 "一级目录")</param>
|
||||||
|
/// <param name="showAlign">是否显示对齐方式选项</param>
|
||||||
|
public StyleEditorControl(string labelText, bool showAlign)
|
||||||
|
{
|
||||||
|
_showAlign = showAlign;
|
||||||
|
Initialize(labelText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化控件界面。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="labelText">分组标题</param>
|
||||||
|
private void Initialize(string labelText)
|
||||||
|
{
|
||||||
|
this.Padding = new Padding(20);
|
||||||
|
this.Size = new Size(380, 200); // Set a default size
|
||||||
|
|
||||||
|
// 字体选择
|
||||||
|
Label lblFont = new Label { Text = "字体:", Location = new Point(20, 30), AutoSize = true };
|
||||||
|
cmbFont = new ComboBox { Location = new Point(80, 27), Width = 150, DropDownStyle = ComboBoxStyle.DropDownList };
|
||||||
|
// Add common Chinese fonts
|
||||||
|
cmbFont.Items.AddRange(new object[] { "宋体", "黑体", "微软雅黑", "楷体", "仿宋", "Arial", "Times New Roman" });
|
||||||
|
cmbFont.SelectedIndex = 0;
|
||||||
|
|
||||||
|
// 字号选择
|
||||||
|
Label lblSize = new Label { Text = "字号:", Location = new Point(20, 70), AutoSize = true };
|
||||||
|
numSize = new NumericUpDown { Location = new Point(80, 67), Width = 80, Minimum = 5, Maximum = 72, DecimalPlaces = 1 };
|
||||||
|
|
||||||
|
// 加粗选项
|
||||||
|
chkBold = new CheckBox { Text = "加粗", Location = new Point(80, 110), AutoSize = true };
|
||||||
|
|
||||||
|
this.Controls.Add(lblFont);
|
||||||
|
this.Controls.Add(cmbFont);
|
||||||
|
this.Controls.Add(lblSize);
|
||||||
|
this.Controls.Add(numSize);
|
||||||
|
this.Controls.Add(chkBold);
|
||||||
|
|
||||||
|
// 对齐方式 (可选)
|
||||||
|
if (_showAlign)
|
||||||
|
{
|
||||||
|
Label lblAlign = new Label { Text = "对齐:", Location = new Point(20, 150), AutoSize = true };
|
||||||
|
cmbAlign = new ComboBox { Location = new Point(80, 147), Width = 100, DropDownStyle = ComboBoxStyle.DropDownList };
|
||||||
|
cmbAlign.Items.AddRange(new object[] { "左对齐", "居中", "右对齐" });
|
||||||
|
cmbAlign.SelectedIndex = 0;
|
||||||
|
|
||||||
|
this.Controls.Add(lblAlign);
|
||||||
|
this.Controls.Add(cmbAlign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 TextStyle 对象应用到界面控件。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="style">要显示的样式对象</param>
|
||||||
|
public void SetStyle(TextStyle style)
|
||||||
|
{
|
||||||
|
if (style == null) return;
|
||||||
|
|
||||||
|
if (cmbFont.Items.Contains(style.FontName))
|
||||||
|
cmbFont.SelectedItem = style.FontName;
|
||||||
|
else
|
||||||
|
cmbFont.Text = style.FontName; // Fallback
|
||||||
|
|
||||||
|
numSize.Value = (decimal)style.FontSize;
|
||||||
|
chkBold.Checked = style.IsBold;
|
||||||
|
|
||||||
|
if (_showAlign && cmbAlign != null)
|
||||||
|
{
|
||||||
|
if (style.Alignment >= 0 && style.Alignment < cmbAlign.Items.Count)
|
||||||
|
cmbAlign.SelectedIndex = style.Alignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从界面控件获取当前的 TextStyle 配置。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>包含用户配置的样式对象</returns>
|
||||||
|
public TextStyle GetStyle()
|
||||||
|
{
|
||||||
|
TextStyle style = new TextStyle();
|
||||||
|
style.FontName = cmbFont.Text;
|
||||||
|
style.FontSize = (float)numSize.Value;
|
||||||
|
style.IsBold = chkBold.Checked;
|
||||||
|
if (_showAlign && cmbAlign != null)
|
||||||
|
{
|
||||||
|
style.Alignment = cmbAlign.SelectedIndex;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
WordAddIn/WordAddIn/WordAddIn.csproj.user
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<PublishUrlHistory />
|
||||||
|
<InstallUrlHistory />
|
||||||
|
<SupportUrlHistory />
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<asmv1:assemblyIdentity name="WordAddIn.dll" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<description xmlns="urn:schemas-microsoft-com:asm.v1">WordAddIn</description>
|
||||||
|
<application />
|
||||||
|
<entryPoint>
|
||||||
|
<co.v1:customHostSpecified />
|
||||||
|
</entryPoint>
|
||||||
|
<trustInfo>
|
||||||
|
<security>
|
||||||
|
<applicationRequestMinimum>
|
||||||
|
<PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />
|
||||||
|
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||||
|
</applicationRequestMinimum>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!--
|
||||||
|
UAC 清单选项
|
||||||
|
如果要更改 Windows 用户帐户控制级别,请用以下节点之一替换
|
||||||
|
requestedExecutionLevel 节点。
|
||||||
|
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
|
||||||
|
如果要利用文件和注册表虚拟化提供
|
||||||
|
向后兼容性,请删除 requestedExecutionLevel 节点。
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentOS>
|
||||||
|
<osVersionInfo>
|
||||||
|
<os majorVersion="5" minorVersion="1" buildNumber="2600" servicePackMajor="0" />
|
||||||
|
</osVersionInfo>
|
||||||
|
</dependentOS>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="4.0.30319.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Accessibility" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.CSharp" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Office.Tools" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Office.Tools.Common" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Office.Tools.v4.0.Framework" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Office.Tools.Word" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.VisualStudio.Tools.Applications.Runtime" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="mscorlib" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="stdole" version="7.0.3300.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Core" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Data" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Data.DataSetExtensions" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Drawing" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Net.Http" version="4.2.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Numerics" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Runtime.Serialization" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Windows.Forms" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Xml" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="System.Xml.Linq" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Office.Tools.Common.v4.0.Utilities.dll" size="32664">
|
||||||
|
<assemblyIdentity name="Microsoft.Office.Tools.Common.v4.0.Utilities" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>jLCTF8Mm6bD4PDN+rnzN6q0+ReXaNgPh68kMWgatFwI=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Newtonsoft.Json.dll" size="721320">
|
||||||
|
<assemblyIdentity name="Newtonsoft.Json" version="13.0.0.0" publicKeyToken="30AD4FE6B2A6AEED" language="neutral" processorArchitecture="msil" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>8MB68OhNTdTaS9eCO6RTW8BIGzv2I+1Atlm2gUemu3U=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="WordAddIn.dll" size="92672">
|
||||||
|
<assemblyIdentity name="WordAddIn" version="1.0.0.0" language="neutral" processorArchitecture="msil" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>y4xivocoIp8Py1pQadRda9HJK1lJPDi2e/MIWHzz8V4=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<vstav3:addIn xmlns:vstav3="urn:schemas-microsoft-com:vsta.v3">
|
||||||
|
<vstav3:entryPointsCollection>
|
||||||
|
<vstav3:entryPoints>
|
||||||
|
<vstav3:entryPoint class="WordAddIn.ThisAddIn">
|
||||||
|
<assemblyIdentity name="WordAddIn" version="1.0.0.0" language="neutral" processorArchitecture="msil" />
|
||||||
|
</vstav3:entryPoint>
|
||||||
|
</vstav3:entryPoints>
|
||||||
|
</vstav3:entryPointsCollection>
|
||||||
|
<vstav3:update enabled="true">
|
||||||
|
<vstav3:expiration maximumAge="7" unit="days" />
|
||||||
|
</vstav3:update>
|
||||||
|
<vstav3:application>
|
||||||
|
<vstov4:customizations xmlns:vstov4="urn:schemas-microsoft-com:vsto.v4">
|
||||||
|
<vstov4:customization>
|
||||||
|
<vstov4:appAddIn application="Word" loadBehavior="3" keyName="WordAddIn">
|
||||||
|
<vstov4:friendlyName>WordAddIn</vstov4:friendlyName>
|
||||||
|
<vstov4:description>WordAddIn</vstov4:description>
|
||||||
|
<vstov4.1:ribbonTypes xmlns:vstov4.1="urn:schemas-microsoft-com:vsto.v4.1" />
|
||||||
|
</vstov4:appAddIn>
|
||||||
|
</vstov4:customization>
|
||||||
|
</vstov4:customizations>
|
||||||
|
</vstav3:application>
|
||||||
|
</vstav3:addIn>
|
||||||
|
<publisherIdentity name="CN=DESKTOP-Q6H7B6L\Administrator" issuerKeyHash="42606c52715d5764c2f9dab5bee6dcd76cc7a67d" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>nzFmuqGMTufidijFdHzd5EGSf5WOKf7c2AjATAY/QXQ=</DigestValue></Reference></SignedInfo><SignatureValue>kec11gHTkSnlIv0W9zVym1S7bKdmUlth8lply4yAThpZy4vYVECTxPs+WnqUb2jfF2GZ0S5HnDirRBDuabJWZ6hzWxH0qZhiwVS4gqQz64IHo6xn+WZ7Jewbq6HRgUNl+JYFoe4MfmT9BsyOaSjjqcSttZHJocW2TMZvSC2CDuY=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="74413f064cc008d8dcfe298e957f9241e4dd7c74c52876e2e74e8ca1ba66319f" Description="" Url=""><as:assemblyIdentity name="WordAddIn.dll" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" type="win32" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=DESKTOP-Q6H7B6L\Administrator</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>lkht93KCRD6xvp4ITwaBZBfKJqkHiRlwzLkUqlOxs2o=</DigestValue></Reference></SignedInfo><SignatureValue>B+FiLgSCXupEf1Nhejue8+299l1qYdgURdD7C2LLB2VbzFLLk9sR8wmGoQhBa3fIFUBAtCJxIMlYOlebZChMrXiiSiol05gBWxrMYk3wprnNUMUOQrJQ+SvHyOWYXiuFgWJMLW3z/VzeNZmelF2HMuyUPOqz3Sd3rnphDvmiu9k=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<assemblyIdentity name="WordAddIn.vsto" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<description asmv2:publisher="WordAddIn" asmv2:product="WordAddIn" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<deployment install="false" mapFileExtensions="true" />
|
||||||
|
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<framework targetVersion="4.7.2" profile="Full" supportedRuntime="4.0.30319" />
|
||||||
|
</compatibleFrameworks>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" codebase="Application Files\WordAddIn_1_0_0_0\WordAddIn.dll.manifest" size="14626">
|
||||||
|
<assemblyIdentity name="WordAddIn.dll" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>l0YIXWniJAOVvXIuq2gcsxgh6HiLzzq3Qbzl/vvdGcU=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<publisherIdentity name="CN=DESKTOP-Q6H7B6L\Administrator" issuerKeyHash="42606c52715d5764c2f9dab5bee6dcd76cc7a67d" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>XIAhjSP9NMvto3hNCon8XWja0spk/WAz/YRgsaC9NAo=</DigestValue></Reference></SignedInfo><SignatureValue>ZEub2vJdHkXv+rnwN2Rfq6vBnN+mUYuOr4/X76AcTre2N9HNv36HIeuufOaCwSIm9I37R09oAa0YKgWsr0K/CCgSF7wqaVqBe6fJcvepI/Gtaolrmta1FwKCh1C53YDt7PNakBpydLsreZW0P0aBY68U2MJAfTNWUs2NmeqXVG4=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="0a34bda0b16084fd3360fd64cad2da685dfc890a4d78a3edcb34fd238d21805c" Description="" Url=""><as:assemblyIdentity name="WordAddIn.vsto" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=DESKTOP-Q6H7B6L\Administrator</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>cV57IfAuq85wNkKjrzi3jhRZNc7Cf6ZvKM70ci4T5wQ=</DigestValue></Reference></SignedInfo><SignatureValue>AzHMNpKdtaXkn+WGDS5auR1B95LwvsxcHO+9+9oxPZqVD9RSQ+E/LmN9xteIZF2ugOZn2LwMDUW7Kc2fOkvwoKycCxJE9avHhK284WaQR+94tOjrlBpm7Tiw8GsWz2Ts/sqhI4n5v07hPY9nGJVcJgGLJEBKrMMdGTFJwbOE7Ps=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
||||||
21
WordAddIn/WordAddIn/publish/WordAddIn.vsto
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<assemblyIdentity name="WordAddIn.vsto" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<description asmv2:publisher="WordAddIn" asmv2:product="WordAddIn" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<deployment install="false" mapFileExtensions="true" />
|
||||||
|
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<framework targetVersion="4.7.2" profile="Full" supportedRuntime="4.0.30319" />
|
||||||
|
</compatibleFrameworks>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" codebase="Application Files\WordAddIn_1_0_0_0\WordAddIn.dll.manifest" size="14626">
|
||||||
|
<assemblyIdentity name="WordAddIn.dll" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>l0YIXWniJAOVvXIuq2gcsxgh6HiLzzq3Qbzl/vvdGcU=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<publisherIdentity name="CN=DESKTOP-Q6H7B6L\Administrator" issuerKeyHash="42606c52715d5764c2f9dab5bee6dcd76cc7a67d" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>XIAhjSP9NMvto3hNCon8XWja0spk/WAz/YRgsaC9NAo=</DigestValue></Reference></SignedInfo><SignatureValue>ZEub2vJdHkXv+rnwN2Rfq6vBnN+mUYuOr4/X76AcTre2N9HNv36HIeuufOaCwSIm9I37R09oAa0YKgWsr0K/CCgSF7wqaVqBe6fJcvepI/Gtaolrmta1FwKCh1C53YDt7PNakBpydLsreZW0P0aBY68U2MJAfTNWUs2NmeqXVG4=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="0a34bda0b16084fd3360fd64cad2da685dfc890a4d78a3edcb34fd238d21805c" Description="" Url=""><as:assemblyIdentity name="WordAddIn.vsto" version="1.0.0.0" publicKeyToken="06a92c46db516926" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=DESKTOP-Q6H7B6L\Administrator</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>cV57IfAuq85wNkKjrzi3jhRZNc7Cf6ZvKM70ci4T5wQ=</DigestValue></Reference></SignedInfo><SignatureValue>AzHMNpKdtaXkn+WGDS5auR1B95LwvsxcHO+9+9oxPZqVD9RSQ+E/LmN9xteIZF2ugOZn2LwMDUW7Kc2fOkvwoKycCxJE9avHhK284WaQR+94tOjrlBpm7Tiw8GsWz2Ts/sqhI4n5v07hPY9nGJVcJgGLJEBKrMMdGTFJwbOE7Ps=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
||||||