2

I'm developing firefox plugin and I want to read file using WinApi. I manage to connect with WinApi and it works fine.

var lib = ctypes.open("user32.dll");
var msgBox = lib.declare("MessageBoxW",
                       ctypes.winapi_abi,
                       ctypes.int32_t,
                       ctypes.int32_t,
                       ctypes.jschar.ptr,
                       ctypes.jschar.ptr,
                       ctypes.int32_t);
var MB_OK = 0;
var ret = msgBox(0, "Hello world", "title", MB_OK);

Now I declare fopen:

const FILE = new ctypes.StructType("FILE").ptr;   
var fopen = libc.declare("fopen",                     // symbol name
                        ctypes.default_abi,           // cdecl calling convention
                        FILE,                         // return type (FILE*)
                        ctypes.char.ptr,              // first arg (const char*)
                        ctypes.char.ptr);             // second arg (const char*)

but I fail to declare fgets. I still can't figure it out. I try to do:

var libc = ctypes.open("msvcrt.dll");
var fgets = libc.declare("fgets",                    
                        ctypes.default_abi,           
                        ctypes.char.ptr,              
                        ctypes.char.ptr,              
                        ctypes.int32_t,               
                        FILE);                        
// Call the function, and get a FILE* pointer object back.
console.log(LOG_FILTER, "Try to open file.");
var file1 = fopen("1.in", "r");

  var SIZE = 100;
  var line = ctypes.char(SIZE).ptr;
  line = fgets(line, SIZE, file1);` 

I think I don't use wrong library because then I would get error "Error: couldn't find function symbol in library" but I still get "TypeError: expected type pointer, got (void 0)"

alicjab
  • 331
  • 2
  • 4
  • 14
  • Not answering your specific question. But please do not use raw `fopen`, etc. if it can be avoided. There are already plenty of file access APIs such as [`nsIFileInputStream`](https://developer.mozilla.org/en/search?q=nsifileinputstream) or [`OS.File`](https://developer.mozilla.org/en-US/docs/JavaScript_OS.File), which are not only cross-platform and in heavy use by Firefox and other add-ons, but also easier to use and more reliably than mucking around with js-ctypes. – nmaier Feb 21 '14 at 22:41
  • I know about those APIs but I need to use WinApi necessarily. – alicjab Feb 25 '14 at 08:04

3 Answers3

2

heres an example of a bunch of different ctype declarations: https://builder.addons.mozilla.org/package/161408/latest/

if you still cant figure it out post it up and ill try to get fget working.

but do with namier recommended, use the cross platform options thats best, but for leearning sake we can do this fget when i have some time if you dont figure it out

Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • Thanks for you response, the example is useful but I still can't do it properly. I edited my post to show how I try to declare `fgets`. Can you see what is wrong with it? – alicjab Feb 25 '14 at 08:20
  • Will look into later, but im curious about your fopen. ```const FILE = new ctypes.StructType("FILE").ptr; ``` thats a pointer, dont you have to define the structure? how does this work? does it even work? – Noitidart Feb 25 '14 at 23:52
  • Yes, it works. When I do `var file = fopen("newfile.in", "w");` it creates new file. Const FILE is used only in function declaration, it doesn't matter. – alicjab Feb 26 '14 at 09:30
  • ok will look into this sometime soon, be sure to remind me though, if i dont get reminders for free time stuff i tend to forget. remind me by posting here every so often. i get notified – Noitidart Feb 26 '14 at 09:34
  • also you arent really implementing this in your addon are you? you should really use [osfile.jsm](https://developer.mozilla.org/en-US/docs/JavaScript_OS.File/OS.File_for_the_main_thread). i'm just working on fget for learning purposes – Noitidart Feb 26 '14 at 09:35
  • I won't use it in my plugin. I'm just developing sth for myself and I want to use winApi instead of ready APIs. – alicjab Feb 26 '14 at 11:21
  • Ok, I finally menage to read file. I used `getc` instead of `fgets` . Thanks for your help! – alicjab Feb 26 '14 at 12:04
  • can you please share the getc with us im real interested in the ctypes version of it. im actually struggling to make a setWindowsHookEx in ctypes – Noitidart Feb 26 '14 at 18:14
2

So here is my solution. I decided to use getc function instead of fgets and I manage to read file.

Components.utils.import("resource://gre/modules/ctypes.jsm");
var libc = ctypes.open("msvcrt.dll");

// int getc(FILE *stream);
var getc = libc.declare("getc",
                        ctypes.default_abi,
                        ctypes.int32_t,
                        FILE);
var file = fopen("newfile.in", "w");
var readFile = readFileToString(file)

function readFileToString(file) {
  var result = '';
  var c = 0;
  while((c = getc(file)) != -1) {
    result += String.fromCharCode(c); 
  }
  console.log("result = " + result);
  return result;
}
alicjab
  • 331
  • 2
  • 4
  • 14
0

ok i had some time so i played around with it and i need your help fixing it.

this is your version i fixed it up. copy paste this to scratchpad set it to environment > browser and run it

Cu.import("resource://gre/modules/ctypes.jsm");
var libc = ctypes.open("msvcrt.dll");

var FILE = new ctypes.StructType("FILE").ptr; //made var otherwise in scratchpad cant run multiple times, this can be CONST its no issue
var fopen = libc.declare("fopen",                     // symbol name
                        ctypes.default_abi,           // cdecl calling convention
                        FILE,                         // return type (FILE*)
                        ctypes.char.ptr,              // first arg (const char*)
                        ctypes.char.ptr);             // second arg (const char*)


var fgets = libc.declare("fgets",                    
                        ctypes.default_abi,           
                        ctypes.char.ptr,              
                        ctypes.char.ptr,              
                        ctypes.int32_t,               
                        FILE);          


var myfile = fopen("C:\\Users\\3K2KYC1\\Desktop\\FirefoxPortable\\newfile.in", "r");

var SIZE = 100;
var line = new ctypes.char(SIZE);
var ret = fgets(line.address(), SIZE, myfile);   


Services.wm.getMostRecentWindow(null).alert(line);
Services.wm.getMostRecentWindow(null).alert(ret);

Results of this test:

  • newfile.in already exists and its contents is "ABC" no quotes
  • line - after running code line is set to "ctypes.char(65)" and 65 is character code of A but how do you read line?
  • ret - after running code ret is set to "ctypes.char.ptr(ctypes.UInt64("0x1e70e808"))" this also makes no sense to me how do you get a string out of this?

Then I changed some stuff up and made it my way but I'm having similar problems i cant read more than one character.

Cu.import("resource://gre/modules/ctypes.jsm");
var libc = ctypes.open("msvcrt.dll");


var struct_FILE = new ctypes.StructType("FILE"); //set to var only so can run multiple times in scratchpad, can change back to const
var fopen = libc.declare("fopen", // symbol name
    ctypes.default_abi, // cdecl calling convention
    struct_FILE.ptr, // return type (FILE*)
    ctypes.char.ptr, // first arg (const char*)
    ctypes.char.ptr); // second arg (const char*)

var fgetc = libc.declare("fgetc", // symbol name
    ctypes.default_abi, // cdecl calling convention
    ctypes.int.ptr, // return type (FILE*)
    struct_FILE.ptr); // second arg (const char*)

var fgets = libc.declare("fgets", // symbol name
    ctypes.default_abi, // cdecl calling convention
    ctypes.jschar.ptr, // return char pointer
    ctypes.jschar.ptr, // first arg char pointer
    ctypes.int, //second arg int
    struct_FILE.ptr); // third arg FILE pointer

var myfile = fopen("C:\\Users\\3K2KYC1\\Desktop\\FirefoxPortable\\newfile.in", "r");
//Services.wm.getMostRecentWindow(null).alert(myfile);



var line = new ctypes.jschar;
var ret = fgets(line.address(), 2, myfile);

Services.wm.getMostRecentWindow(null).alert(line);
Services.wm.getMostRecentWindow(null).alert(ret);
  • newfile.in already exists and its contents is "ABC" no quotes
  • using size 2 as 2nd arg on line 30
  • line - is set to "ctypes.jschar("A")" no quotes, which is the first char in the file, but i said get 2 char why didnt it give first 2 chars if try 3 it gives something weird
  • ret - is set to "ctypes.jschar.ptr(ctypes.UInt64("0xfba2b32"))"

  • if use size of 3

  • line - "ctypes.jschar("\u4241")"
  • ret - "ctypes.jschar.ptr(ctypes.UInt64("0x8fefce8"))"
Noitidart
  • 35,443
  • 37
  • 154
  • 323