Peterfei

上主是我的牧者,我实在一无所缺


  • 首页

  • 归档

  • 标签

使用WPF加载Unity可执行程序

发表于 2019-04-09   |   分类于 WPF   |  

公司有开发wpf需求,模型主要是由Unity开发,导出后是.exe可执行程序,
外层是利用react-native编写界面,主要组件为react-native-windows,于是需要融合二者.
首先是写入wpf调用外部exe组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace Vesal_PC
{
// GameHost is a FrameworkElement and can be added to controls like so:
// var gameHost = new GameHost(container.ActualWidth, container.ActualHeight);
// container.Child = gameHost;
//
// Sources:
// - https://msdn.microsoft.com/en-us/library/ms752055.aspx
// - Another source I can't remember or find, concerning running a standalone Unity process using parentHWND parameter
internal class GameHost : HwndHost
{
private const int WS_CHILD = 0x40000000;
private const int WS_VISIBLE = 0x10000000;
private const int HOST_ID = 0x00000002;
private IntPtr hwndHost;
private int hostHeight, hostWidth;
private Process process;
private IntPtr unityHWND = IntPtr.Zero;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
public GameHost(double width, double height)
{
hostHeight = (int)height;
hostWidth = (int)width;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
hwndHost = IntPtr.Zero;
hwndHost = CreateWindowEx(0, "static", "",
WS_CHILD | WS_VISIBLE,
0, 0,
hostWidth, hostHeight,
hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero,
0);
{
try
{
process = new Process();
process.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "win/vesal.exe";
process.StartInfo.Arguments = "-parentHWND " + hwndHost.ToInt32() + " " + Environment.CommandLine;
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForInputIdle();
// Doesn't work for some reason ?!
//unityHWND = process.MainWindowHandle;
EnumChildWindows(hwndHost, WindowEnum, IntPtr.Zero);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "GameHost: Could not find game executable.");
}
}
return new HandleRef(this, hwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
try
{
process.CloseMainWindow();
System.Threading.Thread.Sleep(1000);
while (process.HasExited == false)
process.Kill();
}
catch (Exception)
{
}
DestroyWindow(hwnd.Handle);
}
private void ActivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
return IntPtr.Zero;
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}
}

编写react-native UnityView组件:

ReactUnityManager.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) Microsoft Corporation. All rights reserved.
// Portions derived from React Native:
// Copyright (c) 2015-present, Facebook, Inc.
// Licensed under the MIT License.
using Newtonsoft.Json.Linq;
using ReactNative.Collections;
using ReactNative.Modules.Image;
using ReactNative.UIManager;
using ReactNative.UIManager.Annotations;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Controls;
namespace Vesal_PC
{
/// <summary>
/// The view manager responsible for rendering native images.
/// </summary>
public class ReactUnityManager : SimpleViewManager<Border>
{
private readonly ConcurrentDictionary<Border, List<KeyValuePair<string, double>>> _imageSources =
new ConcurrentDictionary<Border, List<KeyValuePair<string, double>>>();
Border view;
/// <summary>
/// The view manager name.
/// </summary>
public override string Name
{
get
{
return "RCTUnityView";
}
}
/// <summary>
/// The view manager event constants.
/// </summary>
public override JObject CustomDirectEventTypeConstants
{
get
{
return new JObject
{
{
"topLoadStart",
new JObject
{
{ "registrationName", "onLoadStart" }
}
},
{
"topLoad",
new JObject
{
{ "registrationName", "onLoad" }
}
},
{
"topLoadEnd",
new JObject
{
{ "registrationName", "onLoadEnd" }
}
},
{
"topError",
new JObject
{
{ "registrationName", "onError" }
}
},
};
}
}
/// <summary>
/// Called when view is detached from view hierarchy and allows for
/// additional cleanup.
/// </summary>
/// <param name="reactContext">The React context.</param>
/// <param name="view">The view.</param>
public override void OnDropViewInstance(ThemedReactContext reactContext, Border view)
{
base.OnDropViewInstance(reactContext, view);
_imageSources.TryRemove(view, out _);
}
[ReactPropGroup(
ViewProps.BorderWidth,
ViewProps.BorderLeftWidth,
ViewProps.BorderRightWidth,
ViewProps.BorderTopWidth,
ViewProps.BorderBottomWidth,
DefaultDouble = double.NaN)]
public void SetBorderWidth(Border view, int index, double width)
{
var _width = width;
//view.SetBorderWidth(ViewProps.BorderSpacingTypes[index], width);
}
/// <summary>
/// Creates the image view instance.
/// </summary>
/// <param name="reactContext">The React context.</param>
/// <returns>The image view instance.</returns>
protected override Border CreateViewInstance(ThemedReactContext reactContext)
{
var border = new Border
{
};
var gameHost = new GameHost((int)MainWindow.mw.ActualWidth, (int)MainWindow.mw.ActualHeight-60);
// container.Child = gameHost;
border.Child = gameHost;
var a = view;
return border;
}
}
}

