Как прочитать C ++ SAFEARRAY **, который является Результатом взаимодействия COM, где возвращаемое значение C# было байтом []? - PullRequest
0 голосов
/ 04 февраля 2020

Я создал C# DLL, которая использует пакет Zebra Crossing Nuget (ZXing. Net .Bindings.CoreCompat.System.Drawing), который создает изображение QR.

Подпись * Метод 1023 *:

public interface IWriter
{
    byte[] CreateQrCode(string content, int width, int height, string imageFormat);
};

, и я успешно использовал его в консольном приложении C# для создания различных QR-кодов, в которых я записываю возвращаемое значение byte[] на диск в виде изображения png файлы.

Естественно, чтобы я мог вызывать его из C ++, я установил флажок «Зарегистрироваться для взаимодействия COM» на экране «Свойства / Сборка» библиотеки, подписал сборку ключом надежного имени файла (без пароля). и создал следующее приложение C ++ в качестве проверки концепции, демонстрирующее, как его использовать:


#include <iostream>

#import "C:\Users\[PATH TO C# BUILD]\ImageGenerator\bin\Debug\ImageGenerator.tlb" raw_interfaces_only

using namespace ImageGenerator;

int main()
{
    HRESULT hr = CoInitialize(NULL);

    IWriterPtr pICalc(__uuidof(Writer));

    BSTR content = SysAllocString(L"http://www.google.com/");
    BSTR format = SysAllocString(L"png");

    const LONG width = 100;
    const LONG height = 100;

    const LONG count = width * height;

    SAFEARRAY** myArray = NULL;

    pICalc->CreateQrCode(content, width, height, format, myArray);
}

Как прочитать результат myArray, чтобы сохранить его в виде файла на диске?

Длина массива C# byte[] будет count.

Код библиотеки C# выглядит следующим образом:

using System;
using ZXing;
using System.Drawing;
using ZXing.QrCode;
using ZXing.CoreCompat.System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using BarcodeReader = ZXing.CoreCompat.System.Drawing.BarcodeReader;

namespace ImageGenerator
{

    public interface IWriter
    {
        byte[] CreateQrCode(string content, int width, int height, string imageFormat);
    };

    /// <summary>
    /// An Image Writer class that creates QR code images in a variety of image formats.
    /// </summary>
    public class Writer : IWriter
    {
        public Writer()
        {

        }

        /// <summary>
        /// Creates a QR Code in a specified image format, of width and height, returning it as byte[].
        /// </summary>
        /// <param name="content">The content that is to be represented by the QR Code.</param>
        /// <param name="width">The width of the image.</param>
        /// <param name="height">The Height of the image.</param>
        /// <param name="imageFormat">A text string representing the format of the image, options are png, bmp, emf, exif, gif, icon, jpeg, memorybmp, tiff, and wmf.</param>
        /// <returns></returns>
        public byte[] CreateQrCode(string content, int width, int height, string imageFormat)
        {
            ImageFormat format = ImageFormat.Png;

            switch(imageFormat.ToLower())
            {
                case "png":
                    format = ImageFormat.Png;
                    break;

                case "bmp":
                    format = ImageFormat.Bmp;
                    break;

                case "emf":
                    format = ImageFormat.Emf;
                    break;

                case "exif":
                    format = ImageFormat.Exif;
                    break;

                case "gif":
                    format = ImageFormat.Gif;
                    break;

                case "icon":
                    format = ImageFormat.Icon;
                    break;

                case "jpeg":
                    format = ImageFormat.Jpeg;
                    break;

                case "memorybmp":
                    format = ImageFormat.MemoryBmp;
                    break;

                case "tiff":
                    format = ImageFormat.Tiff;
                    break;

                case "wmf":
                    format = ImageFormat.Wmf;
                    break;
            }

            BarcodeWriter writer = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options = new QrCodeEncodingOptions
                {
                    Width = width,
                    Height = height,
                }
            };

            var qrCodeImage = writer.Write(content); // BOOM!!

            using (var stream = new MemoryStream())
            {
                qrCodeImage.Save(stream, format);
                return stream.ToArray();
            }
        }
    }

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

По моему мнению, здесь есть две основные проблемы:

  1. Вы не можете использовать ZXing. Net .Bindings.CoreCompat.System.Drawing в сценарии взаимодействия COM, потому что Сборка CoreCompat.System.Drawing V2 для. Net Стандарт 2.0 не подписан. Если вы проверите HRESULT, возвращаемое значение вызова pICal c -> CreateQrCode (...), вы увидите значение 0x80131044. Если вы действительно хотите использовать CoreCompat.System.Drawing, вы должны подписать его своим собственным ключом и создать новую версию ZXing. Net .Bindings.CoreCompat.System.Drawing против вашей версии CoreCompat.System.Drawing. В качестве альтернативы вы можете нацелить сборку на. Net Стандарт 1.3, поскольку более старая версия CoreCompat.System.Drawing V1 подписана. Но я не пробовал это. В моем случае я проверил ваш код непосредственно на ZXing. Net с полной версией 4.6.1 и функциональностью растрового изображения собственной платформы.

  2. Мне пришлось изменить ваш код в следующим образом:

    ...
        SAFEARRAY* myArray = NULL;
    
        pICalc->CreateQrCode(content, width, height, format, &myArray);
    }
    

    Именно так в этом случае используется указатель на указатель.

2 голосов
/ 04 февраля 2020

Просто используйте SafeArrayAccessData, чтобы получить указатель возвращаемых данных. Проверьте тип, должно быть VT_BYTE.

Вы получите размер (размеры) SafeArrayGetDim, SafeArrayGetLBound, SafeArrayGetUBound

...