I have a couple of questions here related to IIS and ActiveX controls.
I am developing an activeX control by this tutorial http://haseebakhtar.wordpress.com/2011/05/31/creating-an-activex-control-in-net-using-c/. I am using IE9 for its testing and VS 2010 as IDE. Here is the code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
namespace AxControls
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("42BBA00A-515E-45b5-9EAF-3827F7AEB4FA")]
[ProgId("AxControls.HelloWorld")]
[ComDefaultInterface(typeof(IClip))]
public class HelloWorld : UserControl, IObjectSafety, IClip
{
public HelloWorld()
{
MessageBox.Show("Starting");
}
[STAThread]
public Image GetClipboardImage()
{
MessageBox.Show("try to get image");
Image returnImage = null;
if (Clipboard.ContainsImage())
{
MessageBox.Show("getting image");
returnImage = Clipboard.GetImage();
}
return returnImage;
}
private void SaveImage(Image image)
{
try
{
if (image != null)
{
MessageBox.Show("saving image");
image.Save("C:\\test.jpg");
}
}
catch (Exception e)
{
MessageBox.Show(e.StackTrace);
}
}
public void SaveImgFromClipBoard()
{
Image img = GetClipboardImage();
SaveImage(img);
}
#region IObjectSafety Members
public enum ObjectSafetyOptions
{
INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
INTERFACE_USES_DISPEX = 0x00000004,
INTERFACE_USES_SECURITY_MANAGER = 0x00000008
};
public int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
{
ObjectSafetyOptions m_options = ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
pdwSupportedOptions = (int)m_options;
pdwEnabledOptions = (int)m_options;
return 0;
}
public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
{
return 0;
}
#endregion
}
}
Here is another code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace AxControls
{
[ComImport()]
[Guid("5DC2DE9B-8D7D-490e-A904-C8CBFFD38412")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IObjectSafety
{
[PreserveSig()]
int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions);
[PreserveSig()]
int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions);
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace AxControls
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("013BFB31-B3F8-4bae-B5C2-5F6D22B815E3")]
public interface IClip
{
void SaveImgFromClipBoard();
}
}
and that is how I call it:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace AxControls
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("013BFB31-B3F8-4bae-B5C2-5F6D22B815E3")]
public interface IClip
{
void SaveImgFromClipBoard();
}
}
1) So, when I am refreshing the page I see two message boxes with "Starting" and they appear one by another. I fail to see why. I run it in debug mode (using IIS of course + ASP.NET web project + HTML file inside it). That is my post build action
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x86\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
I even tried to use it on Apache Web Server - but had the same situation - constructor seems to invokes twice.
2) Many times when I am changing my HTML file in Visual Studio and run it in debug mode the changes is not visible in my Browser. I tried to clean IE history and cache with no success. Looks like IIS puts it in cache. Can it be? How can I avoid it?
3) I cannot understand the purpose of adding all that IObjectSafety Members.
UPDATE:
<html>
<head>
<object name="axHello" style='display:none' id='axHello' classid='CLSID:42BBA00A-515E-45b5-9EAF-3827F7AEB4FA'
codebase='AxControls.cab#version=1,0,0,0'></object>
<script language="javascript">
<!-- Load the ActiveX object -->
var x = new ActiveXObject("AxControls.HelloWorld");
<!-- Display the String in a messagebox ffff-->
x.SaveImgFromClipBoard();
</script>
</head>
<body>
</body>
</html>
Now that we've seen your HTML code, it's clear: you create two separate objects: one as object
tag, another one - dynamically - as new ActiveXObject("AxControls.HelloWorld")
. Remove the the second one, and just call:
axHello.SaveImgFromClipBoard();
Don't forget about my notes on IObjectSafety
in the comments. The best thing to do is to lock your control to your own site(s).
Regarding this: 2) Many times when I am changing my HTML file in Visual Studio and run it in debug mode the changes is not visible in my Browser. I tried to clean IE history and cache with no success. Looks like IIS puts it in cache. Can it be? How can I avoid it?
When it happens next time, close all IE windows, then use Process Explorer to check if there is a hidden iexplore.exe
process still hanging in. If so, kill it (all instances), then clear the cache. The next time it should load a fresh version of your page.
If that happens, it's actually a bad sign that your control doesn't shutdown properly (but that would be a subject for a separate question).