我正在使用Pinvoke進行原生(C++)代碼和託管(C#)代碼之間的互操作性。我想實現的是從本機代碼中獲取一些文本到我的託管代碼中。爲此,我嘗試了很多東西,例如使用[IN]和[OUT]傳遞string/stringbuilder,封裝LPSTR,從函數等返回字符串,但在我的情況下沒有任何效果。任何幫助一些小代碼將不勝感激。如何從原生(C++)代碼返回文本
25
A
回答
42
,因爲這意味着你不必兩次調用本機每串,一旦獲得的長度,然後一旦獲得的內容我會用BSTR
做到這一點。
隨着BSTR
編組人員將負責釋放BSTR
與正確的內存管理器,以便您可以安全地將它從您的C++代碼中傳出。
C++
#include <comutil.h>
BSTR GetSomeText()
{
return ::SysAllocString(L"Greetings from the native world!");
}
C#
[DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetSomeText();
還有就是BSTR
之一小缺點,即它帶有UTF-16有效負載,但源數據可能是char*
。
爲了克服這一點,你可以從char*
轉換包到BSTR
這樣的:
BSTR ANSItoBSTR(const char* input)
{
BSTR result = NULL;
int lenA = lstrlenA(input);
int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
if (lenW > 0)
{
result = ::SysAllocStringLen(0, lenW);
::MultiByteToWideChar(CP_ACP, 0, input, lenA, result, lenW);
}
return result;
}
這是最難的一個出路,現在可以很容易地添加其他包裝從LPWSTR
轉換爲BSTR
,std::string
,std::wstring
等
3
4
這裏是通過C#這樣的一個例子。我通過pInvoking通過C#調用Native函數GetWindowText
。 GetWindowText
返回窗口的標題,該窗口的handle
傳遞給它。
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
public static string GetText(IntPtr hWnd)
{
// Allocate correct string length first
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
string str = GetText(this.Handle);
}
0
如果你要返回一個char *
,並且不想修改C/C++代碼來爲你的返回值分配內存(或者你不能修改那個代碼),那麼你可以改變你的C#extern函數原型返回IntPtr
,並進行自己的編組。
舉例來說,這裏是我寫的Pocketsphinx互操作的一個片段:
[DllImport("sphinxbase.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr /* char const * */ jsgf_grammar_name(IntPtr /* jsgf_t * */ jsgf);
而這裏的get訪問爲C#JsgfGrammar
類。 m_pU
是一個IntPtr
,它指向原始對象jsgf_t
。
public string Name
{
get
{
IntPtr pU = jsgf_grammar_name(m_pU);
if (pU == IntPtr.Zero)
strName = null;
else
strName = Marshal.PtrToStringAnsi(pU);
return strName;
}
}
修改這個例子的其他字符串格式(例如Unicode)應該是微不足道的。
相關問題
- 1. 如何使用c代碼從shell腳本獲取返回值
- 2. 你如何從原生Android代碼
- 3. Android C++原生代碼
- 4. 如何從C#代碼隱藏生成sql腳本文件?
- 5. 如何從C代碼返回一個2D int數組到C#?
- 6. 從FORTRAN 77代碼返回值C#
- 7. 從原生c代碼創建一個文件android
- 8. 如何從sp_addlinkedserver檢索返回代碼?
- 9. 如何從pyparsing令牌返回原始文本
- 10. 如何從C#.NET代碼生成JS
- 11. 如何從ICompilationUnit(ICSharpCode)生成C#代碼
- 12. 如何使用ASP.net MVC 3 FileStreamResult返回.net代碼中生成的文本?
- 13. 反應原生谷歌登錄返回狀態代碼:12501
- 14. 如何從C++的主函數返回錯誤代碼?
- 15. 如何從C++函數返回多個錯誤代碼
- 16. 如何將INT轉換爲DWORD從GetExitCodeProcess返回代碼[C#]
- 17. 如何從pyrun_simplefile C代碼返回輸出
- 18. 如何從C#應用代碼返回Powershell DataTable對象?
- 19. Android:MediaRecorder @原生代碼
- 20. WP7原生代碼?
- 21. BitmapRegionDecoder原生代碼
- 22. 如何調用從本機代碼返回char []的Java方法?
- 23. 如何通過out參數將變量從iOS本機代碼返回給C#?
- 24. 從分機返回「原生」PHP對象
- 25. 如何生成c#代碼?
- 26. Android JNI原生C++代碼GetPrimitiveArrayCritical()問題
- 27. 如何從PGP獲取返回代碼命令行代碼
- 28. 如何從採購源代碼中返回源代碼?
- 29. 原生代碼生成
- 30. 如何在Android原生代碼
@rturrado非常感謝您在編輯中的更正。 – 2011-06-16 19:29:37
答案是非常有用的,所以它值得。順便說一句,只是意識到'可能char *'缺少'be'。 – rturrado 2011-06-16 22:50:56
您可以將'-1'作爲第四個參數傳遞給'MultiByteToWideChar'以使函數自動計算字符串的長度;避免需要自己調用'lstrlenA'。 – 2011-08-09 11:42:46