如何在C#中将stdole.stdPicture转换为.net映像



我正在为Outlook构建一个外接程序,将所有exchange用户从全局地址列表复制到本地联系人。

问题是我也想传输交换用户的图片,但exchUser.GetPicture()返回一个stdole.stdPicture,我还没有找到一个有效的解决方案来下载或将其转换为图像.jpg。。。

这里的代码,以获得交换用户从全球地址列表:

private void EnumerateGAL()
{
Outlook.AddressList gal = Application.Session.GetGlobalAddressList(); 
if (gal != null) 
{
for (int i = 1; i <= gal.AddressEntries.Count - 1; i++)
{
Outlook.AddressEntry addrEntry = gal.AddressEntries[i];
Outlook.ExchangeUser exchUser = addrEntry.GetExchangeUser();

if (addrEntry.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry
&& exchUser.CompanyName == "")
{
CreateContact(exchUser);
//exchUser.GetPicture() returns stdole.stdPicture
}
}
}
return;
}

我找到的最接近的解决方案是转换stdole。IPictureDisp返回一个位图,但IPstructureDisp和stdPicture与我在某处读取的不同。

public static System.Drawing.Image ConvertPicture(stdole.IPictureDisp image)
{
int type = image.Type;
if (type == 1)
{
IntPtr hPal = (IntPtr)image.hPal;
return Image.FromHbitmap((IntPtr)image.Handle, hPal);
}
return null;
}

最后我需要下载图片,因为我只能将图片上传到有路径的联系人。那么,有没有一种方法可以下载stdPicture或将其转换为能够下载?

完成任务的主要方法有四种。

";传统的";方法是在System.Windows.Forms.AxHost类中使用GetIPictureDispFromPictureGetPictureFromIPicture方法。这两个都是受保护的类成员,因此不能在外部使用它们。出于这个原因,AxHost类的子类和公开内部调用基类保护方法的公共方法是很常见的。这种方法允许您双向转换:

internal class AxHostConverter : AxHost
{
private AxHostConverter() : base("") { }
static public stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
static public Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPicture(pictureDisp);
}
}

第二种选择是使用OleLoadPictureOleCreatePictureIndirect。这里有一篇关于这个话题的支持文章。CCD_ 8创建一个新的图片对象并根据流的内容对其进行初始化。

internal class OleCreateConverter
{
[DllImport("oleaut32.dll", EntryPoint = "OleCreatePictureIndirect",
CharSet = CharSet.Ansi, ExactSpelling = true, PreserveSig = true)]
private static extern int OleCreatePictureIndirect(
[In] PictDescBitmap pictdesc, ref Guid iid, bool fOwn,
[MarshalAs(UnmanagedType.Interface)] out object ppVoid);
const short _PictureTypeBitmap = 1;
[StructLayout(LayoutKind.Sequential)]
internal class PictDescBitmap
{
internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PictDescBitmap));
internal int pictureType = _PictureTypeBitmap;
internal IntPtr hBitmap = IntPtr.Zero;
internal IntPtr hPalette = IntPtr.Zero;
internal int unused = 0;
internal PictDescBitmap(Bitmap bitmap)
{
this.hBitmap = bitmap.GetHbitmap();
}
}
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
if (image == null || !(image is Bitmap))
{
return null;
}
PictDescBitmap pictDescBitmap = new PictDescBitmap((Bitmap)image);
object ppVoid = null;
Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;
OleCreatePictureIndirect(pictDescBitmap, ref iPictureDispGuid, true, out ppVoid);
stdole.IPictureDisp picture = (stdole.IPictureDisp)ppVoid;
return picture;
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
Image image = null;
if (pictureDisp != null && pictureDisp.Type == _PictureTypeBitmap)
{
IntPtr paletteHandle = new IntPtr(pictureDisp.hPal);
IntPtr bitmapHandle = new IntPtr(pictureDisp.Handle);
image = Image.FromHbitmap(bitmapHandle, paletteHandle);
}
return image;
}
}

您的第三个选择是使用VB6兼容性库,这里有介绍。要使用它,您需要添加对Microsoft.VisualBasic.Compatibility.dll的引用,该引用列在Add References对话框的.NET选项卡上(它位于GAC中(。然后,可以在Support类中使用ImageToIPictureDispIPictureDispToImage方法。这显然是迄今为止最简单的方法,尽管它确实引入了VB6兼容性DLL。在内部,VB6兼容性代码看起来很像上面的第二个选项——使用OleCreatePictureIndirect

using Microsoft.VisualBasic.Compatibility.VB6;
internal class VB6CompatibilityConverter
{
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)Support.ImageToIPictureDisp(image);
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return Support.IPictureDispToImage(pictureDisp);
}
}

最后,您可以自己实现IPictureDispIPicture。如果您只想从图像转换为IPictureDisp,这很好,但对向其他方向转换没有帮助。下面的实现依赖于Image实际上是派生的位图类型,因为我们在内部调用Bitmap.GetHbitmap。如果你想保持对通用Image类型的支持,你必须做更多的工作来对一堆未记录的GDI方法进行p/invoke,而不是

internal class PictureDispConverter
{
public static stdole.IPictureDisp BitmapToPictureDisp(Bitmap bitmap)
{
return new PictureDispImpl(bitmap);
}

public static Image PictureDispToBitmap(stdole.IPictureDisp pictureDisp)
{
// TODO
return null;
}
}
internal class PictureDispImpl : stdole.IPictureDisp, stdole.IPicture
{
#region Init
[DllImport("gdi32.dll")]
static extern void DeleteObject(IntPtr handle);
private Bitmap _image;
private IntPtr _handle;

public PictureDispImpl(Bitmap image)
{
_image = image;
}

~PictureDispImpl()
{
if (_handle != IntPtr.Zero)
{
DeleteObject(_handle);
}
}
#endregion
#region IPictureDisp Members
public int Width
{
get { return _image.Width; }
}
public int Height
{
get { return _image.Height; }
}
public short Type
{
get { return 1; }
}
public int Handle
{
get
{
if (_handle == IntPtr.Zero)
{
_handle = _image.GetHbitmap();
}
return _handle.ToInt32();
}
}

public int hPal
{
get { return 0; }
set { }
}

public void Render(
int hdc, int x, int y, int cx, int cy, int xSrc, int ySrc, int cxSrc, int cySrc, IntPtr prcWBounds)
{
Graphics graphics = Graphics.FromHdc(new IntPtr(hdc));
graphics.DrawImage(
_image, new Rectangle(x, y, cx, cy), xSrc, ySrc, cxSrc, cySrc, GraphicsUnit.Pixel);
}

#endregion
#region IPicture Members

public int Attributes
{
get { return 0; }
}
public int CurDC
{
get { return 0; }
}
public bool KeepOriginalFormat
{
get { return false; }
set { }
}

public void PictureChanged()
{
}

public void SaveAsFile(IntPtr pstm, bool fSaveMemCopy, out int pcbSize)
{
pcbSize = 0;
}
public void SelectPicture(int hdcIn, out int phdcOut, out int phbmpOut)
{
phdcOut = 0;
phbmpOut = 0;
}
public void SetHdc(int hdc)
{
}
#endregion
}

最新更新