windows 下 go 使用
https://www.codenong.com/16492121/
关于go:在cgo中使用Windows库
https://www.cnblogs.com/Kingram/p/12088087.html
Golang编写Windows动态链接库(DLL)及C调用范例
一、准备。
1、GoLang在1.10版本之后开始支持编译windows动态链接库,可以打开命令行工具使用go version 查看自己的go版本。
![](https://img2018.cnblogs.com/i-beta/1383283/201912/1383283-20191223195050231-894753141.png)
2、你的电脑上需要gcc,如果没有的话[点击这里]下载安装,或者问度娘如何下载gcc,有的方法很慢,这是我折腾半天用的最快的方法,下载压缩包解压即可。
二、编译。
1、命令很简单,就一行
> go build -ldflags "-s -w" -o main.dll -buildmode=c-shared main.go
-s 、-w 指令用于减小动态链接库的体积,-s是压缩,-w是去掉调试信息。-o可以指定生成文件的目录。命令可以简化成如下:
> go build -o main.dll -buildmode=c-shared main.go
这句命令执行结束后会在当前目录下生成一个.dll和一个.h文件,至此,编译部分就完成了
https://juejin.cn/post/6844903533649592333
[golang]如何在windows上使用cgo
https://blog.csdn.net/ok532655221/article/details/106729253/
windows下go语言调用C语言xxx.dll动态库(带DEMO)
windows下go语言调用C语言xxx.dll动态库(带DEMO)
https://www.likecs.com/show-308558825.html
Windows监控文件变化(ReadDirectoryChangesW)
2022-12-23
Windows提供了几种方式对文件和目录进行监控,包括:FindFirstChangeNotification、ReadDirectoryChangesW、变更日志(Change Journal)等。
(1)FindFirstChangeNotification函数,可以监控到目标目录及其子目录中所有文件的变化,但不能监控到具体是哪一个文件发生改变。
(2)ReadDirectoryChangesW 能监控到目标目录下某一文件发生改变,并且可以知道发生变化的是哪一个文件。
注意,FindFirstChangeNotification 和 ReadDirectoryChangesW 是互斥的,不能同时使用。
(3)变更日志(Change Journal)可以跟踪每一个变更的细节,即使你的软件没有运行。很帅的技术,但也相当难用。
以下就我使用的ReadDirectoryChangesW 进行说明。
该函数定义为:
BOOL WINAPI ReadDirectoryChangesW( HANDLE hDirectory, // 对目录进行监视的句柄 LPVOID lpBuffer, // 一个指向FILE_NOTIFY_INFORMATION结构体的缓冲区,其中可以将获取的数据结果将其返回。 DWORD nBufferLength, // 指lpBuffer的缓冲区的大小值,以字节为单位。 BOOL bWatchSubtree, // 是否监视子目录. DWORD dwNotifyFilter, // 对文件过滤的方式和标准 LPDWORD lpBytesReturned, // 将接收的字节数转入lpBuffer参数 LPOVERLAPPED lpOverlapped, // 一般选择 NULL LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 一般选择 NULL );
其中结构体FILE_NOTIFY_INFORMATION 的用法下一章将会讲到。
利用ReadDirectoryChangesW函数实现对一个目录进行监控的简单做法是:首先使用CreateFile获取要监控目录的句柄;然后在一个判断循环里面调用ReadDirectoryChangesW,并且把自己分配的用来存放目录变化通知的内存首地址、内存长度、目录句柄传给该函数。用户代码在该函数的调用中进行同步等待。当目录中有文件发生改变,控制函数把目录变化通知存放在指定的内存区域内,并把发生改变的文件名、文件所在目录和改变通知处理。
(1)获取目标目录的句柄
HANDLE m_hDirectory=CreateFile(m_szWatchDirectory, GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY , FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); if(m_hDirectory==INVALID_HANDLE_VALUE) { DWORD dwErr=GetLastError(); return; }
注:FILE_FLAG_BACKUP_SEMANTICS ,使用这个标志需要管理员权限。
共享模式中如果不使用 FILE_SHARE_DELETE,会导致其他进程无法重命名或者删除这个目录下的文件。
这个函数有一个风险:被引用的目录本身处于”使用中“,并且无法被删除。如果希望在监控目录的同时,还允许目录被删除,则应当监控该目录的父目录及父目录下的文件和子目录。
(2)调用 ReadDirectoryChangesW
由于ReadDirectoryChangesW为阻塞函数,以下代码建议在线程中进行。(VS2010中编译通过)
char notify[1024];
memset(notify, 0, sizeof(notify));
FILE_NOTIFY_INFORMATION *pNotification=(FILE_NOTIFY_INFORMATION *)notify;
DWORD BytesReturned=0;
while (TRUE)
{
ZeroMemory(pNotification, sizeof(notify));
watch_state=ReadDirectoryChangesW(hDirectory,
¬ify,
sizeof(notify),
TRUE, //监控子目录
FILE_NOTIFY_CHANGE_FILE_NAME |FILE_NOTIFY_CHANGE_LAST_WRITE , //FILE_NOTIFY_CHANGE_DIR_NAME FILE_NOTIFY_CHANGE_CREATION FILE_NOTIFY_CHANGE_SIZE
(LPDWORD)&BytesReturned,
NULL,
NULL);
if (GetLastError()==ERROR_INVALID_FUNCTION)
{
LOG_INFO(_T("文件监控,系统不支持! %s"), szWatchDirectory);
break;
}
else if(watch_state == FALSE)
{
DWORD dwErr = GetLastError();
LOG_INFO(_T("文件监控,监控失败! %s (LastError: %d)"), szWatchDirectory, dwErr);
break;
}
else if (GetLastError()==ERROR_NOTIFY_ENUM_DIR)
{
LOG_INFO(_T("文件监控,内存溢出! %s"), szWatchDirectory);
continue;
}
else
{
//这里主要就是检测返回的信息,(FILE_NOTIFY_INFORMATION)
CString szFileName(pNotification->FileName, pNotification->FileNameLength / sizeof(wchar_t));
if (pNotification->Action==FILE_ACTION_ADDED)
{
LOG_INFO(_T("文件监控,新增文件! %s\\%s"), szWatchDirectory, szFileName);
}
else if (pNotification->Action==FILE_ACTION_REMOVED)
{
LOG_INFO(_T("文件监控,删除文件! %s\\%s"), szWatchDirectory, szFileName);
}
else if (pNotification->Action==FILE_ACTION_MODIFIED)
{
LOG_INFO(_T("文件监控,修改文件! %s\\%s"), szWatchDirectory, szFileName);
}
else if (pNotification->Action==FILE_ACTION_RENAMED_OLD_NAME)
{
LOG_INFO(_T("文件监控,重命名文件! %s\\%s"), szWatchDirectory, szFileName);
}
else if (pNotification->Action==FILE_ACTION_RENAMED_NEW_NAME) //还没出现过这种情况
{
LOG_INFO(_T("文件监控,重命名文件2! %s\\%s"), szWatchDirectory, szFileName);
}
//PostMessage通知主线程
}
}
CloseHandle(hDirectory);
(3)说明:
A、ReadDirectoryChangesW 数据缓冲区中使用的都是宽字节Unicode,字符串不是 NULL 结尾的,所以不能使用 wcscpy。如果你使用 ATL 或 MFC 的 CString 类,方法在上面代码中有。
B、使用While循环,就是要在每次监测到一次变化后,重新发起新的 ReadDirectoryChangesW 调用。
C、如果很多文件在短时间内发生变更,则有可能会丢失部分通知。
D、如果缓冲区溢出,整个缓冲区的内容都会被丢弃,BytesReturned会返回0。 E、在MSDN中,FILE_NOTIFY_INFORMATION的文档有一个关键的描述:如果文件既有长文件名,又有短文件名,那么文件会返回其中的一个名字,但不确定是返回哪一个。大多数时候,在短文件名和长文件名之间转换都很容易,但是如果文件被删除,情况就不一样了。最好的方法是维护一个跟踪文件的列表,同时跟踪长文件名和短文件名。(这种情况目前还没有遇到过)
(4)以下为本人测试的结果:(本人使用的是WINDOWS10 64位系统)
其中的newName:从pNotification->FileName 偏移pNotification->NextEntryOffset处获取的新名称
方法为:
TCHAR newName[1024]={0}; ZeroMemory(newName, sizeof(newName)); int length = sizeof(notify) - pNotification->NextEntryOffset; CopyMemory(newName, pNotification->FileName + pNotification->NextEntryOffset / sizeof(wchar_t), length);
//新建1:在目标主目录新建文件,只会出现:1次文件相关的FILE_ACTION_ADDED。
//新建2:但在子目录中新建一个文件,会先后出现:1次与文件相关的FILE_ACTION_ADDED,1次与子目录相关的FILE_ACTION_MODIFIED。
//复制:复制一个文件到目标主目录或子目录,会先后出现:1次文件相关的FILE_ACTION_ADDED(只有oldName,无newName),1次文件相关的FILE_ACTION_MODIFIED(oldName和newName都有)。 //fix
//修改:修改文件后,会出现2次FILE_ACTION_MODIFIED。//fix (都只有oldName)
//剪切再粘贴:在目标目录的两个子目录间剪切粘贴一个文件,会先出现1次FILE_ACTION_REMOVED,再出现1次FILE_ACTION_ADDED
//删除:删除一个文件,先出现1次文件相关的FILE_ACTION_REMOVED,再出现1次目录相关的FILE_ACTION_MODIFIED
//重命令:1次FILE_ACTION_RENAMED_OLD_NAME
(5)关于线程退出机制
ReadDirectoryChangesW 为阻塞型函数,很多人会使用TerminateThread强制结束该线程,但这样会导致资源无法释放。
最好的方法是:创建一个手动重置的 Event 对象,作为 WaitForMultipleObjects 等待的第二个句柄。当 Event 被设置的时候,退出线程。
原文链接:https://www.cnblogs.com/pjl1119/articles/ReadDirectoryChanges.html
参考:
https://www.likecs.com/show-308558825.html