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版本。

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,
			&notify,
			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

posted @ 2023-09-05 11:15  redrobot  阅读(203)  评论(0编辑  收藏  举报