Add BSTR xplat PInvoke testcase (#20231)
authorLuqun Lou <luqunl@users.noreply.github.com>
Sat, 6 Oct 2018 02:07:48 +0000 (19:07 -0700)
committerGitHub <noreply@github.com>
Sat, 6 Oct 2018 02:07:48 +0000 (19:07 -0700)
tests/src/Common/Platform/platformdefines.cpp
tests/src/Common/Platform/platformdefines.h
tests/src/Interop/ArrayMarshalling/ByValArray/MarshalArrayByValNative.cpp
tests/src/Interop/CMakeLists.txt
tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs [new file with mode: 0644]
tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj [new file with mode: 0644]
tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp [new file with mode: 0644]
tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs [new file with mode: 0644]
tests/src/Interop/common/types.h

index 82061ac..826e741 100644 (file)
 
 #include "platformdefines.h"
 
-LPWSTR HackyConvertToWSTR(char* pszInput)
+LPWSTR HackyConvertToWSTR(const char* pszInput)
 {
-       size_t cchInput;
-       LPWSTR pwszOutput;
-       char*  pStr;
+    size_t cchInput;
+    LPWSTR pwszOutput;
+    char*  pStr;
 
-       if (NULL == pszInput) return NULL;
+    if (NULL == pszInput) return NULL;
 
-       // poor mans strlen
-       pStr     = pszInput;
-       cchInput = 0;
-       while('\0' != *pStr) {cchInput++; pStr++;}
-       pwszOutput = new WCHAR[ cchInput + 1];
+    // poor mans strlen
+    pStr     = (char*)pszInput;
+    cchInput = 0;
+    while('\0' != *pStr) {cchInput++; pStr++;}
+    pwszOutput = new WCHAR[ cchInput + 1];
 
-       for(size_t i=0; i<=cchInput; i++)
-       {
-               pwszOutput[i] = (WCHAR)pszInput[i];
-       }
+    for(size_t i=0; i<=cchInput; i++)
+    {
+        pwszOutput[i] = (WCHAR)pszInput[i];
+    }
 
-       return pwszOutput;
+    return pwszOutput;
 }
 
 LPSTR HackyConvertToSTR(LPWSTR pwszInput)
 {
-       size_t cchInput;
-       LPSTR  pszOutput;
+    size_t cchInput;
+    LPSTR  pszOutput;
 
-       if (NULL == pwszInput) return NULL;
+    if (NULL == pwszInput) return NULL;
 
-       cchInput = wcslen(pwszInput);
-       pszOutput = new char[ cchInput + 1];
+    cchInput = wcslen(pwszInput);
+    pszOutput = new char[ cchInput + 1];
 
-       for(size_t i=0; i<=cchInput; i++)
-       {
-               // ugly down cast
-               pszOutput[i] = (char)pwszInput[i];
-       }
+    for(size_t i=0; i<=cchInput; i++)
+    {
+        // ugly down cast
+        pszOutput[i] = (char)pwszInput[i];
+    }
 
-       return pszOutput;
+    return pszOutput;
 }
 
 error_t TP_scpy_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource)
 {
-       size_t cnt;
-       // copy sizeInBytes bytes of strSource into strDestination
+    size_t cnt;
+    // copy sizeInBytes bytes of strSource into strDestination
 
-       if (NULL == strDestination || NULL == strSource) return 1;
+    if (NULL == strDestination || NULL == strSource) return 1;
 
-       cnt = 0;
-       while(cnt < sizeInWords && '\0' != strSource[cnt])
-       {
-               strDestination[cnt] = strSource[cnt];
-               cnt++;
-       }
-       strDestination[cnt] = '\0';
+    cnt = 0;
+    while(cnt < sizeInWords && '\0' != strSource[cnt])
+    {
+        strDestination[cnt] = strSource[cnt];
+        cnt++;
+    }
+    strDestination[cnt] = '\0';
 
-       return 0;
+    return 0;
 }
 
 error_t TP_scat_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource)
 {
-       LPWSTR strEnd;
-       // locate the end (ie. '\0') and TP_scpy_s the string
+    LPWSTR strEnd;
+    // locate the end (ie. '\0') and TP_scpy_s the string
 
-       if (NULL == strDestination || NULL == strSource) return 1;
+    if (NULL == strDestination || NULL == strSource) return 1;
 
-       strEnd = strDestination;
-       while('\0' != *strEnd) strEnd++;
+    strEnd = strDestination;
+    while('\0' != *strEnd) strEnd++;
 
-       return TP_scpy_s(strEnd, sizeInWords - ((strEnd - strDestination) / sizeof(WCHAR)), strSource);
+    return TP_scpy_s(strEnd, sizeInWords - ((strEnd - strDestination) / sizeof(WCHAR)), strSource);
 }
 
 int TP_slen(LPWSTR str)
 {
-       int len;
+    int len;
 
-       if (NULL == str) return 0;
+    if (NULL == str) return 0;
 
-       len = 0;
-       while('\0' != *(str+len)) len++;
+    len = 0;
+    while('\0' != *(str+len)) len++;
 
-       return len;
+    return len;
 }
 
 int TP_scmp_s(LPCSTR str1, LPCSTR str2)
 {
-       // < 0 str1 less than str2
-       // 0  str1 identical to str2
-       // > 0 str1 greater than str2
+    // < 0 str1 less than str2
+    // 0  str1 identical to str2
+    // > 0 str1 greater than str2
 
-       if (NULL == str1 && NULL != str2) return -1;
-       if (NULL != str1 && NULL == str2) return 1;
-       if (NULL == str1 && NULL == str2) return 0;
+    if (NULL == str1 && NULL != str2) return -1;
+    if (NULL != str1 && NULL == str2) return 1;
+    if (NULL == str1 && NULL == str2) return 0;
 
-       while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2)
-       {
-               str1++;
-               str2++;
-       }
+    while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2)
+    {
+        str1++;
+        str2++;
+    }
 
