标签: com-server

Excel 2007 UDF:如何添加函数描述,参数帮助?

说明

我在COM服务器中编写了几个Excel UDF.我想获得按fx时获得的标准帮助(" 插入函数"对话框).是的,我可以看到我的COM服务器列在类别下拉列表中,但是

  • 我还看到了Equals,GetHashCode,GetType和ToString(这对于向Excel用户公开是不合适的),
  • 选择我的COM服务器会弹出*Function Arguments*[1]对话框,没有参数信息,也没有该函数的描述.

这是我得到的跛足:

插入函数对话框http://www.iwebthereforeiam.com/files/Insert%20function%20dialog.gif

Excel函数参数对话框http://www.iwebthereforeiam.com/files/Function%20Arguments%20dialog.gif

这个问题

是否有.NET属性我可以把方法传递给Excel?

  • 我可以提供功能说明吗?
  • 我可以提供参数说明吗?
  • 我可以为我的功能提供类别名称,这样我得到的东西比ProgID更好吗?

(我发现在ExcelDNA中看起来很容易,但我不会那样做.模仿govert的代码[自定义属性,某种类型的加载器等]看起来很难.)


附加背景

如果您以前没有使用Excel + COM服务器,这里有一些有用的资源可以加快速度:

以前的StackOverflow问题:
如何在VB.NET中安装并在Automation Servers列表中注册的用于Excel的COM Server for Excel?
如何将COM暴露的.NET项目添加到VB6(或VBA)引用对话框?

其他资源:
在.NET中为Excel编写用户定义的函数
构建和部署.NET COM程序集
在C#中编写自定义Excel工作表函数


编辑2009-10-20 14:10

我试着打电话Application.MacroOptionsSub New().

  1. No Sub New()
    半可接受:功能列在ProgID类别下.
  2. Shared Sub New()
    不可接受:构建时错误.
    Cannot register assembly "...\Foo.dll".
    Exception has been thrown by the target of an invocation.
  3. Sub New()
    不可接受:"插入函数"对话框中未列出类别.

我怀疑这对于MacroOptions和Charles推荐的更复杂的路线都是一个问题.


编辑2009-10-20 14:55

从好的方面来说,Mike建议创建一个实现的接口确实可以消除暴露的烦人的额外方法.


编辑2009-10-20 15:00

这篇 2007年初的微软文章(通过Mike的链接)似乎是关于这个主题的一个相当完整的答案: …

excel excel-udf com-server

9
推荐指数
1
解决办法
2万
查看次数

获取COM服务器的进程ID

我正在通过将Windows消息直接发送到HWND并调用自动化应用程序公开的COM服务器来实现一些自动化.

如果有多个实例正在运行,我需要能够确定COM服务器的进程ID,这样我可以使用COM调用命中相同的实例作为我发送Windows消息的实例.

我可以使用正在运行的对象表枚举所有正在运行的COM服务器,并为所有这些服务器返回monikers,但COM对象本身不会公开任何可用于获取窗口句柄,线程ID,进程ID或任何类型的方法.

有没有办法弄清楚,基于名字对象或名字对象的实际绑定COM对象,COM服务器的进程ID是什么?

谢谢!

com winapi moniker com-server

8
推荐指数
1
解决办法
1260
查看次数

CDialog :: Create对于带有ActiveX控件的对话框失败

我有一个模块,可以创建一个包含ActiveX控件的无模式对话框。该模块是MFC EXE应用程序的一部分,并且对话框的创建工作正常。最近,我将模块移到ATL / COM服务器中,并将对话框资源从EXE复制到COM服务器中。尝试使用CDialog::Create()错误创建无模式对话框时发生。

我调试到CDialog::Create并注意到它的失败,::CreateDialogIndirect()返回NULLGetLastError回报0。我在对话框资源属性中将“ No Fail Create”标志设置为True,并获得了更多有关错误的详细信息。问题发生在该对话框的DoDataExchange()的中DDX_Control宏。这会CDataExchange::PrepareCtrl()使用控件的资源ID 调用,如下所示:

HWND CDataExchange::PrepareCtrl(int nIDC)
{
   ASSERT(nIDC != 0);
   ASSERT(nIDC != -1); // not allowed
   HWND hWndCtrl;
   COleControlSite* pSite = NULL;
   m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
   if (hWndCtrl == NULL)
   {
      // Could be a windowless OCX
      pSite = m_pDlgWnd->GetOleControlSite(nIDC);
      if (pSite == NULL)
      {
         TRACE(traceAppMsg, 0, "Error: no data exchange control with ID 0x%04X.\n", nIDC);
         ASSERT(FALSE);
         AfxThrowNotSupportedException(); …
Run Code Online (Sandbox Code Playgroud)

mfc cdialog com-server

5
推荐指数
1
解决办法
4320
查看次数

我何时为COM服务器生成新的GUID?(Python中的示例)

我是制作COM服务器和使用Python的COM的新手,所以我想澄清一些我找不到明确答案的东西:

正确为COM服务器创建GUID

我生成:

  1. 手动创建我的COM服务器的GUID,从那时起复制它并将#用于服务器?因此,当我分发应用程序时,其他用户将使用我在开发期间创建的相同GUID.

  2. 每次初始化应用程序或COM服务器对象时都有新的GUID?

  3. 基于每台计算机的新GUID,在初始设置期间只有一次然后让应用程序保存GUID#,并且在将来加载时它会从用户设置文件中提取#?

示例场景1:

i)  print(pythoncom.CreateGuid())   #in interpreter
ii) _reg_clsid_ = copy  above GUID into your app
Run Code Online (Sandbox Code Playgroud)

示例场景2:

i)_reg_clsid_ = pythoncom.CreateGuid()
Run Code Online (Sandbox Code Playgroud)

