7

The company I'm working with has a program written in ye olde vb6, which is updated pretty frequently, and most clients run the executable from a mapped network drive. This actually has surprisingly few issues, the biggest of which is automatic updates. Currently the updater program (written in c++) renames the existing exe, then downloads and places the new version into the old version's place. This generally works fine, but in some environments it simply fails.

The solution is running this command from microsoft:

for /f "skip=4 tokens=1" %a in ('net files') do net files %a /close

This command closes all network files that are shared (well... most) and then the updater can replace the exe.

In C++ I can use the System(""); function to run that command, or I could redirect the output of net files, and iterate through the results looking for the particular file in question and run net file /close command to close them. But it would be much much nicer if there were winapi functions that have similar capabilities for better reliability and future safety.

Is there any way for me to programmatically find all network shared files and close relevant ones?

wizebin
  • 730
  • 5
  • 15
  • Sounds like this is a Windows specific C++ question... – shargors Sep 10 '15 at 15:07
  • Yes it is, sorry I'll add a tag – wizebin Sep 10 '15 at 15:08
  • 1
    I recommend you search the MSDN to find some Windows API that can help you close network files. – Thomas Matthews Sep 10 '15 at 15:12
  • Good call, @ThomasMatthews I often forget to do the obvious. Found a [decent resource](https://msdn.microsoft.com/en-us/library/windows/desktop/bb525393(v=vs.85).aspx), I'll post some additional information once I get a working solution. – wizebin Sep 10 '15 at 15:25
  • Note that while this does close the file, it also means that the clients will crash the next time they need to demand-page the executable. – Raymond Chen Sep 10 '15 at 19:52
  • The cleaner solution would be to set the "RunFromNetwork" bit in the PE header. This tells the OS not to keep the file open in the first place. – MSalters Jun 05 '20 at 16:10

1 Answers1

8

You can programmatically do what net file /close does. Just include lmshare.h and link to Netapi32.dll. You have two functions to use: NetFileEnum to enumerate all open network files (on a given computer) and NetFileClose to close them.

Quick (it assumes program is running on same server and there are not too many open connections, see last paragraph) and dirty (no error checking) example:

FILE_INFO_2* pFiles = NULL;
DWORD nRead = 0, nTotal = 0;

NetFileEnum(
  NULL, // servername, NULL means localhost
  "c:\\directory\\path", // basepath, directory where VB6 program is
  NULL, // username, searches for all users
  2, // level, we just need resource ID
  (LPBYTE*)&pFiles, // bufptr, need to use a double pointer to get the buffer
  MAX_PREFERRED_LENGTH, // prefmaxlen, collect as much as possible
  &nRead, // entriesread, number of entries stored in pFiles
  &nTotal, // totalentries, ignore this
  NULL //resume_handle, ignore this 
);

for (int i=0; i < nRead; ++i)
    NetFileClose(NULL, pFiles[i].fi2_id);

NetApiBufferFree(pFiles);

Refer to MSDN for details about NetFileEnum and NetFileClose. Note that NetFileEnum may return ERROR_MORE_DATA if more data is available.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • 3
    With very few modifications this works flawlessly. My compiler complained about the extra comma after the last NULL in the enum function and I had to cast the pFiles `(BYTE**)&pFiles` and change the access from `pFile[i]->fi2_id` to a member access instead of pointer access `pFile[i].fi2_id` – wizebin Sep 10 '15 at 16:43
  • @wizebin you're right, I wrote it here without testing. My bad, thank you! – Adriano Repetti Sep 10 '15 at 19:03
  • the lpvoid line needs to be changed to (LPBYTE*)&pFiles, // bufptr – Dan Sep 07 '17 at 17:33
  • I may have added an s somewhere, because you have pFile everywhere but my line now. – Dan Sep 07 '17 at 22:15