-       if ('\0' == *str1 && '\0' == *str2) return 0;
+    if ('\0' == *str1 && '\0' == *str2) return 0;
 
-       if ('\0' != *str1) return -1;
-       if ('\0' != *str2) return 1;
+    if ('\0' != *str1) return -1;
+    if ('\0' != *str2) return 1;
 
-       return (*str1 > *str2) ? 1 : -1;
+    return (*str1 > *str2) ? 1 : -1;
 }
 
 int TP_wcmp_s(LPWSTR str1, LPWSTR str2)
 {
-       // < 0 str1 less than str2
-       // 0  str1 identical to str2
-       // > 0 str1 greater than str2
+    // < 0 str1 less than str2
+    // 0  str1 identical to str2
+    // > 0 str1 greater than str2
 
-       if (NULL == str1 && NULL != str2) return -1;
-       if (NULL != str1 && NULL == str2) return 1;
-       if (NULL == str1 && NULL == str2) return 0;
+    if (NULL == str1 && NULL != str2) return -1;
+    if (NULL != str1 && NULL == str2) return 1;
+    if (NULL == str1 && NULL == str2) return 0;
 
-       while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2)
-       {
-               str1++;
-               str2++;
-       }
+    while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2)
+    {
+        str1++;
+        str2++;
+    }
 
-       if ('\0' == *str1 && '\0' == *str2) return 0;
+    if ('\0' == *str1 && '\0' == *str2) return 0;
 
-       if ('\0' != *str1) return -1;
-       if ('\0' != *str2) return 1;
+    if ('\0' != *str1) return -1;
+    if ('\0' != *str2) return 1;
 
