VS2005でOCX上のアイコン背景色を透過させるには?

解決


ひば  2007-09-27 23:17:03  No: 137623

VB6で作成したOCXをVS2005で使用したいのですが、
VS2005上でアイコンイメージを読み込むと
透過色が紺色になって透過しません。
どうすれば透過色を使用したアイコンを描画できる
OCXを作成できるのでしょうか。

OCXのUserControl上にImageコントロールがあり、
Pictureプロパティを外だしにしてイメージを読み込んでいます。

よろしくお願いします。


魔界の仮面弁士  2007-09-28 06:36:45  No: 137624

> どうすれば透過色を使用したアイコンを描画できる
> OCXを作成できるのでしょうか。
VB6 ヘルプでいうところの「ShapeLabel コントロール」サンプルは、
VB2005 上でも、背景が透過しますよね?

VB6 ヘルプの下記の項を参照してみてください。

[Visual Basic ドキュメント]
└[Visual Basic の使用方法]
  └[コンポーネント ツール ガイド]
    └[ActiveX コンポーネントの作成方法]
      └[ActiveX コントロールの作成技術]
        └[Visual Basic ActiveX コントロールの機能]
          └[コントロールの透明な背景の設定]


ひば  2007-09-28 20:08:18  No: 137625

回答ありがとうございます。

> VB2005 上でも、背景が透過しますよね?

これは、コントロール自体のリージョンのようなものでしょうか。
コントロール自体の透過ではなく、Imageコントロールが読み込んだ
アイコンファイルの透過色の透過です。

問題を具体的な例で挙げますと…

1.VB6でActiveXコントロールのプロジェクトを作成する。
2.UserControlの背景色を(透過したかわかるように)赤にする。
3.ImageコントロールをUserControlにのせる
4.ImageコントロールのPictureプロパティを
  作成したActiveXコントロールのプロパティとして外にだす。

このようにして作成したActiveXコントロールをフォームに貼り付け
Pictureプロパティにアイコンファイルを指定します。

VB6では読み込んだアイコンファイルの透過色は透過して
Imageコントロールの下のUserControlの背景色が見えます。

VS2005では透過色が透過しません。紺色になってしまいます。


魔界の仮面弁士  2007-09-28 21:47:26  No: 137626

あぁ、そういう事ですか。

.NET から COM へのやりとりの際に、どうやらアイコンが
ビットマップに変換されてしまっているようですね。

img = Image.FromFile(strFilePath)
If img.RawFormat.Guid = Imaging.ImageFormat.Icon.Guid Then
    MsgBox("これはアイコンです")
End If

AxSampleControl1.Picture = img
img = AxSampleControl1.Picture

If img.RawFormat.Guid = Imaging.ImageFormat.MemoryBmp.Guid Then
    MsgBox("これはメモリビットマップです")
End If

VB6 の場合、 Form.Icon も Form.Picture も「Picture型」ですが、
.NET では、Form.Icon は「Icon 型」、Form.BackgroundImage は「Image 型」ですね。

しかも .NET の Icon クラスは、Image クラスを継承していません。
ところが、Picture 型をそのまま公開した場合、Image 型にマッピングされます。
理由はよくわかりませんが、このあたりの事情が絡んでいるのでしょう。

===================
で。対応策としては、VB6 側で「System.Drawing.Icon 型を渡すためのメンバ」を、
別途用意することなのでしょうけれども……それは難しそうなので、

(案1) アンマネージの Picture オブジェクトのままでやりとりする。
(案2) ファイル名またはバイナリを渡すようにして、VB6 側で Picture を生成する。

といったところで如何でしょう。これなら、Icon の背景もきちんと透過するかと。

とりあえず、案1 の実装例を。

------《VB6》-------
Option Explicit

Public Property Get Picture() As Picture
    Set Picture = UserControl.Picture
End Property

Public Property Set Picture(ByVal New_Picture As Picture)
    Set UserControl.Picture = New_Picture
    PropertyChanged "Picture"
End Property

Public Property Get AxPicture() As Object
    Set AxPicture = Me.Picture
End Property

Public Property Set AxPicture(ByVal New_AxPicture As Object)
    Set Me.Picture = New_AxPicture
End Property

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    Set Picture = PropBag.ReadProperty("Picture", Nothing)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    Call PropBag.WriteProperty("Picture", Picture, Nothing)
End Sub

------ 《VB2005》 -------
Const vbPicTypeBitmap As Integer = 1
Const vbPicTypeIcon As Integer = 3

Dim oIcon As New Icon(strFilePath)
Dim inPic As Object, outPic As Object

inPic = Microsoft.VisualBasic.Compatibility.VB6.Support.IconToIPicture(oIcon)
If inPic.Type = vbPicTypeIcon Then
    MsgBox("これはアイコン")
End If

AxSampleControl1.AxPicture = inPic

' Icon のまま保持されているか確認
outPic = AxSampleControl1.AxPicture
If outPic.Type = vbPicTypeBitmap Then
    MsgBox("これはビットマップ")
ElseIf outPic.Type = vbPicTypeIcon Then
    MsgBox("これはアイコン")
End If


魔界の仮面弁士  2007-09-28 23:06:12  No: 137627

おっとっと、VB6 側の変更は一切不要でした。
.NET 側の処理を変更してやるだけで対応できそうです。

《修正前》
AxSampleControl1.Picture = Image.FromFile(strFilePath)

《修正後》
AxSampleControl1.GetOcx().Picture = Microsoft.VisualBasic.Compatibility.VB6.Support.IconToIPicture(New System.Drawing.Icon(strFilePath))

# 問題があるのは、VS が自動生成する「AxInterop.SampleProject.dll」の
# 相互運用アセンブリなので、この DLL を手直しするのも手かも。


ひば  2007-09-29 00:57:56  No: 137628

ありがとうございました。
VB2005では確認できました。
プロパティウィンドウからでは難しそうですね。

この場での質問でないかもしれませんが、すみません。
C#2005の場合、ビルドでエラーになります。
(object型にPictureプロパティが無いため)
どのようにキャストしたらよいのでしょうか。


魔界の仮面弁士  2007-09-29 01:55:34  No: 137629

> プロパティウィンドウからでは難しそうですね。
AxInterop.SampleProject.dll を修正するか、または、
SampleControl を継承して、Icon プロパティを追加すれば OKOK。

IPicture を公開するレガシーコントロールが他にもあるのなら、
いっそのこと、プロパティ設定用の拡張プロバイダを作ると便利かも。
http://msdn2.microsoft.com/ja-jp/library/d6c1xa43%28VS.80%29.aspx

> C#2005の場合、ビルドでエラーになります。
C# ではレイトバインドをサポートしていないので、System.Reflection で
対応するか……あるいは、適切な型へのキャストが必要でしょうね。

> どのようにキャストしたらよいのでしょうか。
板違いにならないように、VBのコードで説明。

Option Strict On
Imports AxSampleProject, SampleProject, stdole
Imports Microsoft.VisualBasic.Compatibility.VB6
Public Class Form1
    Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
        DirectCast(AxSampleControl1.GetOcx(), _SampleControl).Picture = _
            DirectCast(IconToIPicture(Me.Icon), StdPicture)
    End Sub
End Class


ひば  2007-09-29 02:43:32  No: 137630

まずはImageListからアイコンを取り出して
ロード時に設定するようにしました。

とても助かりました。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加