我有一个非线程安全的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));