-       return (*str1 > *str2) ? 1 : -1;
+    return (*str1 > *str2) ? 1 : -1;
 }
 
 error_t TP_getenv_s(size_t* pReturnValue, LPWSTR buffer, size_t sizeInWords, LPCWSTR varname)
 {
-       if (NULL == pReturnValue || NULL == varname) return 1;
+    if (NULL == pReturnValue || NULL == varname) return 1;
 
 #ifdef WINDOWS
-       
-        size_t  returnValue;
+    
+     size_t  returnValue;
      WCHAR   buf[100];
      if( 0 != _wgetenv_s(&returnValue, buf, 100, varname) || returnValue<=0 )
-               return 2;
-       
-       
-       TP_scpy_s(buffer, sizeInWords, (LPWSTR)buf);
+        return 2;
+    
+    
+    TP_scpy_s(buffer, sizeInWords, (LPWSTR)buf);
 #else
-       LPSTR pRet;
-       pRet = getenv( HackyConvertToSTR((LPWSTR)varname) );
-       if (NULL == pRet) return 2;
-       TP_scpy_s(buffer, sizeInWords, HackyConvertToWSTR(pRet));
+    LPSTR pRet;
+    pRet = getenv( HackyConvertToSTR((LPWSTR)varname) );
+    if (NULL == pRet) return 2;
+    TP_scpy_s(buffer, sizeInWords, HackyConvertToWSTR(pRet));
 #endif
-       return 0;
+    return 0;
 }
 
 error_t TP_putenv_s(LPTSTR name, LPTSTR value)
 {
-       if (NULL == name || NULL == value) return 1;
+    if (NULL == name || NULL == value) return 1;
 
 #ifdef WINDOWS
-       if( 0 != _putenv_s(name, value))
-               return 2;
-       else
-               return 0;
+    if( 0 != _putenv_s(name, value))
+        return 2;
+    else
+        return 0;
 #else
-       int retVal = 0;
-       char *assignment = (char*) malloc(sizeof(char) * (strlen(name) + strlen(value) + 1));
-       sprintf(assignment, "%s=%s", name, value);
-
-       if (0 != putenv(assignment))
-               retVal = 2;
-       free(assignment);
-       return retVal;
+    int retVal = 0;
+    char *assignment = (char*) malloc(sizeof(char) * (strlen(name) + strlen(value) + 1));
+    sprintf(assignment, "%s=%s", name, value);
+
+    if (0 != putenv(assignment))
+        retVal = 2;
+    free(assignment);
+    return retVal;
 #endif
 }
 
 void TP_ZeroMemory(LPVOID buffer, size_t sizeInBytes)
 {
-       BYTE* bBuf;
+    BYTE* bBuf;
 
-       // clear out the memory with 0's
-       if (NULL == buffer) return;
+    // clear out the memory with 0's
+    if (NULL == buffer) return;
 
-       bBuf = (BYTE*)buffer;
-       for(size_t i=0; i<sizeInBytes; i++)
-       {
-               bBuf[i] = 0;
-       }
+    bBuf = (BYTE*)buffer;
+    for(size_t i=0; i<sizeInBytes; i++)
+    {
+        bBuf[i] = 0;
+    }
 }
 
 error_t TP_itow_s(int num, LPWSTR buffer, size_t sizeInCharacters, int radix)
 {
-       size_t len;
-       int tmpNum;
-
-       // only support radix == 10 and only positive numbers
-       if (10 != radix) return 1;
-       if (0 > num) return 2;
-       if (NULL == buffer) return 3;
-       if (2 > sizeInCharacters) return 4;
-
-       // take care of the trivial case
-       if (0 == num)
-       {
-               buffer[0] = '\0';
-               buffer[1] = '\0';
-       }
-
-       // get length of final string (dumb implementation)
-       len = 0;
-       tmpNum = num;
-       while (0 < tmpNum)
-       {
-               tmpNum /= 10;
-               len++;
-       }
-
-       if (len >= sizeInCharacters) return 5;
-
-       // convert num into a string (backwards)
-       buffer[len] = '\0';
-       while(0 < num && 0 < len)
-       {
+    size_t len;
+    int tmpNum;
+
+    // only support radix == 10 and only positive numbers
+    if (10 != radix) return 1;
+    if (0 > num) return 2;
+    if (NULL == buffer) return 3;
+    if (2 > sizeInCharacters) return 4;
+
+    // take care of the trivial case
+    if (0 == num)
+    {
+        buffer[0] = '\0';
+        buffer[1] = '\0';
+    }
+
+    // get length of final string (dumb implementation)
+    len = 0;
+    tmpNum = num;
+    while (0 < tmpNum)
+    {
+        tmpNum /= 10;
+        len++;
+    }
+
+    if (len >= sizeInCharacters) return 5;
+
+    // convert num into a string (backwards)
+    buffer[len] = '\0';
+    while(0 < num && 0 < len)
+    {
         len--;
-               buffer[len] = (WCHAR)((num % 10) + '0');
-               num /= 10;
-       }
+        buffer[len] = (WCHAR)((num % 10) + '0');
+        num /= 10;
+    }
 
-       return 0;
+    return 0;
 }
 
 LPWSTR TP_sstr(LPWSTR str, LPWSTR searchStr)
 {
-       LPWSTR start;
-       LPWSTR current;
-       LPWSTR searchCurrent;
-
-       if (NULL == str || NULL == searchStr) return NULL;
-
-       // return a pointer to where searchStr
-       //  exists in str
-       current = str;
-       start   = NULL;
-       searchCurrent = searchStr;
-       while('\0' != *current)
-       {
-               if (NULL != start && '\0' == *searchCurrent)
-               {
-                       break;
-               }
-
-               if (*current == *searchCurrent)
-               {
-                       searchCurrent++;
-                       if (NULL == start) start = current;
-               }
-               else
-               {
-                       searchCurrent = searchStr;
-                       start = NULL;
-               }
-               current++;
-       }
-
-       return start;
+    LPWSTR start;
+    LPWSTR current;
+    LPWSTR searchCurrent;
+
+    if (NULL == str || NULL == searchStr) return NULL;
+
+    // return a pointer to where searchStr
+    //  exists in str
+    current = str;
+    start   = NULL;
+    searchCurrent = searchStr;
+    while('\0' != *current)
+    {
+        if (NULL != start && '\0' == *searchCurrent)
+        {
+            break;
+        }
+
+        if (*current == *searchCurrent)
+        {
+            searchCurrent++;
+            if (NULL == start) start = current;
+        }
+        else
+        {
+            searchCurrent = searchStr;
+            start = NULL;
+        }
+        current++;
+    }
+
+    return start;
 }
 
 DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer)
 {
 #ifdef WINDOWS
-       return GetFullPathNameW(fileName, nBufferLength, lpBuffer, NULL);
+    return GetFullPathNameW(fileName, nBufferLength, lpBuffer, NULL);
 #else
-       char nativeFullPath[MAX_PATH];
-       (void)realpath(HackyConvertToSTR(fileName), nativeFullPath);
-       LPWSTR fullPathForCLR = HackyConvertToWSTR(nativeFullPath);
-       wcscpy_s(lpBuffer, MAX_PATH, fullPathForCLR);
-       return wcslen(lpBuffer);
+    char nativeFullPath[MAX_PATH];
+    (void)realpath(HackyConvertToSTR(fileName), nativeFullPath);
+    LPWSTR fullPathForCLR = HackyConvertToWSTR(nativeFullPath);
+    wcscpy_s(lpBuffer, MAX_PATH, fullPathForCLR);
+    return wcslen(lpBuffer);
 #endif
 }
 DWORD TP_CreateThread(THREAD_ID* tThread, LPTHREAD_START_ROUTINE worker,  LPVOID lpParameter)
 {
 #ifdef WINDOWS
-       DWORD ret;
-       *tThread = CreateThread(
-               NULL,
-               0,
-               worker,
-               lpParameter,
-               0,
-               &ret);
-       return ret;
+    DWORD ret;
+    *tThread = CreateThread(
+        NULL,
+        0,
+        worker,
+        lpParameter,
+        0,
+        &ret);
+    return ret;
 #else
-       pthread_create(
-               tThread,
-               NULL,
-               (MacWorker)worker,
-               lpParameter);
+    pthread_create(
+        tThread,
+        NULL,
+        (MacWorker)worker,
+        lpParameter);
 #ifdef MAC64
-       // This is a major kludge...64 bit posix threads just can't be cast into a DWORD and there just isn't
-       // a great way to get what we're using for the ID. The fact that we're casting this at all is kind of
-       // silly since we're returing the actual thread handle and everything being done to manipulate the thread
-       // is done with that. Anyhow, the only thing done with the dword returned from this method is a printf
-       // which is good since this DWORD really shouldn't be reliably used. Just in case it is though, return
-       // a value that can be traced back to here.
-       return 42;
+    // This is a major kludge...64 bit posix threads just can't be cast into a DWORD and there just isn't
+    // a great way to get what we're using for the ID. The fact that we're casting this at all is kind of
+    // silly since we're returing the actual thread handle and everything being done to manipulate the thread
+    // is done with that. Anyhow, the only thing done with the dword returned from this method is a printf
+    // which is good since this DWORD really shouldn't be reliably used. Just in case it is though, return
+    // a value that can be traced back to here.
+    return 42;
 #else
-       return (DWORD)*tThread;
+    return (DWORD)*tThread;
 #endif
 #endif
 }
