非托管代码调用托管代码适用于开发计算机,而不是部署计算机
我正在构建一个基于 VideoRendererElement 项目 (http://videorendererelement.codeplex.com/) 的网络摄像头应用程序,该项目使用 DirectShowLib 和 Interop 以及非托管 activex 组件。我正在使用 Visual Studio 2010,但目标是 .NET 3.5(2.0 clr 运行时)。
我已经能够在我的开发计算机上构建并运行该应用程序,没有任何问题(甚至在 Visual Studio 之外)。但是,当我在目标计算机(Windows 7、最新的.NET、最新的 C++ 可再发行版)上部署应用程序时,应用程序崩溃了。我设置了一种附加方法来将正在运行的应用程序记录到目标计算机上的文本文件中,并追踪到一个关键差异,非托管代码调用托管代码中的方法,仅缺少先前定义的静态字段。这只发生在目标机器(我部署代码的机器)上。这是一些代码片段和我记录的内容。令人困惑的是,此错误仅发生在目标计算机上。任何为我指明正确方向的帮助将不胜感激。
namespace MediaBridge
{
.....
public class MediaBridgeManager
{
public delegate void NewMediaGraphInfo(MediaBridgeGraphInfo GraphInfo);
private static readonly Dictionary<string, NewMediaGraphInfo> _delegateHash = new Dictionary<string, NewMediaGraphInfo>();
......
public static void AddMediaGraphInfo(MediaBridgeGraphInfo GraphInfo)
{
if (_delegateHash.ContainsKey(GraphInfo.MediaUrl))
{
NewMediaGraphInfo callback = _delegateHash[GraphInfo.MediaUrl];
_delegateHash.Remove(GraphInfo.MediaUrl);
/* Suppress all errors on the callback */
try
{
callback(GraphInfo);
}
catch {}
}
}
......
public static bool RegisterCallback(string MediaUrl, NewMediaGraphInfo Callback)
{
bool returnval = true;
MediaUrl = FormatUrl(MediaUrl);
if (!_delegateHash.ContainsKey(MediaUrl))
{
_delegateHash.Add(MediaUrl, Callback);
}
else
{
returnval = false;
}
return returnval;
}
}
}
在应用程序的 .NET 部分首先调用 RegisterCallback() 并使用 URL 和回调函数填充 _delegateHash 之前。这已在目标计算机上的日志文件中得到验证。
现在非托管部分:
STDMETHODIMP CMediaBridgeSourceFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{
/* Thread-saftey */
CAutoLock cAutoLockShared(&m_cSharedState);
HRESULT phr = S_OK;
/* Create the output pin for our filter */
m_pPin = new CMediaBridgeSourceFilterPin(&phr, this);
/* Create a new class to store information about us/graph in it */
MediaBridge::MediaBridgeGraphInfo ^ graphInfo = gcnew MediaBridge::MediaBridgeGraphInfo();
/* Set the media url sent */
graphInfo->MediaUrl = gcnew System::String(lpwszFileName);
/* Set the pointer to the filter graph */
graphInfo->FilterGraph = System::IntPtr(this->GetFilterGraph());
/* Store the pointer for our instance of the filter */
graphInfo->SourceFilter = System::IntPtr(this);
/* Do the callback into our managed code */
MediaBridge::MediaBridgeManager::AddMediaGraphInfo(graphInfo);
return phr;
}
根据我的日志文件 MediaBridge::MediaBridgeManager::AddMediaGraphInfo() 正在 .NET 端被调用,但回调永远不会到达,因为 _delegateHash 变量现在为空。
以下是我尝试在其上部署应用程序的目标计算机上的日志文件的内容:
RegisterCallback(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ Contains Key: True Delegate Hash count: 1
InitializeDirectShow(): RegisterCallback == true, Url == DShowMediaBridge://d0ffd222-d023-483b-8fc7-4b4035ce3922
AddMediaGraphInfo(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ FilterGraph: 71122304 Contains Key: False Delegate Hash count: 0
请注意,当非托管代码调用 AddMediaGraphInfo() 时,委托哈希计数 (_delegateHash.Count) 现在为 0。
我是否应该做一些事情来识别 VS 在我的开发机器上为我做的目标机器上的 COM/C++ dll?
I am building a webcam app based on the VideoRendererElement project (http://videorendererelement.codeplex.com/), which uses the DirectShowLib and Interop with an unmanaged activex component. I am using Visual Studio 2010, but am targeting .NET 3.5 (2.0 clr runtime).
I have been able to build and run the app on my development machine with no problem (outside of Visual Studio, even). However, when I deployed the app on the target machine (Windows 7,.NET up to date, C++ redistributable up to date) the app crashes. I set up an additional method to log the running application to a text file on the target machine a traced down one key difference, the unmanaged code calls the method in the managed code, only the static fields defined previously are missing. This only happens on the target machine (the one I deployed the code to). Here are some code snippets and what I logged. What is confusing is that this error ONLY occurs on the target machine. Any help pointing me in the right direction would be greatly appreciated.
namespace MediaBridge
{
.....
public class MediaBridgeManager
{
public delegate void NewMediaGraphInfo(MediaBridgeGraphInfo GraphInfo);
private static readonly Dictionary<string, NewMediaGraphInfo> _delegateHash = new Dictionary<string, NewMediaGraphInfo>();
......
public static void AddMediaGraphInfo(MediaBridgeGraphInfo GraphInfo)
{
if (_delegateHash.ContainsKey(GraphInfo.MediaUrl))
{
NewMediaGraphInfo callback = _delegateHash[GraphInfo.MediaUrl];
_delegateHash.Remove(GraphInfo.MediaUrl);
/* Suppress all errors on the callback */
try
{
callback(GraphInfo);
}
catch {}
}
}
......
public static bool RegisterCallback(string MediaUrl, NewMediaGraphInfo Callback)
{
bool returnval = true;
MediaUrl = FormatUrl(MediaUrl);
if (!_delegateHash.ContainsKey(MediaUrl))
{
_delegateHash.Add(MediaUrl, Callback);
}
else
{
returnval = false;
}
return returnval;
}
}
}
Before the .NET part of the app calls RegisterCallback() first and populates _delegateHash with a URL and callback function. This was verified in the logfile on the target machine.
Now the unmanaged part:
STDMETHODIMP CMediaBridgeSourceFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{
/* Thread-saftey */
CAutoLock cAutoLockShared(&m_cSharedState);
HRESULT phr = S_OK;
/* Create the output pin for our filter */
m_pPin = new CMediaBridgeSourceFilterPin(&phr, this);
/* Create a new class to store information about us/graph in it */
MediaBridge::MediaBridgeGraphInfo ^ graphInfo = gcnew MediaBridge::MediaBridgeGraphInfo();
/* Set the media url sent */
graphInfo->MediaUrl = gcnew System::String(lpwszFileName);
/* Set the pointer to the filter graph */
graphInfo->FilterGraph = System::IntPtr(this->GetFilterGraph());
/* Store the pointer for our instance of the filter */
graphInfo->SourceFilter = System::IntPtr(this);
/* Do the callback into our managed code */
MediaBridge::MediaBridgeManager::AddMediaGraphInfo(graphInfo);
return phr;
}
According to my log file MediaBridge::MediaBridgeManager::AddMediaGraphInfo() is being called on the .NET side but the call back is never reached because the _delegateHash variable is now empty.
Here is what my log file says on the target machine that I'm trying to deploy the app on:
RegisterCallback(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ Contains Key: True Delegate Hash count: 1
InitializeDirectShow(): RegisterCallback == true, Url == DShowMediaBridge://d0ffd222-d023-483b-8fc7-4b4035ce3922
AddMediaGraphInfo(): MediaUrl = dshowmediabridge://d0ffd222-d023-483b-8fc7-4b4035ce3922/ FilterGraph: 71122304 Contains Key: False Delegate Hash count: 0
Note how the Delegate Hash count (_delegateHash.Count) is now at 0 when the unmanaged code calls AddMediaGraphInfo().
Is there something I should be doing to identify the dll to COM/C++ on the target machine that VS is doing for me on my development machine?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您如何在目标计算机上部署和运行应用程序。您只是复制可执行文件还是创建安装程序?如果您正在创建安装程序,是否使用 RegSvr32 注册 AX 文件?
COM 组件的问题是它们必须在相关盒子的注册表中注册。在你的盒子上,你已经注册了这个,所以你不会有问题。然而,在目标盒子上,它可能会也可能不会注册,这取决于用户的意愿。如果您已经设置了安装程序,则必须“安装”AX 文件,以便将其注册到注册表中。否则,无论您如何部署 AX 文件,都无法找到 AX 文件。这是 COM 的缺点之一。
How are you deploying and running the application on the target machine. Are you simply copying over the executable or are you creating an installer? If you are creating an installer, are you registering the AX file with RegSvr32?
The issue with COM components is they have to be registered in the registry on the box in question. On your box, you already have this registered, so you will not have an issue. On the target box, however, it may or may not be registered, at the whim of the user. If you have set up an installer, you have to "install" the AX file so it is registered in the registry. If not, the AX file cannot be found, no matter how you deploy the AX file. It is one of the downsides to COM.