从C#库函数返回字符串会使VBA调用应用程序崩溃

从C#库函数返回字符串会使VBA调用应用程序崩溃,c#,vba,outlook,C#,Vba,Outlook,我构建了一个非托管C#库来使用web服务(经过测试,可以正常工作)。web服务接受给定的项目ID,并在项目管理系统中返回内部ID。这很有用,因为我可以深入链接到VBA、应用程序等中的项目 我想使用Declare语句在VBA中使用此库(我无法注册它,因为我无法访问客户端计算机上的注册表)。这有点奏效。我使用rgisecke.DllExport库导出函数而不是类,对于返回内部ID(作为整数)的函数,这非常有效。然而,我试图做的是创建一个函数,将完全构建的URL返回给VBA(或者调用方是什么)。这将使

我构建了一个非托管C#库来使用web服务(经过测试,可以正常工作)。web服务接受给定的项目ID,并在项目管理系统中返回内部ID。这很有用,因为我可以深入链接到VBA、应用程序等中的项目

我想使用Declare语句在VBA中使用此库(我无法注册它,因为我无法访问客户端计算机上的注册表)。这有点奏效。我使用rgisecke.DllExport库导出函数而不是类,对于返回内部ID(作为整数)的函数,这非常有效。然而,我试图做的是创建一个函数,将完全构建的URL返回给VBA(或者调用方是什么)。这将使使用库更加方便用户,而不必在获取内部ID后处理字符串连接和操作。这就是造成问题的原因-字符串返回(我在调试控制台中看到),然后Outlook挂起-没有错误,屏幕将变白,没有响应

为了测试,我将GetLink函数替换为一个简单的C#函数,该函数具有相同的名称和原型,返回“test”并发生相同的事情,因此我认为我没有溢出字符串或任何东西。然后,我让同一个函数返回int并返回0,这很好。因此,它肯定是返回字符串的东西。我怀疑这与函数的调用方式有关,或者VBA试图清理堆栈的方式有关(可能字符串大小在C#和VBA中不同,它将进入受保护的内存?),但我真的不确定。对于其他一些线程,我还尝试在VBA中将函数声明为返回对象,并得到了相同的结果

下面是C#lib和VBA子库的代码

这是C#库:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Runtime.InteropServices;

using System.Threading.Tasks;
using System.Net;
using System.IO;
using RGiesecke.DllExport;

public class ClarityWebService 
{
    [DllExport("GetInternalID", CallingConvention = CallingConvention.StdCall)]
    public static int GetInternalID(string projectID)
    {
        const String USERNAME = "the_username";
        const String PASSWORD = "the_password";
        int internalID;
        projectID = projectID.Trim()

        String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(USERNAME + ":" + PASSWORD));
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("<REST URL>/" + projectID);
        HttpWebResponse response = null;
        Boolean responseSuccess = true;

        request.Method = "GET";    
        request.Headers.Add("Authorization", "Basic " + encoded);

        // ACTUALLY HIT THE WEB SERVICE AND GET THE INTERNAL ID
        try
        {
            response = (HttpWebResponse)request.GetResponse();
        }
        catch (Exception except)
        {
            responseSuccess = false;
        }

        /* 
        * Only return the Internal ID on success. If the try failed,
        * there might be a network problem or an invalid Clarity ID was given, so return -1
        */
        Stream responseDataStream;
        String responseFromServer = "-1";

        if (responseSuccess)
        {
            // Get response as stream
            responseDataStream = response.GetResponseStream();

            // Read the stream
            var reader = new StreamReader(responseDataStream);

            // Parse through response
            responseFromServer = reader.ReadToEnd();

            bool resultofConv = Int32.TryParse(responseFromServer, out internalID);

            // The server should have sent an internal ID, which is an integer
            // If something else is returned, something is wrong
            if (resultofConv != true)
                internalID = -1;

            // Cleanup
            reader.Close();
            responseDataStream.Close();
            response.Close();            
        }
        else
        {
            internalID = -1;
        }

        return internalID;
    }

    [DllExport("GetLink", CallingConvention = CallingConvention.StdCall)]
    public static string GetLink(string projectID, string LinkType = "Main")
    {
        projectID = projectID.Trim();
        int intId = GetInternalID(projectID);
        string strIntId = intId.ToString();

        if (intId != -1)
            return BuildCorrectLink(strIntId,LinkType);
        else
            return "Error getting internal id for project " + projectID + " - make sure project is valid";
    }

    private static string BuildCorrectLink(string internalId, string LinkType = "Main")
    {
        // Generic deep links to various parts of a project
        const string mainLink = "<URL>&id=<INTERNAL ID>";
        const string statusReportLink = "<URL>&id=<INTERNAL ID>;
        const string dashboardLink = "<URL>&id=<INTERNAL ID>";
        const string auditLink = "<URL>&id=<INTERNAL ID>";
        const string hierarchyLink = "<URL>&id=<INTERNAL ID>";
        const string tasksLink = "<URL>&id=<INTERNAL ID>";
        const string ganttLink = "<URL>&id=<INTERNAL ID>";

        // Replace the <INTERNAL ID> in the generic link with the actual Internal ID and return it
        switch (LinkType.Trim())
        {
            // If LinkType = "Main" or is blank
            case "Main" : case "":
                return mainLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Status Report":
                return statusReportLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Dashboard":
                return dashboardLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Audit":
                return auditLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Hierarchy":
                return hierarchyLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Tasks":
                return tasksLink.Replace("<INTERNAL ID>", internalId);
                break;
            case "Gantt":
                return ganttLink.Replace("<INTERNAL ID>", internalId);
                break;
            default:
                return "Error - unknown subpage requested";
                break;
        }
    }

}
Option Explicit
' DEBUG function declarations
Declare Function GetInternalID Lib "C:\Users\MyUserName\Documents\Visual Studio 2010\Projects\ClarityWebService\ClarityWebService\bin\Debug\ClarityWebService.dll" (ByVal ProjectID As String) As Long
Declare Function GetLink Lib "C:\Users\MyUserName\Documents\Visual Studio 2010\Projects\ClarityWebService\ClarityWebService\bin\Debug\ClarityWebService.dll" (ByVal ProjectID As String, Optional ByVal LinkType As String) As String

' Shared drive function declarations
'Declare Function GetInternalID Lib "Shared Network Drive\ClarityWebService.dll" (ByVal ProjectID As String) As Long
'Declare Function GetLink Lib "Shared Network Drive\ClarityWebService.dll" (ByVal ProjectID As String, Optional ByVal LinkType As String) As String


Sub TestClarityWebService()        
    ' The line below works (I see a link in the debug console),
    ' but Outlook crashes right after
    Debug.Print (GetLink("ID_of_Project1", "Main"))
End Sub

为了提供另一种选择,以防您不知道:这可能允许您调用您的方法,而无需所有非托管魔法。@Heinzi:谢谢您的链接。这似乎很有趣,我会记住这个选项,但我认为它不适合我目前的需要。我目前的目标是能够分发引用共享驱动器上的.dll的Outlook VBA模块和Excel.xlm文件,或者将代码和库一起分发。我目前不打算创建一个通过InstallShield安装的完整应用程序。