@@ -318,8 +318,184 @@ DWORD TP_CreateThread(THREAD_ID* tThread, LPTHREAD_START_ROUTINE worker,  LPVOID
 void TP_JoinThread(THREAD_ID tThread)
 {
 #ifdef WINDOWS
-       WaitForSingleObject(tThread, INFINITE);
+    WaitForSingleObject(tThread, INFINITE);
 #else
-       pthread_join(tThread, NULL);
+    pthread_join(tThread, NULL);
 #endif
 }
+
+#define INTSAFE_E_ARITHMETIC_OVERFLOW       ((HRESULT)0x80070216L)  // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW
+#define ULONG_ERROR     (0xffffffffUL)
+#define WIN32_ALLOC_ALIGN (16 - 1)
+//
+// ULONGLONG -> ULONG conversion
+//
+HRESULT ULongLongToULong(ULONGLONG ullOperand, ULONG* pulResult)
+{
+    HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+    *pulResult = ULONG_ERROR;
+    
+    if (ullOperand <= ULONG_MAX)
+    {
+        *pulResult = (ULONG)ullOperand;
+        hr = S_OK;
+    }
+    
+    return hr;
+}
+
+HRESULT ULongAdd(ULONG ulAugend, ULONG ulAddend,ULONG* pulResult)
+{
+    HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+    *pulResult = ULONG_ERROR;
+
+    if ((ulAugend + ulAddend) >= ulAugend)
+    {
+        *pulResult = (ulAugend + ulAddend);
+        hr = S_OK;
+    }
+    
+    return hr;
+}
+
+HRESULT ULongMult(ULONG ulMultiplicand, ULONG ulMultiplier, ULONG* pulResult)
+{
+    ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier);
+    
+    return ULongLongToULong(ull64Result, pulResult);
+}     
+
+HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result)
+{
+    if (result == NULL)
+        return E_INVALIDARG;
+
+    // +2 for the null terminator
+    // + DWORD_PTR to store the byte length of the string
+    int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN;
+
+    if (isByteLen)
+    {
+        if (SUCCEEDED(ULongAdd(constant, cchSize, result)))
+        {
+            *result = *result & ~WIN32_ALLOC_ALIGN;
+            return S_OK;
+        }
+    }
+    else
+    {
+        ULONG temp = 0; // should not use in-place addition in ULongAdd
+        if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) &
+            SUCCEEDED(ULongAdd(temp, constant, result)))
+        {
+            *result = *result & ~WIN32_ALLOC_ALIGN;
+            return S_OK;
+        }
+    }
+    return INTSAFE_E_ARITHMETIC_OVERFLOW;
+}
+
+BSTR TP_SysAllocString(LPWSTR psz)
+{
+#ifdef WINDOWS    
+    return SysAllocString(psz);
+#else
+    if(psz == NULL)
+        return NULL;
+    return TP_SysAllocStringLen(psz, (DWORD)wcslen(psz));
+#endif
+}
+
+BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len)
+{
+    ULONG cbTotal = 0;
+
+    if (FAILED(CbSysStringSize((ULONG)len, FALSE, &cbTotal)))
+        return NULL;
+
+    BSTR bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal);
+
+    if(bstr != NULL){
+
+#if defined(_WIN64)
+      // NOTE: There are some apps which peek back 4 bytes to look at the size of the BSTR. So, in case of 64-bit code,
+      // we need to ensure that the BSTR length can be found by looking one DWORD before the BSTR pointer. 
+      *(DWORD_PTR *)bstr = (DWORD_PTR) 0;
+      bstr = (BSTR) ((char *) bstr + sizeof (DWORD));
+#endif
+      *(DWORD *)bstr = (DWORD)len * sizeof(OLECHAR);
+
+      bstr = (BSTR) ((char*) bstr + sizeof(DWORD));
+
+      if(psz != NULL){
+            memcpy(bstr, psz, len * sizeof(OLECHAR));
+      }
+
+      bstr[len] = '\0'; // always 0 terminate
+    }
+
+    return bstr; 
+}
+
+BSTR TP_SysAllocStringByteLen(LPCSTR psz, size_t len)
+{
+#ifdef WINDOWS    
+    return SysAllocStringByteLen(psz, (UINT)len);
+#else
+    BSTR bstr;
+    ULONG cbTotal = 0;
+
+    if (FAILED(CbSysStringSize(len, TRUE, &cbTotal)))
+        return NULL;
+
+    bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal);
+
+    if (bstr != NULL) {
+#if defined(_WIN64)
+      *(DWORD *)((char *)bstr + sizeof (DWORD)) = (DWORD)len;
+#else
+      *(DWORD *)bstr = (DWORD)len;
+#endif
+
+      bstr = (WCHAR*) ((char*) bstr + sizeof(DWORD_PTR));
+
+      if (psz != NULL) {
+            memcpy(bstr, psz, len);
+      }
+
+      // NULL-terminate with both a narrow and wide zero.
+      *((char *)bstr + len) = '\0';
+      *(WCHAR *)((char *)bstr + ((len + 1) & ~1)) = 0;
+    }
+
+    return bstr;
+#endif    
+}
+
+void TP_SysFreeString(BSTR bstr)
+{
+#ifdef WINDOWS    
+    return SysFreeString(bstr);
+#else
+    if (bstr == NULL)
+      return;
+    TP_CoTaskMemFree((BYTE *)bstr - sizeof(DWORD_PTR));  
+#endif    
+}
+
+size_t TP_SysStringByteLen(BSTR bstr)
+{
+#ifdef WINDOWS    
+    return SysStringByteLen(bstr);
+#else   
+    if(bstr == NULL)
+      return 0;
+    int32_t * p32 = (int32_t *) bstr;
+    int32_t * p32_1 = p32 -1;
+    DWORD * d32 = (DWORD *) bstr;
+    DWORD * d32_1 = d32 - 1;
+    //std::cout << p32 << p32_1 << endl;
+    //std::cout << d32 << d32_1 << endl;
+    return (unsigned int)(((DWORD *)bstr)[-1]);
+#endif    
+}
index 0961e86..aa96483 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <cstdint>
 
 #ifndef _PLATFORMDEFINES__H
 #define _PLATFORMDEFINES__H