注册组件:

MyReactPage.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using ReactNative.UIManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vesal_PC.MyModel;
namespace Vesal_PC
{
public class MyReactPage : IReactPackage
{
public static ReactContext context;
public IReadOnlyList<INativeModule> CreateNativeModules(ReactContext reactContext)
{
context = reactContext;
MyDialogModel mdm = new MyDialogModel(reactContext);
return new List<INativeModule>
{
mdm,
};
}
public IReadOnlyList<IViewManager> CreateViewManagers(ReactContext reactContext)
{
return new List<IViewManager> {
new ReactUnityManager()
};
}
}
}

AppReactPage.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using ReactNative;
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using ReactNative.Shell;
using ReactNative.UIManager;
using System;
using System.Collections.Generic;
using ReactNative.Modules.Dialog;
namespace Vesal_PC
{
internal class AppReactPage : ReactPage
{
public override string MainComponentName => "Vesal_PC";
public override string JavaScriptMainModuleName => "index";
#if BUNDLE
public override string JavaScriptBundleFile => AppDomain.CurrentDomain.BaseDirectory + "ReactAssets/index.wpf.bundle";
#endif
public override List<IReactPackage> Packages => new List<IReactPackage>
{
new MainReactPackage(),
new MyReactPage(),
};
public override bool UseDeveloperSupport
{
get
{
#if !BUNDLE || DEBUG
return true;
#else
return false;
#endif
}
}
}
}

前端:

UnityView.js

1
2
3
4
5
6
7
8
9
import { PropTypes, Component } from "react";
import { requireNativeComponent, View, ViewPropTypes } from "react-native";
class UnityView extends Component {
render() {
return <RCTUnityView {...this.props} />;
}
}
module.exports = requireNativeComponent("RCTUnityView", UnityView);

使用:

1
<UnityView style={{width:1680,height:1050}}/>

服务器监控脚本

发表于 2019-04-09   |   分类于 Python   |  

monitor.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# coding:utf-8
# !/usr/bin/env python3
import os
import time
from aliyunsdkdysmsapi.request.v20170525 import SendSmsRequest
from aliyunsdkdysmsapi.request.v20170525 import QuerySendDetailsRequest
from aliyunsdkcore.client import AcsClient
import uuid
from aliyunsdkcore.profile import region_provider
from aliyunsdkcore.http import method_type as MT
from aliyunsdkcore.http import format_type as FT
import const
# from config import Alarm_cache
from config import Settings
# 监控逻辑
# 注意:不要更改
REGION = "cn-hangzhou"
PRODUCT_NAME = "Dysmsapi"
DOMAIN = "dysmsapi.aliyuncs.com"
acs_client = AcsClient(const.ACCESS_KEY_ID, const.ACCESS_KEY_SECRET, REGION)
region_provider.add_endpoint(PRODUCT_NAME, REGION, DOMAIN)
def send_sms(phone_numbers, sign_name, template_code, template_param=None):
smsRequest = SendSmsRequest.SendSmsRequest()
# 申请的短信模板编码,必填
smsRequest.set_TemplateCode(template_code)
# 短信模板变量参数
if template_param is not None:
smsRequest.set_TemplateParam(template_param)
# 短信签名
smsRequest.set_SignName(sign_name)
# 数据提交方式
# smsRequest.set_method(MT.POST)
# 数据提交格式
# smsRequest.set_accept_format(FT.JSON)
# 短信发送的号码列表,必填。
smsRequest.set_PhoneNumbers(phone_numbers)
# 调用短信发送接口,返回json
smsResponse = acs_client.do_action_with_exception(smsRequest)
# TODO 业务处理
return smsResponse
def monitor():
print('***启动监控***')
while True:
ports = [8000, 8001, 8002]
for port in ports:
check_url = "http://api.XXX.cn:%s/server?type=0" % (
port)
command = "curl -I -m 30 -o /dev/null -s -w %{http_code} " + check_url
http_code = os.popen(command).read()
print("ping %s 状态码为%s" % (check_url, http_code))
if http_code != "200":
# Alarm_cache["ping_error"].append(diff)
# 发短信
print("###发送短信给相关的人###")
params = "{\"interface\":\"%s\"}" % (port)
for phone in Settings["alarm_phones"]:
print(send_sms(phone, "thisissignname", "SMS_99999999", params))
time.sleep(300)
print('5分钟后检查')
if __name__ == '__main__':
monitor()

