首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将stdole.stdPicture转换为C#中的.net映像?

如何将stdole.stdPicture转换为C#中的.net映像?
EN

Stack Overflow用户
提问于 2022-03-08 15:09:29
回答 1查看 242关注 0票数 1

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

问题是我也想传输exchange用户的图片,但是exchUser.GetPicture()返回一个stdole.stdPicture,我还没有找到一个下载或转换成一个映像/jpg/.

在这里,从全局地址列表中获取exchange用户的代码:

代码语言:javascript
运行
复制
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的转换,它返回位图,但IPuctureDisp和stdPicture与我在某个地方看到的不一样。

代码语言:javascript
运行
复制
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或将其转换为能够下载吗?

EN

Stack Overflow用户

回答已采纳

发布于 2022-03-08 15:48:26

完成这项工作的方法主要有四种。

“传统”方法是在GetIPictureDispFromPicture类中使用System.Windows.Forms.AxHostGetPictureFromIPicture方法。它们都是类的受保护成员,因此不能在外部使用它们。因此,通常会对AxHost类进行子类并公开内部调用基类受保护方法的公共方法。这种方法允许您在两个方向进行转换:

代码语言:javascript
运行
复制
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。这里有一篇关于这个主题的支持文章。OleLoadPicture创建一个新的图片对象,并从流的内容中初始化它。

代码语言:javascript
运行
复制
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选项卡上(它驻留在Add References对话框中)。然后,您可以在ImageToIPictureDisp类中使用SupportIPictureDispToImage方法。这显然是迄今为止最简单的方法,尽管它确实引入了VB6兼容性DLL。在内部,VB6兼容性代码看起来很像上面的第二个选项--使用OleCreatePictureIndirect

代码语言:javascript
运行
复制
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,但这并不能帮助您向相反的方向转换,这是很好的。下面的实现依赖于图像实际上是派生的位图类型,因为我们在内部调用Bitmap.GetHbitmap。如果您想保持对泛型Image类型的支持,那么您将不得不做更多的工作来对一堆无文档的GDI方法进行p/调用

代码语言:javascript
运行
复制
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
}
票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71397239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档