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

时间:2015-07-01 13:10:54

标签: c# vba outlook-vba

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

我想使用Declare语句在VBA中使用此库(我无法注册它,因为我无法访问客户端计算机上的注册表)。这个有些有效。我使用RGiesecke.DllExport库来导出函数而不是类,对于返回内部ID(作为整数)的函数,这很有用。但是,我要做的是创建一个函数,将完全构建的URL返回给VBA(或者调用者的任何内容)。这将使得使用库更加用户友好,而不必在获取内部ID后进行字符串连接和操作。这就是导致问题的原因 - 字符串返回(我在调试控制台中看到它),然后Outlook只是挂起 - 没有错误,屏幕只会变白并且没有响应。

为了测试,我用一个简单的C#函数取代了GetLink函数,该函数具有相同的名称&返回的原型"测试"并且同样的事情发生了,所以我不认为我溢出了字符串或任何东西。然后我做了相同的函数返回一个int并返回0,这工作正常。因此,它肯定会返回一个字符串。我怀疑它是如何调用函数的,或者VBA是如何尝试清理堆栈的(C#和VBA中的字符串大小可能不一样,它会进入受保护的mem?),但我真的不确定。对于其他一些线程,我也尝试在VBA中将该函数声明为返回一个Object,并且具有相同的结果。

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;
        }
    }

}

以下是VBA代码:

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

0 个答案:

没有答案