1

VS2012でC#言語でDLL(C書き込み)を呼び出しています。mylib.dll は C# で呼び出すネイティブ dll であり、mylib.dll は別の mylib_another.dll も呼び出します。

C 関数の宣言は次のとおりです。

extern DECLSPEC_DLL BOOLEAN_TYPE SetConnection(char *dev, char *addr); 

My C# file で、次のように宣言します。

[DllImport("C:\\mylib.dll", EntryPoint = "SetConnection", CharSet = CharSet.Auto)]
public static unsafe extern int SetConnection(StringBuilder  dev,  StringBuilder addr);

コードで呼び出すと、文字列が 1 文字しか渡されないことがわかりました。dev を "USB" として渡すと、ネイティブ DLL は実際には "U" しか取得しません。

宣言を次のように変更すると:

[DllImport("C:\\mylib.dll", EntryPoint = "SetConnection", CharSet = CharSet.Ansi)]
public static unsafe extern int SetConnection(StringBuilder  dev,  StringBuilder addr);

次に、 System.AccessViolationException Exception が発生します。

System.Reflection.TargetInvocationException was unhandled
HResult=-2146232828
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib
StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at QC.QTMDotNetKernel.DotNetKernel.RunDotNetTest(Object stateObject)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException: System.AccessViolationException
   HResult=-2147467261
   Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

それについてのアイデアはありますか?

以下のように解決しました(答えは最初の質問、2番目の質問に対するものです。これは、mylib.dllが別のネイティブdllを呼び出し、システムがそれを見つけられなかったためです)。

同様の問題がここにあります:

4

2 に答える 2

3

このような 1 文字しか受信しない場合、通常は、ASCII、UTF8、ANSI などの 8 ビット形式を想定している C/C++ 関数に Unicode (UTF16) 文字列を渡していることを意味します。

16 ビットの Unicode 形式では、最終的に ASCII/ANSI 範囲の文字の 2 バイトのうち 1 バイトがゼロに設定されます。C/C++ プログラムはゼロ バイトを文字列の終わりの文字として扱うため、切り捨てられます。文字列。

ANSI を使用して、それが役立つかどうかを確認するのは簡単です。変化する

CharSet = CharSet.Auto

CharSet = CharSet.Ansi
于 2013-06-07T23:23:24.890 に答える
0

p/invoke にはいくつか問題があります。

  1. 呼び出し規約は のようcdeclです。ネイティブ コードでは指定されておらず、最も可能性の高いデフォルトは ですcdecl
  2. StringBuilderパラメータに使用されるものを渡していoutます。2 つのパラメーターは両方とも入力パラメーターであると想定していることに注意してください。
  3. 文字セットが間違っています。ネイティブ コードは、8 ビットでエンコードされたテキストを受け取ります。
  4. を使用する必要はありませんunsafe

訂正された宣言は次のとおりです。

[DllImport(@"C:\mylib.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int SetConnection(string dev, string addr);

ANSIがデフォルトなので、文字セットの指定は省略できます。もちろん、CharSet=CharSet.Ansi明示的にしたい場合は指定しても問題ありません。EntryPoint宣言する関数と同じ名前であるかどうかを指定する必要はありません。

于 2013-06-10T17:11:55.007 に答える