Как я могу передать данные MemoryStream неуправляемому C++ DLL с помощью P/Invoke

Я сделал чисто версию оболочки для встроенной системы, используя преимущества:

  • / usr / bin / dd SIGUSR1 для обработки сигналов.

    По сути, если вы отправите 'kill SIGUSR1 $ (pid_of_running_dd_process)', он выведет сводную информацию о скорости передачи и количестве передаваемых данных.

  • Фоновая обработка dd, а затем регулярный запрос его на наличие обновлений и генерация тиковых хешей, как раньше использовали старые ftp-клиенты.

  • Использование / dev / stdout в качестве места назначения для дружественных к stdout программ, таких как scp

Конечный результат позволяет вам выполнить любую операцию передачи файла и получить обновление прогресса, которое Похоже на старый хеш-вывод FTP, где вы просто получите хеш-метку для каждого X байтов.

Это едва ли код качества производства, но вы поняли идею. Я думаю, что это мило.

Для чего бы это ни стоило, фактическое количество байтов может не отражаться правильно в количестве хэшей - у вас может быть один больше или меньше в зависимости от проблем округления. Не используйте это как часть тестового сценария, это просто конфетка. И, да, я знаю, что это ужасно неэффективно - это сценарий оболочки, и я не извиняюсь за это.

Примеры с wget, scp и tftp в конце. Он должен работать со всем, что имеет данные. Обязательно используйте / dev / stdout для программ, которые не подходят для stdout.

#!/bin/sh
#
# Copyright (C) Nathan Ramella (nar+progress-script@remix.net) 2010 
# LGPLv2 license
# If you use this, send me an email to say thanks and let me know what your product
# is so I can tell all my friends I'm a big man on the internet!

progress_filter() {

        local START=$(date +"%s")
        local SIZE=1
        local DURATION=1
        local BLKSZ=51200
        local TMPFILE=/tmp/tmpfile
        local PROGRESS=/tmp/tftp.progress
        local BYTES_LAST_CYCLE=0
        local BYTES_THIS_CYCLE=0

        rm -f ${PROGRESS}

        dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

        # Loop while the 'dd' exists. It would be 'more better' if we
        # actually looked for the specific child ID of the running 
        # process by identifying which child process it was. If someone
        # else is running dd, it will mess things up.

        # My PID handling is dumb, it assumes you only have one running dd on
        # the system, this should be fixed to just get the PID of the child
        # process from the shell.

        while [ $(pidof dd) -gt 1 ]; do

                # PROTIP: You can sleep partial seconds (at least on linux)
                sleep .5    

                # Force dd to update us on it's progress (which gets
                # redirected to $PROGRESS file.
                # 
                # dumb pid handling again
                pkill -USR1 dd

                local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
                local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

                # Don't print anything unless we've got 1 block or more.
                # This allows for stdin/stderr interactions to occur
                # without printing a hash erroneously.

                # Also makes it possible for you to background 'scp',
                # but still use the /dev/stdout trick _even_ if scp
                # (inevitably) asks for a password. 
                #
                # Fancy!

                if [ $XFER_BLKS -gt 0 ]; then
                        printf "#%0.s" $(seq 0 $XFER_BLKS)
                        BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
                fi
        done

        local SIZE=$(stat -c"%s" $TMPFILE)
        local NOW=$(date +"%s")

        if [ $NOW -eq 0 ]; then
                NOW=1
        fi

        local DURATION=$(($NOW-$START))
        local BYTES_PER_SECOND=$(( SIZE / DURATION ))
        local KBPS=$((SIZE/DURATION/1024))
        local MD5=$(md5sum $TMPFILE | awk '{ print $1 }')

        # This function prints out ugly stuff suitable for eval() 
        # rather than a pretty string. This makes it a bit more 
        # flexible if you have a custom format (or dare I say, locale?)

        printf "\nDURATION=%d\nBYTES=%d\nKBPS=%f\nMD5=%s\n" \
            $DURATION \
            $SIZE \
            $KBPS \
            $MD5
}

Примеры:

echo "wget"
wget -q -O /dev/stdout http://www.blah.com/somefile.zip | progress_filter

echo "tftp"
tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter

echo "scp"
scp user@192.168.1.1:~/myfile.tar /dev/stdout | progress_filter
9
задан 28 June 2009 в 01:47
поделиться

1 ответ

Если он просто ожидает байтов, вы можете прочитать MemoryStream в байтовый массив, а затем передать указатель на него методу.

Вы должны объявить внешний метод:

[DllImport("mylibrary.dll", CharSet = CharSet.Auto)]
public static extern bool doSomething(IntPtr rawData, int dataLength);

Затем , считайте байты из MemoryStream в массив байтов. Выделите GCHandle , который:

После выделения вы можете использовать GCHandle чтобы предотвратить управляемый объект собираются мусором коллектор, когда неуправляемый клиент содержит единственную ссылку. Без таких ручка, объект можно собрать сборщиком мусора перед завершая свою работу от имени неуправляемый клиент.

И, наконец, используйте метод AddrOfPinnedObject, чтобы получить IntPtr для передачи в dll C ++.

private void CallTheMethod(MemoryStream memStream)
{
   byte[] rawData = new byte[memStream.Length];
   memStream.Read(rawData, 0, memStream.Length);

   GCHandle rawDataHandle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
   IntPtr address = handle.AddrOfPinnedObject ();

   doSomething(address, rawData.Length);
   rawDataHandle.Free();
 }
13
ответ дан 4 December 2019 в 15:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: