C#使用AppDomain或Process多次加载非线程安全的DLL

时间:2018-03-10 17:46:22

标签: c# multithreading visual-studio process appdomain

我有一个非线程安全的DLL,它包含静态方法和数据。我需要从不同的对象调用它的方法,并且可能是线程保持一切分开。谷歌说我必须创建不同的AppDomain(在这种情况下,每个对象调用DLL一个)或创建一个新的进程。真的吗?如果是,哪一个是最佳解决方案,我该如何实际做到这一点?如果没有,还有其他解决方案吗?

另外,我有一个Form实例化使用DLL的类,我需要能够从Form访问类中的方法。我能做到吗?

为了更清楚,我发布了一些代码 DLL导入如下:

namespace ASCOM.QHYCCD
{
    public class libqhyccd
    {
        [DllImport("import/qhyccd.dll", EntryPoint = "InitQHYCCDResource",
            CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public unsafe static extern UInt32 InitQHYCCDResource();

        [DllImport("import/qhyccd.dll", EntryPoint = "GetQHYCCDSingleFrame",
        CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public unsafe static extern UInt32 GetQHYCCDSingleFrame(IntPtr handle, ref UInt32 w, ref UInt32 h, ref UInt32 bpp, ref UInt32 channels, byte* rawArray);
        public unsafe static UInt32 C_GetQHYCCDSingleFrame(IntPtr handle, ref UInt32 w, ref UInt32 h, ref UInt32 bpp, ref UInt32 channels, byte[] rawArray)
        {
            UInt32 ret;
            fixed(byte* prawArray = rawArray)
                ret = GetQHYCCDSingleFrame(handle, ref w, ref h, ref bpp, ref channels, prawArray);
            return ret;
        }

        // a lot more stuff like this

    }
}

这是班级:

class QHYCamera
{
    public static IntPtr handler;
    private bool isConnected = false;
    uint width, height, bpp, channels;
    double chipw, chiph, pixelw, pixelh;
    byte[] rawArray;
    uint arrayLength;

    public QHYCamera(){}

    public void Connect(int index, string strid)
    {
        if (!isConnected)
        {
            //ASCOM.QHYCCD.libqhyccd.InitQHYCCDResource();
            StringBuilder id = new StringBuilder(strid);
            //ASCOM.QHYCCD.libqhyccd.GetQHYCCDId(index, id);
            handler = ASCOM.QHYCCD.libqhyccd.OpenQHYCCD(id);
            Console.WriteLine(handler.ToString());
            ASCOM.QHYCCD.libqhyccd.SetQHYCCDStreamMode(handler, 0);
            ASCOM.QHYCCD.libqhyccd.InitQHYCCD(handler);
            ASCOM.QHYCCD.libqhyccd.GetQHYCCDChipInfo(handler, ref chipw, ref chiph, ref width, ref height, ref pixelw, ref pixelh, ref bpp);
            ASCOM.QHYCCD.libqhyccd.SetQHYCCDBinMode(handler, 1, 1);
            ASCOM.QHYCCD.libqhyccd.SetQHYCCDResolution(handler, 0, 0, width, height);
            arrayLength = ASCOM.QHYCCD.libqhyccd.GetQHYCCDMemLength(handler);
            rawArray = new byte[arrayLength];
            isConnected = true;
        }
    }

    public void Disconnect()
    {
        if (isConnected)
        {
            ASCOM.QHYCCD.libqhyccd.CloseQHYCCD(handler);
            ASCOM.QHYCCD.libqhyccd.ReleaseQHYCCDResource();
            isConnected = false;
        }
    }

    public bool IsConnected()
    {
        return isConnected;
    }

    public Dictionary<string, int> GetAvailableCameras()
    {
        Dictionary<string, int> index_id = new Dictionary<string, int>();
        for (int i = 0; i < ASCOM.QHYCCD.libqhyccd.ScanQHYCCD(); i++)
        {
            StringBuilder id = new StringBuilder(200);
            ASCOM.QHYCCD.libqhyccd.GetQHYCCDId(i, id);
            index_id.Add(id.ToString(), i);
        }
        return index_id;
    }

    public void SetExposure(double exposure)
    {
        if (ASCOM.QHYCCD.libqhyccd.SetQHYCCDParam(handler, StructModel.CONTROL_ID.CONTROL_EXPOSURE, exposure) == 1)
        {
            MessageBox.Show("Cannot set exposure", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    public void SetGain(double gain)
    {
        if (ASCOM.QHYCCD.libqhyccd.SetQHYCCDParam(handler, StructModel.CONTROL_ID.CONTROL_GAIN, gain) == 1)
        {
            MessageBox.Show("Cannot set exposure", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    public Task<Bitmap> GetBitmapAsync()
    {
        return Task.Run(() =>
        {
            return GetBitmap();
        });
    }

    public Bitmap GetBitmap()
    {
        ASCOM.QHYCCD.libqhyccd.SetQHYCCDBitsMode(handler, bpp);
        ASCOM.QHYCCD.libqhyccd.InitQHYCCD(handler);
        ASCOM.QHYCCD.libqhyccd.ExpQHYCCDSingleFrame(handler);

        uint ret = 1;
        while(ret != 0)
        {
            ret = ASCOM.QHYCCD.libqhyccd.C_GetQHYCCDSingleFrame(handler, ref width, ref height, ref bpp, ref channels, rawArray);
        }

        if (ret == 0)
        {
            Color[] palette = new Color[256];
            for (Int32 b = 0; b < 256; b++)
                palette[b] = Color.FromArgb(b, b, b);
            return BuildImage(rawArray, (int)width, (int)height, (int)width, PixelFormat.Format8bppIndexed, palette, null);
        }
        return default(Bitmap);
    }

    public static Bitmap BuildImage(Byte[] sourceData, Int32 width, Int32 height, Int32 stride, PixelFormat pixelFormat, Color[] palette, Color? defaultColor)
    {
        Bitmap newImage = new Bitmap(width, height, pixelFormat);
        BitmapData targetData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, newImage.PixelFormat);
        Int32 newDataWidth = ((Image.GetPixelFormatSize(pixelFormat) * width) + 7) / 8;
        Boolean isFlipped = stride < 0;
        stride = Math.Abs(stride);
        Int32 targetStride = targetData.Stride;
        Int64 scan0 = targetData.Scan0.ToInt64();
        for (Int32 y = 0; y < height; y++)
            Marshal.Copy(sourceData, y * stride, new IntPtr(scan0 + y * targetStride), newDataWidth);
        newImage.UnlockBits(targetData);
        if (isFlipped)
            newImage.RotateFlip(RotateFlipType.Rotate180FlipX);
        if ((pixelFormat & PixelFormat.Indexed) != 0 && palette != null)
        {
            ColorPalette pal = newImage.Palette;
            for (Int32 i = 0; i < pal.Entries.Length; i++)
            {
                if (i < palette.Length)
                    pal.Entries[i] = palette[i];
                else if (defaultColor.HasValue)
                    pal.Entries[i] = defaultColor.Value;
                else
                    break;
            }
            newImage.Palette = pal;
        }
        return newImage;
    }

}

从主窗体我只需要实例化该类,生成一个调用某些方法的新线程:

private void BackgroundPreviewHandler(QHYCamera camera)
{
     while (camera.IsConnected())
     {
         Bitmap bitmap = camera.GetBitmap();
         PictureBox1.Image = bitmap;
     }
}

private QHYCamera visibleCam = new QHYCamera();
private QHYCamera halphaCam = new QHYCamera();

await Task.Factory.StartNew(() => BackgroundPreviewHandler(visibleCam));
await Task.Factory.StartNew(() => BackgroundPreviewHandler(halphaCam));

0 个答案:

没有答案