5

I am attempting to write a native Node addon that enumerates all windows on a Windows machine and returns an array of their titles to JS userland.

However I am stumped by this error:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(655): error C3074: an array cannot be initialized with a parenthesized initializer [C:\xampp\htdocs\enum-windows\build\enumWindows.vcxproj]

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,char(&)[255]>(_Objty (*),char (&)[255])' being comp iled with [ _Ty=char [255], _Objty=char [255] ]

To my knowledge I am not performing a parenthesised initialisation of an array?

#include <vector>
#include <node.h>
#include <v8.h>
#include <windows.h>
#include <stdio.h>

using namespace node;
using namespace v8;

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM ptr) {
    std::vector<char[255]>* windowTitles =
        reinterpret_cast<std::vector<char[255]>*>(ptr);

    if (IsWindowVisible(hWnd)) {
        int size = GetWindowTextLength(hWnd);
        char buff[255];
        GetWindowText(hWnd, (LPSTR) buff, size);
        windowTitles->push_back(buff);
    }

    return true;
};

void GetWindowTexts(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);
    Local<Array> arr = Array::New(isolate);
    std::vector<char[255]> windowTitles;

    EnumWindows(
        &EnumWindowsProc, 
        reinterpret_cast<LPARAM>(&windowTitles));

    for (unsigned int i = 0; i < windowTitles.size(); i++) {
        const char* ch = reinterpret_cast<const char*>(windowTitles.at(i));
        Local<String> str = String::NewFromUtf8(isolate, ch);
        arr->Set(i, str);
    }

    args.GetReturnValue().Set(arr);
}

void init(Handle<Object> exports, Handle<Object> module) {
    NODE_SET_METHOD(module, "exports", GetWindowTexts);
}

NODE_MODULE(enumWindows, init);

I believe the error has something to do with this line:

windowTitles->push_back(buff);

Perhaps my approach is naive.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
  • I'm not familiar with Visual Studio, but I believe it shall print the error with the line number, so that you can be *sure* which line causes the error. – Mine Jun 23 '16 at 13:13
  • 1
    I'd recommend a vector of `std::string`. `&s[0]` can be safely used in C++11 to make a string's data writable. Also, casts to `LPSTR` look very suspicious. In your case, the cast is doing nothing. – chris Jun 23 '16 at 13:13
  • `const char* ch = reinterpret_cast(windowTitles.at(i));` looks ok. I've found that you can see which line is causing the template instantiation error by checking the following compiler errors. So it will start with xmemory as in this case, then it should be followed by another line for perhaps another standard library, but eventually you will get a line number in one of your source files. Just keep reading. Once you see the line it becomes easier. – wally Jun 23 '16 at 13:18
  • Looks like the problem is in `windowTitles->push_back(buff);` – wally Jun 23 '16 at 13:26
  • @flatmouse After looking at the stack trace more closely, you are correct. – sdgluck Jun 23 '16 at 13:27
  • @chris I removed the cast to LSPTR and its absence hasn't caused any extra issues. Thanks! – sdgluck Jun 23 '16 at 13:29

1 Answers1

12

The problem arises here:

windowTitles->push_back(buff);

Because you cannot store an array in std::vector.

From the linked answer:

The objects stored by a standard library container must be copyable and assignable, and arrays are neither of these.

Perhaps use something like the following. The array has been replaced with std::array<char,255>:

BOOL CALLBACK EnumWindowsProc(HWND hWnd,LPARAM ptr)
{
    std::vector<std::array<char,255>>* windowTitles =
        reinterpret_cast<std::vector<std::array<char,255>>*>(ptr);

    if (IsWindowVisible(hWnd)) {
        int size = GetWindowTextLength(hWnd);
        std::array<char,255> buff;
        GetWindowText(hWnd,(LPWSTR)buff.data(),size);
        windowTitles->push_back(buff);
    }

    return true;
};
Community
  • 1
  • 1
wally
  • 10,717
  • 5
  • 39
  • 72
  • I had to cast to `LPSTR` rather than `LPWSTR`. And now it produces an array of window titles, however some are truncated. But it's progress! Thank you kindly. – sdgluck Jun 23 '16 at 14:21
  • 1
    You're very welcome. I had unicode turned on, but I forgot I changed to `LPWSTR` to test. – wally Jun 23 '16 at 14:25