我正在尝试使用 ActiveX 为 SAP b1 创建自定义控件。
我的用户控件如下所示:
[ComVisible(false)]
public delegate void OnCheckBoxClickEventHandler(string val);
[ProgId("MyComLib.Controls.TextBoxCheck")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ITextBoxCheckEvents))]
public partial class TextBoxCheckClass : UserControl, TextBoxCheck
{
public string PlaceHolder
{
get
{
return textBox1.Text;
}
set
{
textBox1.Text = value;
}
}
public TextBoxCheckClass()
{
InitializeComponent();
}
public event OnCheckBoxClickEventHandler OnCheckBoxClick;
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
textBox1.ReadOnly = checkBox1.Checked;
OnCheckBoxClick?.Invoke(textBox1.Text);
}
private void TextBoxCheck_Load(object sender, …Run Code Online (Sandbox Code Playgroud) 在Visual Studio中添加对Office的COM互操作的引用的技术是:
神奇命名的参考出现:
Microsoft.Office.Core
Run Code Online (Sandbox Code Playgroud)
该Project.csproj文件显示了参考的详细信息:
<COMReference Include="Microsoft.Office.Core">
<Guid>{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>3</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
</COMReference>
Run Code Online (Sandbox Code Playgroud)
并且项目被检查到源代码控制并且一切都很好.
然后,Office 2007的开发人员从源代码控制获取项目,并且无法构建它,因为此类引用不存在.
他(即我)检出.csproj文件,删除对它的引用
Microsoft Office 11.0 Object Library
Run Code Online (Sandbox Code Playgroud)
并重新添加COM引用
Microsoft Office 12.0 Object Library
Run Code Online (Sandbox Code Playgroud)
神奇地出现了一个命名参考:
Microsoft.Office.Core
Run Code Online (Sandbox Code Playgroud)
该Project.csproj文件显示了参考的详细信息:
<COMReference Include="Microsoft.Office.Core">
<Guid>{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>4</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
</COMReference>
Run Code Online (Sandbox Code Playgroud)
并且项目被检查到源代码控制并且一切都很好.
然后,Office 2003的开发人员从源代码控制获取项目,并且无法构建它,因为这样的引用不存在.
他(即不是我)检出.csproj文件,删除对它的引用
Microsoft Office 12.0 Object Library
Run Code Online (Sandbox Code Playgroud)
并重新添加COM引用
Microsoft Office 11.0 Object Library
Run Code Online (Sandbox Code Playgroud)
神奇地出现了一个命名参考:
Microsoft.Office.Core
Run Code Online (Sandbox Code Playgroud)
该Project.csproj文件显示了参考的详细信息:
<COMReference Include="Microsoft.Office.Core"> …Run Code Online (Sandbox Code Playgroud) 我有一个_bstr_t变量bstrErr,我有一个CString变量csError.如何设置该进来的价值bstrErr来csError?
似乎有一些虚拟文件夹与GUID相关联(控制面板,桌面) -
:: {00021400-0000-0000-c000-000000000046} //桌面
火焰是这些定义的?他们什么时候用?
我想要的是一种方法,让一个字符串代表一个没有任何歧义的虚拟文件夹.
如果,例如,我要创建一个PIDL桌面,显示名称回来为"C:\用户\史蒂夫\桌面".
嗯,目前这是真的 - 但它不是真正的正确文件夹.我可以在资源管理器中导航到该文件夹,它包含我桌面上的部分文件,而不是整个桌面.
我想是到该位置编码为一个字符串,将始终定位到虚拟桌面文件夹(即具有的所有内容,而不仅仅是几件事情之一)的方式.
有谁知道这些GUID的最终清单?或者我如何将给定的PIDL转换成一个?
我试图SHGetDisplayName(PIDL,SHGDN_*) - 的,对于桌面PIDL每一个版本给我任何短暂的"桌面"或"C:\用户\史蒂夫\桌面".(显然我是在'史蒂夫'帐户下登录的).
想法/评论/指针?
编辑:所以我似乎可以使用下面给出的答案来获得已知文件夹GUId的列表.但有没有人以编程方式知道如何从PIDL转换 - >已知文件夹GUID?我以为我可以ParseDisplayName(":: {GUID}"),以获得PIDL,但有一种方式来获得的GUID?
编辑2:我仍然找不到以编程方式获取GUID的方法.然而,我的目的,我记录CSIDL_xxx我最初用来创建对象,并编写出与后来恢复它,然后由CSIDL,它保留了正确的标识(即方式创建一个PIDL.它不不会降级为"C:\ Users \\ Desktop",而是生成一个真正指向虚拟桌面的PIDL.
我的诀窍是始终使用CSIDL-> PIDL,永远不要在它们之间使用字符串.CSIDL-> PIDL-> string-> PIDL =退化为非虚拟路径.
感谢大家的帮助 - 我会一直在寻找是否有人发现更多关于这个主题并发布它,我会感兴趣!;)
创建一个COM服务器,然后我注册了它.
当我试图在COM客户端中添加该COM服务器时,我无法添加,并且出现以下错误.
"无法添加对'COMTest'的引用
ActiveX类型库'c\user \〜\ Debug\COMTest.tlb'是从.NET程序集导出的,无法添加为引用.
添加对.NET的引用"
任何人都可以告诉我这是什么错误.我以两种方式注册COM,也来自VS,也尝试使用命令提示符.
我正在使用来自第三方库的COM对象来生成定期事件.当我使用Winforms应用程序中的库,将对象作为类成员并在主窗体线程中创建它时,一切正常.但是,如果我从另一个线程创建对象,我不会收到任何事件.
我的猜测是我需要在用于创建对象的同一个线程中有某种事件循环.
我需要从控制台应用程序中使用此对象.我想我可以使用Application.DoEvents,但我宁愿不在控制台App中包含Winforms命名空间.
我怎么解决这个问题?
更新3(2011-06-15):供应商终于回答了.简而言之,他们说Application.Run创建的消息泵与Thread.Join创建的消息泵之间存在一些差异,但他们不知道这有什么区别.
我同意他们; 任何关于此事的光明都会非常感激.
更新:
从理查德评论到mdm回答:
如果其他组件是单线程并从MTA实例化,则Windows将创建工作线程+窗口+消息泵并执行必要的编组.
试着听从他的建议,我正在做以下事情:
更新2:
我改变了JoãoAngelo回答后的代码.
using System;
namespace ConsoleApplication2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
MyComObjectWrapper wrapper = new MyComObjectWrapper();
}
}
class MyComObjectWrapper
{
MyComObject m_Object;
AutoResetEvent m_Event;
public MyComObjectWrapper()
{
m_Event = new System.Threading.AutoResetEvent(false);
System.Threading.Thread t = new System.Threading.Thread(() => CreateObject());
t.SetApartmentState (System.Threading.ApartmentState.STA);
t.Start();
Wait();
}
void ObjectEvt(/*...*/)
{
// ...
}
void Wait()
{
m_Event.WaitOne();
}
void CreateObject()
{
m_Object = new MyComObject();
m_Object.OnEvent …Run Code Online (Sandbox Code Playgroud) 我知道每个线程在与COM系统交互之前调用COM 的要求CoInitialize.
.NET公开了一些内部在线程上运行的项目,例如:
ThreadPool 线程BackgroundWorker class(使用异步委托(使用线程池线程))如果我要从一个线程与一个COM对象进行交互,我是否需要先调用CoInitialize?
我问,因为可能会有更多魔法自动称呼它 - 我不知道.
托管和非托管线程
对于互操作性,公共语言运行库在调用COM对象时创建并初始化公寓.托管线程可以创建并进入仅包含一个线程的单线程单元(STA),或包含一个或多个线程的多线程单元(MTA).当COM公寓和线程生成的公寓兼容时,COM允许调用线程直接调用COM对象.如果公寓不兼容,COM会创建一个兼容的公寓,并通过新公寓的代理人打电话.
运行时调用CoInitializeEx将COM单元初始化为MTA或STA单元.
更新二:
看起来你不应该使用.NET提供的任何类型的线程中的COM:
托管线程池
有几种情况适合创建和管理自己的线程而不是使用线程池线程:
您需要前台线程.
您需要一个线程具有特定的优先级.
您有任务导致线程长时间阻塞.线程池具有最大线程数,因此大量被阻塞的线程池线程可能会阻止任务启动.
您需要将线程放入单线程单元中.所有ThreadPool线程都在多线程单元中.
您需要具有与线程关联的稳定标识,或者将线程专用于任务.
更新三:
看起来您可以设置非线程线程的线程模型:
Microsoft Windows中的托管和非托管线程
可以标记托管线程以指示它将托管单线程或多线程单元.Thread类的GetApartmentState,SetApartmentState和TrySetApartmentState方法返回并分配线程的单元状态.如果尚未设置状态,则GetApartmentState将返回ApartmentState.Unknown.
仅当线程处于ThreadState.Unstarted状态时才能设置该属性; 它只能为一个线程设置一次.
如果在线程启动之前未设置单元状态,则将线程初始化为多线程单元(MTA).
很多相互矛盾的信息.
这就是为什么我们会使用Stackoverflow上的任何人说的真正答案.
考虑以下理解
regsvr32调用入口点DllRegisterServer/ DllUnregisterServer加载目标DLL到通过其地址空间后LoadLIbrary.C:\Windows\SysWOW64但是在我的2008 R2 Box上,我能够通过64位regsvr32注册一个32位的dll.怎么可能?我错过了什么吗?

我的Powershell(2.0)脚本包含以下代码段:
$fileName = "c:\reports\1.xlsx"
$xl = new-object -comobject excel.application
$xlFormat = [Microsoft.Office.Interop.excel.XlFileFormat]::xlWorkbookDefault
$xl.displayalerts = $false
$workbook = $xl.workbooks.open($fileName)
#Code to manipulate a worksheet
$workbook.SaveAs($fileName, $xlformat)
$xl.quit()
$error | out-file c:\reports\error.txt
Run Code Online (Sandbox Code Playgroud)
我可以在Powershell命令提示符下运行此脚本,没有任何问题.电子表格会更新,error.txt为空.但是,当我在任务计划程序中将其作为任务运行时,我会在第一行出错.
使用"1"参数调用"打开"的异常:"Microsoft Office Excel无法访问文件'C:\ reports\1.xlsx'.有几个可能的原因:文件名或路径不存在.文件正在尝试保存的工作簿与当前打开的工作簿具有相同的名称.
我使用与Powershell命令提示符中运行脚本相同的凭据运行任务.当我手动运行脚本时,它可以打开,更新和保存电子表格而不会出现任何问题.当我在任务计划程序中运行它时,它无法访问电子表格.
有问题的文件对所有用户都是可读/可写的.我已经验证我可以使用相同的凭据在Excel中打开该文件.如果我创建一个新的电子表格并将其名称作为$ filename,我会得到相同的结果.我已经确认任务管理器中没有Excel.exe实例.
奇怪的是,如果我使用get-content,我没有任何问题.另外,如果我制作新的电子表格,我没有任何问题.
$fileName = "c:\reports\1.xlsx"
$xl = get-content $spreadsheet
$xl = new-object -comobject excel.application
$xlFormat = [Microsoft.Office.Interop.excel.XlFileFormat]::xlWorkbookDefault
$xl.displayalerts = $false
# Commented out $workbook = $xl.workbooks.open($fileName)
$workbook = $xl.workbooks.add()
#Code to manipulate a worksheet
$workbook.SaveAs($fileName, $xlformat)
$xl.quit()
$error | out-file c:\reports\error.txt
Run Code Online (Sandbox Code Playgroud)
这很好.因此Get-ChildItem可以毫无问题地打开文件.如果我手动运行它,ComObject可以打开该文件,但如果它作为任务运行则不能.
我不知所措.有任何想法吗?
我有一些代码使用COM公开的第三方库(ArcObjects).所以例如有-interface IGeometry.
IGeometry geometry = GetGeometry();
Run Code Online (Sandbox Code Playgroud)
现在,当我想查看对象成员时,我打开了一个QuickWatch:
我已经阅读了几个问题,这些问题都指向Visual Studio 2015中的"启用本机代码调试"选项.我已经启用该选项无济于事.
如何让调试器公开COM对象的成员?
编辑:当使用VS2010和.NET 3.5时,这适用:
com ×10
c# ×4
c++ ×3
interop ×3
excel ×2
.net ×1
activex ×1
add-on ×1
arcobjects ×1
bstr ×1
com-interop ×1
events ×1
mfc ×1
ms-office ×1
powershell ×1
rpc ×1
sapb1 ×1
shell ×1
visual-c++ ×1
windows ×1