示例场景3:

if self.isfile = os.path.isfile(url):
    load_previous_generated_GUID(url)
else:
    #first time running application or setup file is missing
    GUID = pythoncom.CreateGuid()
    save_GUID_to_setup_file(GUID)
Run Code Online (Sandbox Code Playgroud)

我可以使用GUID来跟踪程序/ COM服务器版本吗?

如果上面的场景#1是正确的那么:当我进行升级时,我可以测试旧的GUID,以便我可以正确地与它进行交互?

TODO:如何从Python和/或VBA获取COM服务器的GUID?

python com guid com-server

5
推荐指数
1
解决办法
345
查看次数

调用IContextMenu :: QueryContextMenu,但IContextMenu :: InvokeCommand没有

在我的IContextMenuCOM服务器实现中,QueryContextMenu调用了gets(可以通过日志记录查看),但InvokeCommand没有.这是QueryContextMenu:

HRESULT ContexMenuImp::QueryContextMenu(HMENU hmenu,UINT indexMenu,UINT idCmdFirst,
    UINT idCmdLast,UINT uFlags)
{
    if (uFlags & CMF_DEFAULTONLY) {
        // shouldn't handle this situation:
        LOG("IContextMenu::QueryContextMenu:    (...,CMF_DEFAULTONLY)");
        return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,0);
    }else if (InsertMenuItem(hmenu,indexMenu,TRUE,&globals.menuItemInfo) == FALSE){
        // error occurred:
        LOG("IContextMenu::QueryContextMenu:    Error: %d",GetLastError());
        return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,0);
    } else{
        // the desired situation: add item to the menu:
        LOG("IContextMenu::QueryContextMenu(hMenu,indexMenu:%u,idCmdFirst:%u,idCmdLast:%u,0x%x):    All set...",
            indexMenu,idCmdFirst,idCmdLast,uFlags);
        return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,1/*handle only a single item*/);
    }
}
Run Code Online (Sandbox Code Playgroud)

知道为什么吗?

c++ windows com atl com-server

1
推荐指数
1
解决办法
1161
查看次数

进程外COM服务器 - 每个调用进程一个服务器进程?

我有一个进程外com服务器,指定CLSCTX_LOCAL_SERVER作为上下文,并指定REGCLS_MULTIPLEUSE作为连接类型.这导致单个服务器进程被来自多个客户端的多个调用重用.

我现在想要对服务器进行一些更改,遗憾的是,这些更改无法与客户端共享的单个进程一起工作(有这样的原因,但是它们已经很长时间了).我知道您可以将服务器设置为使用REGCLS_SINGLEUSE作为连接类型,这将为每次调用的OOP服务器创建一个新进程.这解决了我的问题,但在流程使用方面是不起作用的; 短时间内的多次呼叫会导致许多进程,并且这种特定的服务器可能会经常受到惊吓.

有没有人碰巧知道混合这两种连接类型的机制?基本上我想要的是每个调用进程一个服务器进程.(即,客户端1创建一个进程,该进程被重用于该客户端的后续调用.客户端2尝试调用服务器,并创建一个新进程).我怀疑我可以通过强制REGCLS_SINGLEUSE服务器在客户端永久保持打开来实现它,但这既不优雅也不可能(因为我无法更改其中一个客户端).

思考?

更新 正如预期的那样,似乎没有办法做到这一点.如果时间和资源允许,我很可能将其转换为In-Proc解决方案.但就目前而言,我不得不采用任何调用客户端所使用的新行为.幸运的是,这种变化的影响非常小,并且客户可以接受.我稍后会研究更激烈和适当的变化.

注意 我已经将Hans的回复标记为答案,因为事实上它确实解决了维护OOP解决方案的问题.我只是没有能力实现它.

CAL

c++ com com-server

1
推荐指数
1
解决办法
508
查看次数

标签 统计

com-server ×6

com ×4

c++ ×2

atl ×1

cdialog ×1

excel ×1

excel-udf ×1

guid ×1

mfc ×1

moniker ×1

python ×1

winapi ×1

windows ×1