簡體   English   中英

如何讀取 C++ SAFEARRAY**,它是來自 COM 互操作的結果,其中 C# 返回值為 byte[]?

[英]How to read a C++ SAFEARRAY** that is a Result from a COM interop where the C# return value was byte[]?

我創建了一個 C# DLL,它使用 Zebra Crossing Nuget 包 (ZXing.Net.Bindings.CoreCompat.System.Drawing) 來創建 QR 圖像。

C#方法的簽名是:

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

我已經成功地在 C# 控制台應用程序中使用它來創建各種二維碼,其中我將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();
            }
        }
    }

只需使用SafeArrayAccessData來獲取返回的數據的 prointer。 檢查類型,應該是VT_BYTE

你得到大小(尺寸) SafeArrayGetDimSafeArrayGetLBoundSafeArrayGetUBound

在我看來,這里有兩個主要問題:

  1. 您不能在 COM 互操作方案中使用 ZXing.Net.Bindings.CoreCompat.System.Drawing,因為 .Net Standard 2.0 的 CoreCompat.System.Drawing V2 程序集未簽名。 如果您檢查調用 pICalc->CreateQrCode(...) 的 HRESULT 返回值,您將看到值 0x80131044。 如果您真的想使用 CoreCompat.System.Drawing,則必須使用自己的密鑰對其進行簽名,並針對您的 CoreCompat.System.Drawing 版本構建新版本的 ZXing.Net.Bindings.CoreCompat.System.Drawing。 或者,您可以針對 .Net Standard 1.3 定位您的程序集,因為舊版本 CoreCompat.System.Drawing V1 已簽名。 但我沒有嘗試。 就我而言,我使用完整框架 4.6.1 和本機框架的位圖功能直接針對 ZXing.Net 檢查了您的代碼。

  2. 我必須按以下方式修改您的代碼:

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

    這就是在這種情況下如何使用指向指針的指針的方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM