duangsuse::Echo
719 subscribers
4.28K photos
130 videos
583 files
6.49K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#C #Windows 我来总结一下用了哪些 API 怎么用,方便背

首先,你需要 aero.h [@ysc3839's gist] 这个 undocumented API header 其中包括必须的数据类型和子程序定义

#CSharp 版:需要使用 C# 的 P/Invoke (System.Runtime.InteropServices)特性

1. 对于外部的 C 结构体,只需要使用 struct 关键字定义,然后加上 [StructLayout(LayoutKind.Sequential)] 特性避免压缩移动优化结构体就可以了
2. 对于外部的 C 子程序,只需要将在一个类里定义的静态方法用 extern 修饰,这个方法加上 [DllImport("user32.dll")] 之类的特性就可以了,如果要指定载入使用的字符编码,需要使用 CharSet(=CharSet.Ansi) 特性指定

Trumeet 的示例还用了一个 [STAThread] 方法特性,只是这个单元只能单线程执行,不过其实不必加在 Main 静态方法上,和 COM 交互的时候加就好了,这个知道就好
Forwarded from Richard Yu
aero-example.c
1.2 KB
写好了。
duangsuse::Echo
#C #Windows 我来总结一下用了哪些 API 怎么用,方便背 首先,你需要 aero.h [@ysc3839's gist] 这个 undocumented API header 其中包括必须的数据类型和子程序定义 #CSharp 版:需要使用 C# 的 P/Invoke (System.Runtime.InteropServices)特性 1. 对于外部的 C 结构体,只需要使用 struct 关键字定义,然后加上 [StructLayout(LayoutKind.Sequential)]…
== 无关的 Win32 Form API

static Application.EnableVisualStyles();

static Application.SetCompatibleTextRenderingDefault(bool);
static Application.Run(Form);

namespace System.Windows.Forms { Form }
class Form {
protected void OnLoad(EventArgs);
}

== 有关的 Aero API

首先这里的 Aero 就是 Windows 所谓的毛玻璃特效
既然都用过这个特效,那都知道这个特效有三个最重要的参数:

1. 毛玻璃的特效状态,比如是否启用
2. 毛玻璃的颜色(color)、毛玻璃的模糊度、边缘和渐变色什么的,这些统称为毛玻璃效果的属性(attribute)
3. 毛玻璃的大小矩形框(这个是作为一个矩形视图也要有的)
4. Aero 是可以指定窗口动画的

== 有关的 P/Invkoke 封送(System.Runtime.InteropServices.Marshal)API

static Int32 Marshal.SizeOf<T>(); 
[NET 4.5.1+]
static Marshal.AllocHGlobal(Int32); 其中 H 是 Handle 的意思... 总之 Unix 系 Programmer 的直觉还是有点无法和 Win32 MSVC 系无法统一啊(UNIX 是直接 void *malloc(size_t);
static Marshal.FreeHGlobal(Int32);
用完了别忘记放回去别人还得用
static void StructureToPtr<T>(T, IntPtr, Boolean); 就是 memmove,Rust 的 ptr::write,第三个参数的意思就是复制数据之前要不要先删掉那块地方旧的分配(如果是新分配到的内存就不需要)
注意:
1. 如果你使用 deleteOld,且 ptr output 没有被正确设置,则可能破坏原有有效数据
2. 如果你不使用 deleteOld,且 ptr output 本来就已经没用了,则可能导致内存泄漏 (滑稽)

此外,要使用 C# 的 FFI 特性,还有 new T {} where T: structureref T 拿到指针的特性


那实际上只需要用这两个 API,一个 Getter 一个 Setter,都 Take 一个 Window Handle,一个 struct _WINDOWCOMPOSITIONATTRIBDATA *

bool __stdcall pfnGetWindowCompositionAttribute(HWND, WINDOWCOMPOSITIONATTRIBDATA*);
bool __stdcall pfnSetWindowCompositionAttribute(HWND, WINDOWCOMPOSITIONATTRIBDATA*);

我实在不知道 typedef 还可以这么用 typedef int (*add2)(int);... 等于这个 type 的名字是 (*add2)(int), 看起来根本不是一个标识符... 或者说根本不存在名字(int (*)(int) 本身就是 C 的函数指针类型)... 奇妙



WINDOWCOMPOSITIONATTRIBDATA
这个类型又是啥子呢?它就是 Windows 的窗口混成器参数:

struct {
enum WINDOWCOMPOSITIONATTRIB Attrib;
void *pvData; size_t cbData;
}

其中 WINDOWCOMPOSITIONATTRIB 有很多单选项啦,比如 WCA_EXCLUDED_FROM_LIVEPREVIEW (不允许实时预览)、WCA_TRANSITIONS_FORCEDISABLED(不允许移动?)
后面的 void *pvDatasize_t cbData 是一家的,它们指向一个内存切片(buffer; slice)一般可以被解释为

struct ACCENT_POLICY {
enum ACCENT_STATE AccentState;
DWORD AccentFlags;
DWORD GradientColor;
DWORD AnimationId;
}

enum ACCENT_STATE {
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
ACCENT_INVALID_STATE = 6
}

一般直接用毛玻璃(BLUR BEHIND)

== 这个合成属性的使用

首先,准备好目标窗体 hwnd 和 Aero 参数 struct AccentPolicy

static int SetAero(IntPtr hwnd, ref AccentPolicy policy) {...}

准备数据

var wcaps = new WindowsCompositionAttributeData { Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY };

wcaps.SizeOfData = Marshal.SizeOf<AccentPolicy>();
wcaps.Data = policy;

Trumeet 是直接复制了别人的 SizeOf, AllocHGlobal, StructureToPtr, FreeHGlobal... 走了一遍 StructToNewAlloc 的流程,但是其实拿到此结构的指针传递数据就可以了,也不一定得堆分配。
然后直接使用 setter attributeDatas[AccentPolicy] = ...(拟

return SetWindowCompositionAttribute(hwnd, ref wcaps);

Aero 参数 AccentPolicy 怎么拿?首先我们得清楚,架构此结构体的方法不能返回一个本地分配的 AccentPolicy... 其次最好也不要返回一个 struct AccentPolicy,因为它要复制比较多的数据....
那既然如此为什么不把 SetAero 当成是 MakeAeroEffect 子程序的辅助者,然后直接在 MakeAeroEffect 里分配?

static int MakeAeroEffect(IntPtr hwnd, AeroState st, int aeroFlags = 0, int gradientColor = 0x00000000, int animId = 0) {...}

这里就对应到了之前的四个特效属性

var params = new AccentPolicy { AccentState=st, AccentFlags=aeroFlags, GradientColor=gradientColor, AnimationId=animId };

然后按照约定,调用 setAero

return setAero(hwnd, ref params);

就 OK 了

以上讲到的是 CSharp P/Invoke Windows 10 Aero Hidden API 的代码,不过 Windows 7 的(默认 Aero)要使用 DwmApi.dllDwmExtendFrameIntoClientArea 来把 window 的某个 frame 化为新混成区域,因为默认有 Aero glass

你学到的应该是:
1. 使用 [DllImport(...)] extern ... 动态链接外部函数库;使用 [StructLayout(LayoutKind.Sequential)] 定义可以被正确传递给 C FFI 的结构体
2. 使用 IntPtrref (当然它们不如 SafeHandle,不过后者是只有真正的 C#+Windows CNI 原生接口 程序员才知道)
3. 如何使用 SetWindowCompositionAttribute 设置指定窗体混成属性
4. Windows 的 Aero 混成属性:AccentPolicyenum AccentState,它的四个子属性(状态、特性标志、渐变、动画效果)
duangsuse::Echo
aero-example.c
Win32 API 真的是很不友好... 要记很多东西,而且比如那个 dialog 本来应该是属性的东西却被弄成 callback Query 的形式,真是让人有点难记

虽然所有人看着文档都能写出代码而已,我会很希望默写下来看到的每一行代码... 😭
Forwarded from dnaugsuz
说起来我之前以为不能在 Kotlin 里面 null ?: return 的因为 returnNothing,另一个想法就是表达式求值不应该被中断... (这明显是错误的)
现在想来居然可以!
Forwarded from Yuuta
原来 GetModuleHandle(0) 的参数是 LPCSTR
Forwarded from Yuuta
我就把 0 理解为 Null 了
Forwarded from Richard Yu
是的
Forwarded from Richard Yu
C里面一般是 #define NULL (void*)0 的,C++ 里面 nullptr 转换为指针的时候也是 0。
Forwarded from dnaugsuz
... 真的不该这么写的,以后千万千万不要把 nullptr (char*) *{'\0'}; 之类的东西写成 0 了,很多人以为代码短一点很秀,其实反而会导致很大混淆,这是不正确的

LLVM Cookbook 这本书里,把所有 * 指针类型的空指针值全写成了 0,我眼睛都要看瞎了
书中有一个大概类似这样的子程序:
ConstLiteral::Codegen override 了超类 BaseAstvirtual Value *Codegen();
Value *ConstLiteral::Codegen() override {
switch (type) {
case vaConstInt: return ConstantInt::get(Type::getInt32Ty(vCtx), (int) value);
default: return 0;
}
}

有的时候父语法树节点依赖子节点的值,然后要 null safe,他是这么判断的(比如 for i=0, 10 循环节点):

if (initval.Codegen() == 0) return 0;

其实要这么写(也很辣鸡莫名其妙)我都能接受,但他偏偏写了这么多 0...
if (initval.Codegen() /*!=0*/) {...}

我的天啊,简直看瞎了,当时我就觉得他们都是些只会抄代码的货,虽然后面的确是有干货,为什么编程风格这么差
Forwarded from dnaugsuz
所以以后觉得 "" 难看就弄一个 EMPTY_CHARP (当然 Windows 里显然要叫 EMPTY_LPCHAR...) 常量算了
这么混淆的确是有点误人子弟,别人看第一眼还以为是 GetModuleHandle 函数处理了特别的值,其实只是 "" 而已
Forwarded from yunfeng
隔壁 java 留下了眼泪(
Forwarded from dnaugsuz
Jawa 也有一些可以“跨运行时平台”的实现,比如 JSweet transpiler
JVM 本身对 C, C++ 等所谓 Native 语言的编译器也有实现的,至少人家还支持 JNI 扩展底层访问性呢 [比如说这个]
曾经的 GCJ (GNU Compiler for Java) 也是支持 Java -> native code 的
现在 GraalVM 、之前 ExcelsiorJET 不也在吹 AOT 编译的说
Forwarded from Yuuta
不懂那么深奥的,反正 J AV A 给我的感觉就是有大又笨又老(x
Forwarded from dnaugsuz
Java 是很老,但也是 Kotlin 它干爹啊 🌝
Forwarded from Yuuta
不能完全算吧?从某种意义上说 Kotlin 是 “兼容” Java(x
Forwarded from dnaugsuz
C 自己也有不好的地方,比如 Null safety
你得自己写代码处理输入 ptr 可能为空但不应该为空的情况,而 Kotlin 是自动处理

如果你是比较优秀的程序员,肯定会用子程序对 raw FFI 进行高层封装(比如,一个 Optional<T> 会被你弄成 @Throws(XXXNotFound::class) 的形式),这样就避免了每次检查 null safety 的问题,Kotlin 只是做了对的事情,检查了 null 指针的可能性,把运行期的错误提升到了编译期,虽然 Kotlin 它不 Check Exceptions... 也有自己的道理,但完全不 sound (没 error 也没 warn)的编译检查还是....

这一点 ice1000 的博文《形式验证、依赖类型与动态类型》讲得很好