原生开发,使用C语言调用Windows API 开发软件思路分享
Githu: https://github.com/vladelaina/Catime

作者是一个高度依赖计时器功能的人,但是市面上的软件都不能满足个性化的需求,所以打算自己动手开发,同时采用c语言来做原生开发,一下是开发思路,以及遇到的问题
1. 原生开发的优势
使用Windows API进行原生开发具有以下优势:
- 高性能:直接调用系统API,无中间层开销,执行效率高
- 低资源占用:程序体积小,内存占用少,适合轻量级应用
- 系统集成度高:可以深度访问Windows系统功能和资源
- 无依赖性:不需要额外运行时环境,降低部署复杂度
- 精确控制:对UI和系统交互有更精细的控制能力
2. 开发思路与架构设计
2.1 基本架构
典型的Windows API应用程序架构包括:
- 窗口过程函数:处理窗口消息的核心回调函数
- 消息循环:获取并分发系统消息
- 资源管理:处理GDI对象、内存等资源
- 模块化设计:将功能分散到不同模块中
2.2 设计模式
- 事件驱动模型:基于Windows消息机制
- MVC/MVP模式:分离UI和业务逻辑
- 单例模式:管理全局资源和状态
3. 关键技术点
3.1 窗口创建与管理
// 窗口类注册
WNDCLASS wc = {0};
wc.lpfnWndProc = WindowProcedure;
wc.hInstance = hInstance;
wc.lpszClassName = "MyWindowClass";
RegisterClass(&wc);
// 创建窗口
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"MyWindowClass",
"Window Title",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL);
3.2 消息处理
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE:
// 窗口创建时的初始化
break;
case WM_PAINT:
// 绘制窗口内容
break;
case WM_COMMAND:
// 处理菜单和控件命令
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
3.3 GDI绘图
void DrawContent(HWND hwnd) {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// 创建和选择画笔、画刷
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
HPEN hOldPen = SelectObject(hdc, hPen);
// 绘制图形
Rectangle(hdc, 10, 10, 100, 100);
// 清理资源
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
}
3.4 资源管理
// 资源文件 (resource.rc)
IDI_MYICON ICON "myicon.ico"
IDM_MYMENU MENU BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open", IDM_OPEN
MENUITEM "&Save", IDM_SAVE
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
END
END
// 加载资源
HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
3.5 对话框和控件
// 创建控件
HWND hButton = CreateWindow(
"BUTTON", "Click Me",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 10, 100, 30,
hwnd, (HMENU)IDC_BUTTON, hInstance, NULL);
// 显示对话框
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), hwnd, DialogProc);
// 对话框过程
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if(LOWORD(wParam) == IDOK) {
EndDialog(hwndDlg, IDOK);
return TRUE;
}
break;
}
return FALSE;
}
4. 开发挑战与解决方案
4.1 内存管理
- 挑战:手动管理内存容易导致泄漏
- 解决方案:
- 使用资源获取即初始化(RAII)模式
- 成对调用分配/释放函数
- 使用工具检测内存泄漏
4.2 多线程同步
- 挑战:UI线程与工作线程的协调
- 解决方案:
- 使用PostMessage/SendMessage进行线程间通信
- 合理使用互斥量、事件、信号量等同步原语
- 避免死锁和竞态条件
4.3 DPI感知
- 挑战:在不同DPI设置下保持UI一致性
- 解决方案:
- 实现DPI感知(SetProcessDpiAwareness)
- 使用相对单位而非固定像素
- 根据DPI缩放绘图操作
4.4 国际化支持
- 挑战:支持多语言和不同区域设置
- 解决方案:
- 使用资源字符串而非硬编码文本
- 支持Unicode字符集
- 考虑文本布局方向(RTL/LTR)
5. 构建与部署
5.1 构建工具
- Visual Studio:提供完整IDE体验
- MinGW/GCC:开源编译器选项
- CMake:跨平台构建系统
- Makefile:传统构建脚本
5.2 静态链接与动态链接
- 静态链接:生成独立可执行文件,无外部依赖
- 动态链接:减小可执行文件体积,共享系统DLL
5.3 安装程序制作
- NSIS (Nullsoft Scriptable Install System)
- Inno Setup
- WiX Toolset
5.4 部署注意事项
- 运行时依赖检查
- 权限要求
- 注册表和系统配置
- 应用程序清单(manifest)设置
6. 调试与优化技巧
6.1 调试技术
- 使用DebugView捕获调试输出
- 使用WinDbg进行高级调试
- 实现自定义日志系统
6.2 性能优化
- 减少不必要的重绘
- 优化GDI对象使用
- 使用双缓冲技术避免闪烁
- 延迟加载资源
7. 参考资源
- MSDN文档:https://docs.microsoft.com/en-us/windows/win32/
- Charles Petzold的《Programming Windows》
- 开源项目示例:ReactOS, Wine
- Raymond Chen的博客:The Old New Thing
8. 结语
Windows API原生开发虽然学习曲线较陡,但掌握后能够开发出高效、轻量且深度集成Windows系统的应用程序。通过合理的架构设计和模块化,可以降低开发复杂度,提高代码可维护性。
原生开发,使用C语言调用Windows API 开发软件思路分享的更多相关文章
- C#调用windows API的一些方法
使用C#调用windows API(从其它地方总结来的,以备查询) C#调用windows API也可以叫做C#如何直接调用非托管代码,通常有2种方法: 1. 直接调用从 DLL 导出的函数. 2. ...
- C#中调用Windows API的要点 .
介绍 API(Application Programming Interface),我想大家不会陌生,它是我们Windows编程的常客,虽然基于.Net平台的C#有了强大的类库,但是,我们还是不能否认 ...
- C#中调用Windows API时的数据类型对应关系
原文 C#中调用Windows API时的数据类型对应关系 BOOL=System.Int32 BOOLEAN=System.Int32 BYTE=System.UInt16 CHAR=System. ...
- VBS调用Windows API函数
Demon's Blog 忘记了,喜欢一个人的感觉 Demon's Blog » 程序设计 » VBS调用Windows API函数 « 用VBS修改Windows用户密码 在VB中创建和使用 ...
- C#调用Windows API函数截图
界面如下: 下面放了一个PictureBox 首先是声明函数: //这里是调用 Windows API函数来进行截图 //首先导入库文件 [System.Runtime.InteropServices ...
- 【转】用C#调用Windows API向指定窗口发送
一.调用Windows API. C#下调用Windows API方法如下: 1.引入命名空间:using System.Runtime.InteropServices; 2.引用需要使用的方法,格式 ...
- c# 判断窗体是否永在最前(TopMost),调用windows API
许多程序都可以把自身的窗体设为最前显示状态,这个可以参考博客c#让窗体永在最前 调用windows api 将窗体设为topmost.那么如何判断桌面上的一个窗体是否为最前显示状态呢,不光是自己的程序 ...
- c#让窗体永在最前 调用windows api 将窗体设为topmost
有时候应用程序需要将一个窗体始终位于屏幕的最前面,即使切换到其它窗体也能看到该窗体,这样的窗体就叫做TopMost窗体. 用C#制作TopMost窗体之前,首先要了解如何声明SetWindowPos函 ...
- 善于 调用Windows API
前一段时间看见别人做的一个自动填写信息并且点击登录的程序,觉得很有意思. 其实就是在程序中调用Windows的API,那么如何调用,下面就做个简单的介绍. 写的简单粗暴, 不喜轻喷. 0.首先引入名称 ...
- 用C#调用Windows API向指定窗口发送按键消息 z
用C#调用Windows API向指定窗口发送 一.调用Windows API. C#下调用Windows API方法如下: 1.引入命名空间:using System.Runtime.Interop ...
随机推荐
- Linux安装EasyConnect
首先下载并安装EasyConnect客户端 wget http://download.sangfor.com.cn/download/product/sslvpn/pkg/linux_767/Easy ...
- 更改linux文件/目录的权限、拥有者及用户组
在Linux中,创建一个文件时,该文件的拥有者都是创建该文件的用户.该文件用户可以修改该文件的拥有者及用户组,root用户可以修改任何文件的拥有者及用户组. 在Linux中,对于文件的权限(rwx), ...
- 浅谈LINUX中/DEV/VDA1文件满了解决方法
1. 先查看内存使用情况 df -h 1 2. 进入/dev/vdal的磁盘挂载的目录 /,查看各个文件占用大小 cd / du -sh * 1 2 注意:进入那个比较大的文件,我这里发现var这个文 ...
- 夜莺 v8 第一个版本来了,开始做有意思的功能了
夜莺 v8 大版本已经启动开发,预计 25 年 7.8 月份发正式版,相比 v7 大概会做四五个大功能,每个功能做完了做稳定了都会提前放出来供大家体验,虽然以 beta 来命名,实际是稳定的,大家可以 ...
- Iframe标签显示目标网页的指定区域,视频可全屏可缩小
由于播放的直播视频有多余的logo和聊天框等所以需要去掉,用Iframe标签显示目标网页的指定区域,视频可全屏可缩小 用自己私人的服务器来测试吧,99买阿里云 HTML代码 <html> ...
- 在 Development 环境下依赖注入的行为可能有所不同
奇怪的问题 本周被一个奇怪的问题困扰了一天.事情的起因是这样的:在某个 PR 合并后,我拉了最新代码,但是在我本地F5调试始终报错.示例代码如下: public interface Interface ...
- 零基础Windows Server搭建部署Word Press 博客系列教程(2):从菜鸡到高手之Windows Server 环境配置
上一篇:零基础Windows Server搭建部署Word Press 博客系列教程(1):从萌新到菜鸡之云主机配置与备案 本篇教程主要介绍在云主机上安装好相关组件并配置好环境,直至网站上线. 1.之 ...
- Solution Set - “我献上明月一盏,照满河山”
目录 0.「集训队互测 2018」「洛谷 P9248」完美的集合 1.「UR #6」「UOJ #74」破解密码 2.「NOI Simu.」苯为 3.「NOI Simu.」西克 4.「NOI Simu. ...
- AVL树的插入
关于AVL树的插入,其实是一个比较复杂的问题,主要是在于他对于"旋转"这一概念,对于这一概念其实我感觉很多博主讲的都不是很明白,包括CHATGPT,也试了,但是也没有比较清楚的解释 ...
- 学Shiro完结版-5
第二十一章 授予身份及切换身份--<跟我学Shiro> 在一些场景中,比如某个领导因为一些原因不能进行登录网站进行一些操作,他想把他网站上的工作委托给他的秘书,但是他不想把帐号/密码告诉他 ...