Comment utiliser ReadDirectoryChangesW dans XULRunner (js-ctypes)

J'essaie d'implémenter la réponse à cette question sur la surveillance d'un système de fichiers Windows de manière asynchrone. J'utilise js ctypes dans un ChomeWorker dans le cadre d'une application XULRunner, mais je suppose que cela serait le même si j'avais mis en place un complément Firefox.

Dans le cadre de la tâche, j'ai essayé de déclarer la fonction ReadDirectoryChangesW comme suit (en fonction de ma connaissance limitée des js ctypes et de la documentation MSDN ).

const BOOL = ctypes.bool; const DWORD = ctypes.uint32_t; const LPDWORD = ctypes.uint32_t.ptr; const HANDLE = ctypes.int32_t; const LPVOID = ctypes.voidptr_t; var library = self.library = ctypes.open("Kernel32.dll"); ReadDirectoryChangesW = library.declare( "ReadDirectoryChangesW" , ctypes.winapi_abi , BOOL // return type , HANDLE // hDirectory , LPVOID // lpBuffer , DWORD // nBufferLength , BOOL // bWatchSubtree , DWORD // dwNotifyFilter , LPDWORD // lpBytesReturned ); 

De plus (non présenté ici), j'ai déclaré les mappages de fonctions pour FindFirstChangeNotification() et WaitForSingleObject() qui semblent fonctionner FindFirstChangeNotification() .

Le problème que j'ai est que lorsqu'un événement sur un système de fichiers se produit, je n'ai aucune idée de ce que je suis censé transmettre à l'argument lpBuffer ou comment interpréter le résultat.

Tous les exemples de C ++ semblent utiliser un tableau DWORD et ensuite expulser les résultats. Ma tentative est la suivante:

 const DWORD_ARRAY = new ctypes.ArrayType(DWORD); var lBuffer = new DWORD_ARRAY(4000); var lBufferSize = DWORD.size * 4000; var lBytesOut = new LPDWORD(); ReadDirectoryChangesW(lHandle, lBuffer.address(), lBufferSize, true, WATCH_ALL, lBytesOut) 

Cela semble couper XULRunner tout le temps.

Quelqu'un peut-il suggérer ce que je devrais passer pour l'argument lpBuffer et / ou comment obtenir des résultats de ReadDirectoryChangesW() ? Tout ce que je peux trouver en ligne est des exemples C ++ et ils ne sont pas très utiles. Merci.

Voici une solution plus propre, lisez les commentaires, beaucoup d'apprentissage là-bas. Pour les définitions de type, voir ici: https://github.com/Noitidart/jscFileWatcher/blob/36d53bc6b19f36e4612658b90260f4d4cbd2c49d/modules/ostypes_win.jsm

 var path = OS.Constants.Path.desktopDir; // path to monitor var hDirectory = ostypes.API('CreateFile')(path, ostypes.CONST.FILE_LIST_DIRECTORY | ostypes.CONST.GENERIC_READ, ostypes.CONST.FILE_SHARE_READ | ostypes.CONST.FILE_SHARE_WRITE, null, ostypes.CONST.OPEN_EXISTING, ostypes.CONST.FILE_FLAG_BACKUP_SEMANTICS | ostypes.CONST.FILE_FLAG_OVERLAPPED, null); console.info('hDirectory:', hDirectory.toString(), uneval(hDirectory)); if (ctypes.winLastError != 0) { //cutils.jscEqual(hDirectory, ostypes.CONST.INVALID_HANDLE_VALUE)) { // commented this out cuz hDirectory is returned as `ctypes.voidptr_t(ctypes.UInt64("0xb18"))` and i dont know what it will be when it returns -1 but the returend when put through jscEqual gives `"breaking as no targetType.size on obj level:" "ctypes.voidptr_t(ctypes.UInt64("0xb18"))"` console.error('Failed hDirectory, winLastError:', ctypes.winLastError); throw new Error({ name: 'os-api-error', message: 'Failed to CreateFile', }); } var dummyForSize = ostypes.TYPE.FILE_NOTIFY_INFORMATION.array(1)(); // accept max of 1 notifications at once (in application you should set this to like 50 or something higher as its very possible for more then 1 notification to be reported in one read/call to ReadDirectoryChangesW) console.log('dummyForSize.constructor.size:', dummyForSize.constructor.size); console.log('ostypes.TYPE.DWORD.size:', ostypes.TYPE.DWORD.size); var dummyForSize_DIVIDED_BY_DwordSize = dummyForSize.constructor.size / ostypes.TYPE.DWORD.size; console.log('dummyForSize.constructor.size / ostypes.TYPE.DWORD.size:', dummyForSize_DIVIDED_BY_DwordSize, Math.ceil(dummyForSize_DIVIDED_BY_DwordSize)); // should be whole int but lets round up with Math.ceil just in case var temp_buffer = ostypes.TYPE.DWORD.array(Math.ceil(dummyForSize_DIVIDED_BY_DwordSize))(); var temp_buffer_size = temp_buffer.constructor.size; // obeys length of .array console.info('temp_buffer.constructor.size:', temp_buffer.constructor.size); // will be Math.ceil(dummyForSize_DIVIDED_BY_DwordSize) var bytes_returned = ostypes.TYPE.DWORD(); var changes_to_watch = ostypes.CONST.FILE_NOTIFY_CHANGE_LAST_WRITE | ostypes.CONST.FILE_NOTIFY_CHANGE_FILE_NAME | ostypes.CONST.FILE_NOTIFY_CHANGE_DIR_NAME; //ostypes.TYPE.DWORD(ostypes.CONST.FILE_NOTIFY_CHANGE_LAST_WRITE | ostypes.CONST.FILE_NOTIFY_CHANGE_FILE_NAME | ostypes.CONST.FILE_NOTIFY_CHANGE_DIR_NAME); console.error('start hang'); var rez_RDC = ostypes.API('ReadDirectoryChanges')(hDirectory, temp_buffer.address(), temp_buffer_size, true, changes_to_watch, bytes_returned.address(), null, null); var cntNotfications = 0; var cOffset = 0; while (cOffset < bytes_returned) { cntNotfications++; var cNotif = ctypes.cast(temp_buffer.addressOfElement(cOffset), ostypes.TYPE.FILE_NOTIFY_INFORMATION.ptr).contents; // cannot use `temp_buffer[cOffset]` here as this is equivlaent of `temp_buffer.addressOfElement(cOffset).contents` and cast needs a ptr console.info('cNotif:', cNotif.toString()); cOffset += cNotif.NextEntryOffset; // same as doing cNotif.getAddressOfField('NextEntryoffset').contents // also note that .contents getter makes it get a primaive value so DWORD defined as ctypes.unsigned_long will not be returned as expected ctypes.UInt64 it will be primative (due to the .contents getter), so no need to do the typical stuff with a `var blah = ctypes.unsigned_long(10); var number = blah.value.toString();` } console.info('total notifications:', cntNotifications); 

Je travaille à faire fonctionner l'async verison, mais à un moment délicat, si quelqu'un est intéressé à voir le code / aide, faites-le moi savoir.

Voici ce que j'ai appris alors que je travaille à faire de même maintenant, toujours en cours

  • Vous devez créer un tampon de DWORD pour var buf = ctypes.ArrayType(DWORD, BUFSIZE) car il doit être aligné sur la limite DWORD, quoi qu'il en soit
  • Je ne sais pas ce que BUFSIZE devrait être exactement, mais j'ai vu 2048 et 4096, je ne sais pas pourquoi. J'ai également vu BUFSIZE de 1024 * 64, pas d'idée pourquoi
  • Ensuite, après avoir exécuté avec succès ReadDirectoryChangesW ce tampon sur FILE_NOTIFY_INFORMATION , puis lisez son contenu
  • Passez null aux 2 arguments finaux uniquement si vous ne voulez pas asynchroniser, nous voulons Async afin que nous LPOVERLAPPED structure LPOVERLAPPED et que nous LPOVERLAPPED là.

modifier:

Heres solution for sync: ceci lit avec succès un événement. Si vous avez plus à déplacer dans temp_buff par le prochain_entry_offset et diffusé: https://github.com/Noitidart/jscFileWatcher/tree/36d53bc6b19f36e4612658b90260f4d4cbd2c49d

Installez cet addon et créez un nouveau dossier sur votre bureau ou quelque chose, et il se connecte à la console du navigateur.

Je travaille sur une version asynchrone, ayant des problèmes avec ça.