@@ -19,7 +20,7 @@
 #define FS_SEPERATOR L"\\"
 #define PATH_DELIMITER L";"
 #define L(t) L##t
-
+#define W(str)  L##str
 
 typedef unsigned error_t;
 typedef HANDLE THREAD_ID;
@@ -30,11 +31,34 @@ typedef HANDLE THREAD_ID;
 #include <pthread.h>
 
 typedef char16_t WCHAR;
-typedef unsigned long DWORD;
+typedef unsigned int DWORD;
 typedef int BOOL;
 typedef WCHAR *LPWSTR, *PWSTR;
 typedef const WCHAR *LPCWSTR, *PCWSTR;
 
+typedef long HRESULT;
+#define LONGLONG long long
+#define ULONGLONG unsigned LONGLONG
+typedef unsigned long ULONG, *PULONG;
+#define S_OK                    0x0
+#define SUCCEEDED(_hr)          ((HRESULT)(_hr) >= 0)
+#define FAILED(_hr)             ((HRESULT)(_hr) < 0)
+
+#ifdef ULONG_MAX
+#undef ULONG_MAX
+#endif
+#define ULONG_MAX     0xffffffffUL
+#define CCH_BSTRMAX 0x7FFFFFFF  // 4 + (0x7ffffffb + 1 ) * 2 ==> 0xFFFFFFFC
+#define CB_BSTRMAX 0xFFFFFFFa   // 4 + (0xfffffff6 + 2) ==> 0xFFFFFFFC
+
+#ifdef RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) _sc
+#else // RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
+#endif // RC_INVOKED
+#define E_INVALIDARG                     _HRESULT_TYPEDEF_(0x80070057L)
+#define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b)))
+
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -51,9 +75,11 @@ typedef const WCHAR *LPCWSTR, *PCWSTR;
 #if __i386__
 #define __stdcall __attribute__((stdcall))
 #define _cdecl __attribute__((cdecl))
+#define __cdecl __attribute__((cdecl))
 #else
 #define __stdcall
 #define _cdecl
+#define __cdecl
 #endif
 #endif
 
@@ -63,11 +89,12 @@ typedef const WCHAR *LPCWSTR, *PCWSTR;
 #define DLL_EXPORT
 #endif
 
-LPWSTR HackyConvertToWSTR(char* pszInput);
+LPWSTR HackyConvertToWSTR(const char* pszInput);
 
 #define FS_SEPERATOR L("/")
 #define PATH_DELIMITER L(":")
 #define L(t) HackyConvertToWSTR(t)
+#define W(str)  u##str
 #define MAX_PATH 260
 
 typedef pthread_t THREAD_ID;
@@ -91,6 +118,8 @@ typedef unsigned char BYTE;
 typedef WCHAR OLECHAR;
 #endif
 
+typedef ULONG_PTR DWORD_PTR;
+
 //
 // Method declarations
 //
@@ -110,6 +139,13 @@ void TP_JoinThread(THREAD_ID tThread);
 void TP_DebugBreak();
 DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer);
 
+typedef WCHAR* BSTR;
+BSTR TP_SysAllocStringByteLen(LPSTR psz, size_t len);
+void TP_SysFreeString(BSTR bstr);
+size_t TP_SysStringByteLen(BSTR bstr);
+BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len);
+BSTR TP_SysAllocString(LPWSTR psz);
+
 //
 // Method redirects
 //
index 83c844e..9e6be4f 100644 (file)
@@ -3,7 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 #include <xplatform.h>
-
+#include "platformdefines.h"
 const int ARRAY_SIZE = 100;
 template<typename T> bool IsObjectEquals(T o1, T o2);
 
index fad9760..7b509d6 100644 (file)
@@ -2,6 +2,7 @@ if(WIN32)
     list(APPEND LINK_LIBRARIES_ADDITIONAL
         ole32.lib
         advapi32.lib
+        OleAut32.lib
     )
 endif(WIN32)
 
@@ -26,6 +27,7 @@ add_subdirectory(RefCharArray)
 add_subdirectory(StringMarshalling/LPSTR)
 add_subdirectory(StringMarshalling/LPTSTR)
 add_subdirectory(StringMarshalling/UTF8)
+add_subdirectory(StringMarshalling/BSTR)
 add_subdirectory(MarshalAPI/FunctionPointer)
 add_subdirectory(MarshalAPI/IUnknown)
 add_subdirectory(SizeConst)
diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs
new file mode 100644 (file)
index 0000000..fbd0b72
--- /dev/null
@@ -0,0 +1,200 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System;
+using System.Reflection;
+using System.Text;
+using NativeDefs;
+
+class Test
+{
+
+    #region "Report Failure"
+    static int fails = 0; //record the fail numbers
+    // Overload methods for reportfailure      
+    static int ReportFailure(string s)
+    {
+        Console.WriteLine(" === Fail:" + s);
+        return (++fails);
+    }
+    static int ReportFailure(string expect, string actual)
+    {
+        Console.WriteLine(" === Fail: Expected:" + expect + "\n          Actual:" + actual);
+        return (++fails);
+    }
+    static int ReportFailure(string describe, string expect, string actual)
+    {
+        Console.WriteLine(" === Fail: " + describe + "\n\tExpected:" + expect + "\n\tActual:" + actual);
+        return (++fails);
+    }
+    #endregion
+
+    #region "Helper"
+    // ************************************************************
+    // Returns the appropriate exit code
+    // *************************************************************
+    static int ExitTest()
+    {
+        if (fails == 0)
+        {
+            Console.WriteLine("PASS");
+            return 100;
+        }
+        else
+        {
+            Console.WriteLine("FAIL - " + fails + " failure(s) occurred");
+            return 101;
+        }
+    }
+    #endregion
+
+    #region ReversePInvoke
+
+    public static string Call_DelMarshal_InOut(string s)
+    {
+        string strRet;
+        if (!s.Equals("\u0148"))
+        {
+            Console.WriteLine(s.Length);
+            ReportFailure("Method Call_DelMarshal_InOut[Managed Side],The passed string is wrong", "\u0148", s);
+            strRet = "\0\0\0";
+            return strRet;
+        }
+        s = "Managed";
+        strRet = "Return\0Return\0";
+        return strRet;
+    }
+
+    public static string Call_DelMarshalPointer_Out(out string s)
+    {
+        s = "Native\0String\0";
+        string strRet = "Return\0Return\0";
+        return strRet;
+    }
+
+    public static StringBuilder Call_Del_MarshalStrB_InOut(StringBuilder r)
+    {
+        StringBuilder retstr = new StringBuilder("Return\0Native");
+
+        if (!r.ToString().Equals(new StringBuilder("a", 1).ToString()))
+        {
+            ReportFailure("Method Call_Del_MarshalStrB_InOut[Managed Side] Failure. String is different than expected", "ă", r.ToString());
+        }
+        r.Replace('a', 'm');
+        return retstr;
+    }
+
+    public static StringBuilder Call_Del_MarshalStrB_Out(out StringBuilder r)
+    {
+        StringBuilder retstr = new StringBuilder("Native\0Native");
+        r = new StringBuilder("Managed", 7);
+        return retstr;
+    }
+
+    #endregion
+
+    public static int Main(string[] args)
+    {
+#pragma warning disable 0219
+        string strManaged = "Managed\0String\0";
+        string strRet = "a";
+        StringBuilder strBRet = new StringBuilder("a", 1);
+        string strNative = " Native";
+        StringBuilder strBNative = new StringBuilder(" Native", 7);
+#pragma warning restore 0219
+
+        //since the out attributes doesnt work for string, so i dont check the out value.
+        string strPara2 = strManaged;
+        string strRet2 = PInvokeDef.Marshal_InOut(strPara2);
+        if (!strRet2.Equals(strRet))
+        {
+            ReportFailure("Method PInvokeDef.Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet2);
+        }
+        if (!strPara2.Equals(strManaged))
+        {
+            ReportFailure("Method PInvokeDef.Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara2);
+        }
+
+        //TestMethod3
+        string strPara3 = strManaged;
+        string strRet3 = PInvokeDef.Marshal_Out(strPara3);
+        if (!strRet.Equals(strRet3))
+        {
+            ReportFailure("Method PInvokeDef.Marshal_Out[Managed Side],The Return string is wrong", strRet, strRet3);
+        }
+        if (!strPara3.Equals(strManaged))
+        {
+            ReportFailure("Method PInvokeDef.Marshal_Out[Managed Side],The Parameter string is not Changed", strManaged, strPara3);
+        }
+
+        //TestMethod5
+        string strPara5 = strManaged;
+        string strRet5 = PInvokeDef.MarshalPointer_InOut(ref strPara5);
+
+        if (!strRet5.Equals(strRet))
+        {
+            ReportFailure("Method PInvokeDef.MarshalPointer_InOut[Managed Side],The Return string is wrong", strRet, strRet5);
+        }
+        if (!strPara5.Equals(strNative))
+        {
+            ReportFailure("Method PInvokeDef.MarshalPointer_InOut[Managed Side],The Passed string is wrong", strNative, strPara5);
+        }
+
+        //TestMethod6
+        string strPara6 = strManaged;
+        string strRet6 = PInvokeDef.MarshalPointer_Out(out strPara6);
+        if (!strRet6.Equals(strRet))
+        {
+            ReportFailure("Method PInvokeDef.MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet6);
+        }
+        if (!strPara6.Equals(strNative))
+        {
+            ReportFailure("Method PInvokeDef.MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara6);
+        }
+
+        #region ReversePinvoke
+        DelMarshal_InOut d1 = new DelMarshal_InOut(Call_DelMarshal_InOut);
+        if (!PInvokeDef.RPinvoke_DelMarshal_InOut(d1, "\u0148"))
+        {
+            ReportFailure("Method RPinvoke_DelMarshal_InOut[Managed Side],Return value is false");
+        }
+
+        DelMarshalPointer_Out d2 = new DelMarshalPointer_Out(Call_DelMarshalPointer_Out);
+        if (!PInvokeDef.RPinvoke_DelMarshalPointer_Out(d2))
+        {
+            ReportFailure("Method RPinvoke_DelMarshal_Out[Managed Side],Return value is false");
+        }
+
+        #endregion
+        #region DelegatePInvoke
+
+        Del_Marshal_InOut d3 = new Del_Marshal_InOut(PInvokeDef.Marshal_InOut);
+        string strPara9 = strManaged;
+        string strRet9 = d3(strPara9);
+        if (!strRet9.Equals(strRet))
+        {
+            ReportFailure("Method Del_Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet9);
+        }
+        if (!strPara9.Equals(strManaged))
+        {
+            ReportFailure("Method Del_Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara9);
+        }
+
+        Del_MarshalPointer_Out d4 = new Del_MarshalPointer_Out(PInvokeDef.MarshalPointer_Out);
+        string strPara10 = strManaged;
+        string strRet10 = d4(out strPara10);
+        if (!strRet10.Equals(strRet))
+        {
+            ReportFailure("Method Del_MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet10);
+        }
+        if (!strPara10.Equals(strNative))
+        {
+            ReportFailure("Method Del_MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara10);
+        }
+
+        #endregion
+        return ExitTest();
+    }
+}
diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj
new file mode 100644 (file)
index 0000000..05c7287
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>BSTRTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{176EC495-7AE9-42CF-A591-06A382DB4048}</ProjectGuid>
+    <OutputType>exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />    
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>
+    <ProjectReference Include="CMakeLists.txt">
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp b/tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp
new file mode 100644 (file)
index 0000000..9a4668b
--- /dev/null
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "platformdefines.h"
+
+WCHAR strManaged[] = W("Managed\0String\0");
+size_t lenstrManaged = sizeof(strManaged) - sizeof(WCHAR);
+
+WCHAR strReturn[] = W("a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+WCHAR strerrReturn[] = W("error");
+
+WCHAR strNative[] = W(" Native");
+size_t lenstrNative = sizeof(strNative) - sizeof(WCHAR);
+
+//Test Method1
+extern "C" BSTR ReturnString()
+{
+    return TP_SysAllocString(strReturn);
+}
+
+extern "C" BSTR ReturnErrorString()
+{
+    return TP_SysAllocString(strerrReturn);
+}
+
+//Test Method2
+extern "C" DLL_EXPORT BSTR Marshal_InOut(/*[In,Out]*/BSTR s)
+{
+    //Check the Input
+    size_t len = TP_SysStringByteLen(s);
+
+    if (len != lenstrManaged || memcmp(s,strManaged,lenstrManaged) != 0)
+    {
+        printf("Error in Function Marshal_InOut(Native Client)\n");
+        printf("Error: Actual: %d, Expected: %d\n",(int32_t) len, (int32_t)lenstrManaged);
+
+        return ReturnErrorString();
+    }
+
+    //In-Place Change
+    memcpy(s, strNative, len);
+
+    //Return
+    return ReturnString();
+}
+
+
+extern "C" DLL_EXPORT BSTR Marshal_Out(/*[Out]*/BSTR s)
+{
+    s = TP_SysAllocString(strNative);
+        
+    //Return
+    return ReturnString();
+}
+
+
+extern "C" DLL_EXPORT BSTR MarshalPointer_InOut(/*[in,out]*/BSTR *s)
+{    
+    //Check the Input
+    size_t len = TP_SysStringByteLen(*s);
+
+    if (len != lenstrManaged || memcmp(*s,strManaged,lenstrManaged)!=0)
+    {
+        printf("Error in Function MarshalPointer_InOut\n");
+        printf("Error: Expected: %d, Actual: %d", (int32_t)lenstrManaged, (int32_t)len);
+
+        return ReturnErrorString();
+    }
+
+    //Allocate New
+    TP_SysFreeString(*s);
+    *s = TP_SysAllocString(strNative);
+
+    //Return
+    return ReturnString();
+}
+
+extern "C" DLL_EXPORT BSTR MarshalPointer_Out(/*[out]*/ BSTR *s)
+{
+    *s = TP_SysAllocString(strNative);
+    return ReturnString();
+}
+
+typedef BSTR (__stdcall * Test_DelMarshal_InOut)(/*[in]*/ BSTR s);
+extern "C" DLL_EXPORT BOOL __cdecl RPinvoke_DelMarshal_InOut(Test_DelMarshal_InOut d, /*[in]*/ BSTR s)
+{
+    BSTR str = d(s);
+    WCHAR ret[] = W("Return\0Return\0");    
+
+    size_t lenstr = TP_SysStringByteLen(str);
+    size_t lenret = sizeof(ret) - sizeof(WCHAR);
+
+    if (lenret != lenstr || memcmp(str,ret,lenstr) != 0)
+    {
+        printf("Error in RPinvoke_DelMarshal_InOut, Returned value didn't match\n");
+        return FALSE;
+    }
+
+    TP_SysFreeString(str);
+    return TRUE;
+}
+
+//
+// PInvokeDef.cs explicitly declares that RPinvoke_DelMarshalPointer_Out uses STDCALL
+//
+typedef BSTR (__cdecl * Test_DelMarshalPointer_Out)(/*[out]*/ BSTR * s);
+extern "C" DLL_EXPORT BOOL __stdcall RPinvoke_DelMarshalPointer_Out(Test_DelMarshalPointer_Out d)
+{
+    BSTR str;
+    BSTR ret = d(&str);
+
+    WCHAR changedstr[] = W("Native\0String\0");
+
+    size_t lenstr = TP_SysStringByteLen(str);
+    size_t lenchangedstr = sizeof(changedstr) - sizeof(WCHAR);
+
+    if ( lenstr != lenchangedstr || (memcmp(str,changedstr,lenstr)!=0))
+    {
+        printf("Error in RPinvoke_DelMarshalPointer_Out, Value didn't change\n");
+        return FALSE;
+    }
+
+    WCHAR expected[] = W("Return\0Return\0");
+    size_t lenret = TP_SysStringByteLen(ret);
+    size_t lenexpected = sizeof(expected) - sizeof(WCHAR);
+
+    if (lenret != lenexpected || memcmp(ret,expected,lenret)!=0)
+    {
+        printf("Error in RPinvoke_DelMarshalPointer_Out, Return vaue is different than expected\n");
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+//
+// PInvokeDef.cs explicitly declares that ReverseP_MarshalStrB_InOut uses STDCALL
+//
+typedef BSTR (__stdcall * Test_Del_MarshalStrB_InOut)(/*[in,out]*/ BSTR s);
+extern "C" DLL_EXPORT  BOOL __stdcall ReverseP_MarshalStrB_InOut(Test_Del_MarshalStrB_InOut d, /*[in]*/ BSTR s)
+{
+    BSTR ret = d((BSTR)s);
+    WCHAR expected[] = W("Return");
+    size_t lenret = TP_SysStringByteLen(ret);
+    size_t lenexpected = sizeof(expected) - sizeof(WCHAR);
+
+    if (lenret != lenexpected || memcmp(ret,expected,lenret) != 0)
+    {
+        printf("Error in ReverseP_MarshalStrB_InOut, Return vaue is different than expected\n");
+        return FALSE;
+    }
+
+    WCHAR expectedchange[] = W("m");
+    size_t lenstr = TP_SysStringByteLen(s);
+    size_t lenexpectedchange = sizeof(expectedchange) - sizeof(WCHAR);
+    
+    if (lenstr != lenexpectedchange || memcmp(s,expectedchange,lenstr) != 0)
+    {
+        printf("Error in ReverseP_MarshalStrB_InOut, Value didn't get change\n");
+        return FALSE;
+    }
+    return TRUE;
+}
diff --git a/tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt b/tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d485437
--- /dev/null
@@ -0,0 +1,18 @@
+cmake_minimum_required (VERSION 2.6)
+project (BSTRTestNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES BSTRTestNative.cpp)
+
+# add the executable
+add_library (BSTRTestNative SHARED ${SOURCES})
+
+if(WIN32)
+    list(APPEND LINK_LIBRARIES_ADDITIONAL
+        OleAut32.lib
+    )
+endif(WIN32)
+
+target_link_libraries(BSTRTestNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS BSTRTestNative DESTINATION bin)
diff --git a/tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs b/tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs
new file mode 100644 (file)
index 0000000..241eeff
--- /dev/null
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System;
+using System.Reflection;
+using System.Text;
+
+namespace NativeDefs
+{
+    
+    [return: MarshalAs(UnmanagedType.BStr)]
+    public delegate string Del_MarshalPointer_Out([MarshalAs(UnmanagedType.BStr)] out string s);
+    
+    [return: MarshalAs(UnmanagedType.BStr)]
+    public delegate string Del_Marshal_InOut([MarshalAs(UnmanagedType.BStr)]string s);
+    
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+    [return: MarshalAs(UnmanagedType.BStr)]
+    public delegate string DelMarshalPointer_Out([MarshalAs(UnmanagedType.BStr)][Out] out string s);
+
+    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
+    [return: MarshalAs(UnmanagedType.BStr)]
+    public delegate string DelMarshal_InOut([MarshalAs(UnmanagedType.BStr)][In, Out]string s);
+
+    public static class PInvokeDef
+    {
+        public const string NativeBinaryName = "BSTRTestNative";
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.BStr)]
+        public static extern string Marshal_InOut([In, Out][MarshalAs(UnmanagedType.BStr)]string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.BStr)]
+        public static extern string Marshal_Out([Out][MarshalAs(UnmanagedType.BStr)]string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.BStr)]
+        public static extern string MarshalPointer_InOut([MarshalAs(UnmanagedType.BStr)]ref string s);
+
+        [DllImport(NativeBinaryName)]
+        [return: MarshalAs(UnmanagedType.BStr)]
+        public static extern string MarshalPointer_Out([MarshalAs(UnmanagedType.BStr)]out string s);
+
+        [DllImport(NativeBinaryName, CallingConvention = CallingConvention.Cdecl)]
+        public static extern bool RPinvoke_DelMarshal_InOut(DelMarshal_InOut d, [MarshalAs(UnmanagedType.BStr)]string s);
+
+        [DllImport(NativeBinaryName, CallingConvention = CallingConvention.StdCall)]
+        public static extern bool RPinvoke_DelMarshalPointer_Out(DelMarshalPointer_Out d);
+    }
+}
index 37c1454..1443e59 100755 (executable)
@@ -9,7 +9,6 @@
 #define INT_MIN           (-2147483647 - 1)
 
 typedef char16_t WCHAR;
-typedef unsigned long DWORD;
 typedef int BOOL;
 typedef WCHAR *LPWSTR, *PWSTR;
 typedef const WCHAR *LPCWSTR, *PCWSTR;
@@ -18,7 +17,6 @@ typedef char* LPSTR;
 typedef const char* LPCSTR;
 typedef void* FARPROC;
 typedef void* HMODULE;
-typedef void* ULONG_PTR;
 typedef unsigned error_t;
 typedef void* LPVOID;
 typedef unsigned char BYTE;
@@ -37,8 +35,6 @@ typedef unsigned short USHORT;
 typedef signed short SHORT;
 typedef unsigned short WORD, *PWORD, *LPWORD;
 
-typedef int*  DWORD_PTR;
-
 #ifndef TRUE
 #define TRUE 1
 #endif