Gerrit Niezen


This is a follow-on to Part 1 and Part 2 of my adventures in connecting to Android devices over MTP using Node.js, on Windows.

While compiling the Node.js native module, I got the following error:

Macro definition of snprintf conflicts with Standard Library function declaration

Searching StackOverflow led to this solution, which I added to the libmtp source code:

#if _MSC_VER < 1900
#define snprintf _snprintf

I also kept on getting a “Module not found” error, until I re-read my own post and used Dependency Walker to figure out that for some reason my .node file is looking for libmtp-9.dll.dll instead of libmtp-9.dll. 🤷‍♂️️ I also had to copy libusb-1.0.dll into the same folder, as it was looking for that too.

Finally, like magic, I was able to connect to a device on Windows over MTP with my own Node.js library using libmtp, instead of the Windows MTP implementation that can only be accessed through Windows Explorer or the Windows APIs.

And I just submitted a PR to get Windows builds fixed in the upstream libmtp library.

Next step: Getting it compiled for 32-bit Windows using i686-w64-mingw32 and/or i686-mingw32

I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting

#100DaysToOffload #day34 #libmtp #Node.js

So even though I managed to get libmtp compiled under Windows, I can't get it to work with Node.js. I've decided to take the same approach as what I did with ffmpeg's libavutil library, and cross-compile it under Linux instead.

To do this, I needed mingw64 on my Linux machine:

sudo apt-get install mingw-w64
sudo apt-get install mingw-w64-tools

It doesn't look like libusb has been pre-compiled for mingw64 on Linux, so I had to do the following:

git clone
 git checkout v1.0.23
./configure --host=x86_64-w64-mingw32
DESTDIR=$HOME/Code/mingw64/ make install

This installs the libusb library (compiled for Windows) under $HOME/Code/mingw64/. Then I had to configure libmtp to use our Windows libusb build:

PKG_CONFIG_PATH=$HOME/Code/mingw64/usr/local/lib/pkgconfig  ./configure --host=x86_64-w64-mingw32

Again I had to fix unicode.c to get it working. I should submit this work as a PR to libmtp.

Next step: Try to get this working in as a native Node.js addon.

For reference:

I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting

#100DaysToOffload #day33 #libmtp

A couple of days ago I mentioned that I'm attempting to compile libmtp under MSYS2/MINGW64. Steps so far:

  • Install MSYS2
  • Do pacman -Syuu repeatedly after first start until everything is up to date
  • Install git: pacman -S git
  • Install base-devel for basic development utilities
  • install mingw-w64-x86_64-toolchain (as we need mingw-w64-x86_64-gcc to not get _spawnv errors, see
  • Install mingw-w64-x86_64-libiconv
  • Install mingw-w64-x86_64-libusb
  • Remember to run before running ./configure
  • Run make

Some useful MSYS2-specific things:

  • Use cd /c/ to get to the C: drive
  • pacman -S to install, -R to remove and -Ss to search
  • To access Windows path (e.g. to run node/npm, which can't be installed in MSYS2), add -use-full-path to the mingw64 app shortcut, or set environment variable MSYS2_PATH_TYPE to inherit

Now, after all of this I still got the following error:

unicode.c: In function 'utf16_to_utf8':
unicode.c:91:23: error: 'PTPParams' {aka 'struct _PTPParams'} has no member named 'cd_ucs2_to_locale'
   91 |   nconv = iconv(params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax);
      |                       ^~
unicode.c: In function 'utf8_to_utf16':
unicode.c:126:23: error: 'PTPParams' {aka 'struct _PTPParams'} has no member named 'cd_locale_to_ucs2'
  126 |   nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen, &unip, &convmax);

Turns out, it's a known issue. Based on a potential fix linked to in that GitHub issue, I was able to write a fix for a different file:

diff --git a/src/unicode.c b/src/unicode.c
index 2adc94e..b14274b 100644
--- a/src/unicode.c
+++ b/src/unicode.c
@@ -87,12 +87,14 @@ char *utf16_to_utf8(LIBMTP_mtpdevice_t *device, const uint16_t *unicstr)
   size_t convmax = STRING_BUFFER_LENGTH*3;

+  #if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
   /* Do the conversion.  */
   nconv = iconv(params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax);
   if (nconv == (size_t) -1) {
     // Return partial string anyway.
     *locp = '\0';
+  #endif
   loclstr[STRING_BUFFER_LENGTH*3] = '\0';
   // Strip off any BOM, it's totally useless...
   if ((uint8_t) loclstr[0] == 0xEFU && (uint8_t) loclstr[1] == 0xBBU && (uint8_t) loclstr[2] == 0xBFU) {
@@ -121,7 +123,7 @@ uint16_t *utf8_to_utf16(LIBMTP_mtpdevice_t *device, const char *localstr)

+  #if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
   /* Do the conversion.  */
   nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen, &unip, &convmax);

@@ -130,6 +132,7 @@ uint16_t *utf8_to_utf16(LIBMTP_mtpdevice_t *device, const char *localstr)
     unip[0] = '\0';
     unip[1] = '\0';
+  #endif
   // make sure the string is null terminated
   unicstr[STRING_BUFFER_LENGTH*2] = '\0';
   unicstr[STRING_BUFFER_LENGTH*2+1] = '\0';

Lo and behold, I got it to compile!

I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting

#100DaysToOffload #day26 #libmtp