config.py

1
2
3
4
5
6
7
8
# coding:utf-8
Alarm_cache = {
"ping_error": []
}
# 配置
Settings = {
"alarm_phones": ['thisiscellphone']
}

Android 调试|日志脚本

发表于 2019-04-08   |   分类于 前端   |  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
PackageName=$1
#PackageName=com.example.appinfomanagertinno
pid="$(adb shell ps | grep $PackageName | awk '{print $2}')"
echo "PackageName-----"
echo "$PackageName"
echo "-----------------------------------------"
echo "-----------------------------------------"
echo "pid-----"
echo "$pid"
echo "-----------------------------------------"
echo "-----------------------------------------"
adb logcat | grep $pid

使用方法
./logcat_package.sh com.XXX.XXX

百度语音tts Android9.0 发音解决办法

发表于 2019-04-08   |   分类于 前端   |  

百度语音在Android9.0不能发音解决办法:
在 AndroidManifest.xml <application>下加入:

1
<uses-library android:name="org.apache.http.legacy" android:required="false"/>

Swift高级篇

发表于 2016-12-20   |   分类于 Swift   |  

扩展(Extension)

任务: 求数字的平方。

1
2
3
4
// 菜鸟版
func square(x: Int) -> Int { return x * x }
var squaredOfFive = square(x: 5)
square(x: squaredOfFive) // 625

为了求5的四次方我们被迫创建变量 squaredOfFive — 高手可不喜欢被迫定义一个无用的变量。

1
2
3
4
5
6
// 高手版
extension Int {
var squared: Int { return self * self }
}
5.squared // 25
5.squared.squared // 625

泛型(Generics)

任务:打印输出数组内所有的元素。

1
2
3
4
5
6
7
8
9
10
11
// 菜鸟版
var stringArray = ["苍老师", "范老师", "优衣库"]
var intArray = [1, 3, 4, 5, 6]
var doubleArray = [1.0, 2.0, 3.0]
func printStringArray(a: [String]) {
for s in a {
print(s)
}
}
func printIntArray(a: [Int]) { for i in a { print(i) } }
func printDoubleArray(a: [Double]) {for d in a { print(d) } }

居然要定义这么多函数? 菜鸟能忍高手不能忍!

1
2
3
4
5
6
// 高手版
func printElementFromArray(a: [T]) {
for element in a {
print(element)
}
}

For 遍历 vs While 遍历

任务:打印 5 次 大雁塔

1
2
3
4
5
6
// 菜鸟版
var i = 0
while 5 > i {
print("大雁塔")
i += 1
}

被迫定义了变量 i 来确保打印大雁塔5次

1
2
3
4
// 高手版
for _ in 1...5 {
print("大雁塔")
}

计算属性 vs 函数

任务:计算圆的直径

1
2
3
4
5
6
// 菜鸟版
funcgetDiameter(radius: Double) -> Double { return radius * 2}
funcgetRadius(diameter: Double) -> Double { return diameter / 2}
getDiameter(radius: 10) // return 20
getRadius(diameter: 200) // return 100
getRadius(diameter: 600) // return 300

上面我们创建了2个毫无关系的函数,可是直径和周长两者真的没有关系吗?

1
2
3
4
5
6
7
8
9
10
// 高手版
var radius: Double = 10
var diameter: Double {
get { return radius * 2}
set { radius = newValue / 2}
}
radius // 10
diameter // 20
diameter = 1000
radius // 500

函数式编程

任务: 获取偶数。

1
2
3
4
5
6
7
8
// 菜鸟版
var newEvens = [Int]()
for i in 1...10 {
if i % 2 == 0 {
newEvens.append(i)
}
}
print(newEvens) // [2, 4, 6, 8, 10]

这种for循环真是冗长,让人看的昏昏欲睡。

1
2
3
4
// 高手版
var evens = (1...10).filter { $0 % 2 == 0 }
print(evens)
// [2, 4, 6, 8, 10]

1…456…16
peterfei

peterfei

peterfei|技术|上主是我的牧者

77 日志
14 分类
62 标签
RSS
github
© 2023 peterfei
由 Hexo 强力驱动
主题 - NexT.Mist