2013-11-23 2 views
1

내 프로젝트 중 하나에서 P/Invoke를 사용하여 avifil32.dll 메소드를 호출하고 모든 것이 지금까지 제대로 작동했습니다. 오늘, 몇 달 후 그 프로젝트로 돌아가고 그 동안 Windows 8로 전환함으로써, 나는 더 이상 아무것도 작동하지 않는다는 것을 발견했습니다. avifil32 메소드에 대한 대부분의 호출은 AccessViolationException ("보호 된 메모리 읽기 또는 쓰기 시도 ...")를 발생시킵니다. 내가 this 유용한 게시물을 발견하고 결과적으로 웹에 일부 검색 후C# LPCTSTR에서 마샬링이 더 이상 작동하지 않습니다.

[DllImport("avifil32.dll", PreserveSig=true)] 
static extern int AVIFileOpen(out IntPtr ppfile, string szFile, uint mode, int pclsidHandler); 

:

한 기능이 (또한 pinvoke.net here에 명시된) 이전에 나는이 방법으로 호출 된 AVIFileOpen이었다으로 하여금 나는 내 호출 (주 AVIFileOpenW) 변경 :

[DllImport("avifil32.dll", PreserveSig=true, CharSet = CharSet.Auto)] 
public static extern int AVIFileOpenW(ref int ppfile, [MarshalAs(UnmanagedType.LPWStr)] String szFile, int uMode, int pclsidHandler); 

을 지금은 작동합니다. 그러나 나는 다른 문제가있다. 예를 들어 나는 같은 예외를 가지고있다. AVIFileCreateStream

내가 뭘 잘못하고 있니? 그리고 더 흥미롭게도, 지금은 더 이상 작동하지 않는 이유가 될 수 있습니다. 나는 그동안 무슨 일이 일어 났는지 모른다. 큰 변화는 Windows 7에서 Windows 8로 넘어 가고 있지만 문제를 설명 할 수 있습니까?

편집


내가 전화를 호출 /를 P를 수정하지했고 지금은 더 이상 AccessViolationexception을했습니다 한스 옆모습의 sugestion에 따라. 그러나 전에 일하는 동안 그것은 여전히 ​​내게 미스터리입니다. 사실 현재 (Win8)와 이전 (Win7)에는 64 비트 OS가 있습니다. 그러나 프로젝트 설정에서 설명 할 수있는 또 다른 세부 사항이 있습니다. 이것은 내 프로젝트에서 호출 된 라이브러리 프로젝트입니다. 필자의 주요 프로젝트 대상은 x64 (x86을 대상으로하는 것은 옵션이 아님)이며, 라이브러리는 AnyCPU를 대상으로합니다. 나는이 설정으로 또 다른 재판을했고, 나의 이전 버전 인 AVIFileOpen은 Win7 x64 시스템에서는 작동하지만 Win8 x64에서는 작동하지 않는다. 이것은 JIT 컴파일러에 의해 AnyCPU의 다른 "관리"와 관련 될 수 있습니까, 아니면 내가 놓친 다른 설정이 있어야합니까?

이제 프로그램은 x86과 x64에서 모두 작동합니다. 여기에 코드의 추출 아래 내가 사용하고 있습니다 :

AVIFileInit(); 
IntPtr aviFile = IntPtr.Zero; 
IntPtr aviStream = IntPtr.Zero; 
string tmp = Path.GetTempFileName(); 
if (AVIFileOpen(out aviFile, tmp.Substring(0, tmp.Length - 4) + ".avi", OF_WRITE | OF_CREATE, IntPtr.Zero) == 0) 
{ 
    AVISTREAMINFO strhdr = new AVISTREAMINFO(); 
    strhdr.fccType = mmioStringToFOURCC("vids", 0); 
    strhdr.fccHandler = mmioStringToFOURCC("CVID", 0); 
    strhdr.dwScale = 1; 
    strhdr.dwRate = 25; 
    strhdr.dwSuggestedBufferSize = 102400; 
    strhdr.dwQuality = -1; 
    strhdr.rcFrame.bottom = 320; 
    strhdr.rcFrame.right = 320; 
    strhdr.szName = ""; 
    if (AVIFileCreateStream(aviFile, out aviStream, ref strhdr) == 0) 
    { 
     AVICOMPRESSOPTIONS_CLASS options = new AVICOMPRESSOPTIONS_CLASS(); 
     options.fccType = (uint)streamtypeVIDEO; 
     options.lpParms = IntPtr.Zero; 
     options.lpFormat = IntPtr.Zero; 
     bool ok = AVISaveOptions(this.Handle, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE, 1, ref aviStream, ref options); 
    } 
} 

public static readonly int streamtypeVIDEO = mmioFOURCC('v', 'i', 'd', 's'); 
public const UInt32 ICMF_CHOOSE_KEYFRAME = 0x0001; 
public const UInt32 ICMF_CHOOSE_DATARATE = 0x0002; 
public const UInt32 ICMF_CHOOSE_PREVIEW = 0x0004; 
public const int OF_WRITE = 1; 
public const int OF_READWRITE = 2; 
public const int OF_CREATE = 4096; 

[StructLayout(LayoutKind.Sequential)] 
public struct RECT 
{ 
    public UInt32 left; 
    public UInt32 top; 
    public UInt32 right; 
    public UInt32 bottom; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct AVISTREAMINFO 
{ 
    public Int32 fccType; 
    public Int32 fccHandler; 
    public Int32 dwFlags; 
    public Int32 dwCaps; 
    public Int16 wPriority; 
    public Int16 wLanguage; 
    public Int32 dwScale; 
    public Int32 dwRate; 
    public Int32 dwStart; 
    public Int32 dwLength; 
    public Int32 dwInitialFrames; 
    public Int32 dwSuggestedBufferSize; 
    public Int32 dwQuality; 
    public Int32 dwSampleSize; 
    public RECT rcFrame; 
    public Int32 dwEditCount; 
    public Int32 dwFormatChangeCount; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public String szName; 
} 

[StructLayout(LayoutKind.Sequential)] 
public class AVICOMPRESSOPTIONS_CLASS 
{ 
    public UInt32 fccType; 
    public UInt32 fccHandler; 
    public UInt32 dwKeyFrameEvery; 
    public UInt32 dwQuality; 
    public UInt32 dwBytesPerSecond; 
    public UInt32 dwFlags; 
    public IntPtr lpFormat; 
    public UInt32 cbFormat; 
    public IntPtr lpParms; 
    public UInt32 cbParms; 
    public UInt32 dwInterleaveEvery; 
} 

[DllImport("avifil32.dll")] 
public static extern void AVIFileInit(); 

[DllImport("winmm.dll", CharSet = CharSet.Auto)] 
public static extern int mmioStringToFOURCC([MarshalAs(UnmanagedType.LPWStr)] String sz, int uFlags); 

[DllImport("avifil32.dll", PreserveSig = true, CharSet = CharSet.Auto)] 
public static extern int AVIFileOpen(out IntPtr ppfile, String szFile, int uMode, IntPtr pclsidHandler); 

[DllImport("avifil32.dll", CharSet = CharSet.Auto)] 
public static extern int AVIFileCreateStream(IntPtr pfile, out IntPtr ppavi, ref AVISTREAMINFO ptr_streaminfo); 

[DllImport("avifil32.dll")] 
public static extern bool AVISaveOptions(IntPtr hwnd, UInt32 uiFlags, Int32 nStreams, ref IntPtr ppavi, ref AVICOMPRESSOPTIONS_CLASS plpOptions); 
+0

전체 코드를 공유 할 수 있습니까? 언젠가 고통으로 이어질 것입니다 –

답변

4

큰 변화가

문제를 설명 할 수있다, 당신은 아마 가지고

64 윈도우 8 윈도우 7에서 통과되었습니다 - 비트 버전의 Windows 8. 사용하는 두 선언 모두 잘못되어 64 비트 모드로 프로그램을 실행할 때 진단하기가 매우 어렵습니다. 관련 프로젝트 설정은 프로젝트 + 속성, 빌드 탭, 플랫폼 타겟 설정입니다. 여기서 "x86"을 사용하는 것이 가장 좋습니다 (VS2012 이상에서는 32 비트를 선호). 이러한 나쁜 선언으로 인해 고통받을 불행을 제한 할 것입니다.

첫 번째 인수는 PAVIFILE, "인터페이스 포인터를받는 버퍼에 대한 포인터"입니다. 마지막 인수는 CLSID, "클래스 식별자에 대한 포인터"입니다. 포인터는 32 비트 모드에서 4 바이트, 64 비트 모드에서 8 바이트입니다. 해당 C# 선언은 ref 또는 out 키워드를 사용하거나 IntPtr을 사용하여 호환 가능해야합니다.

그래서 첫 번째 인수는 out IntPtr이 올바른지 사용하여 "포인터 포인터"입니다. 너처럼.

마지막 인수는 거의 사용되지 않습니다 그리고 당신은 널 포인터를 전달합니다. 어떤 경우에는 IntPtr으로 선언하고 전화를 걸 때 IntPtr.Zero를 전달해야합니다. 함수는 처음에는 0, 4 바이트를 전달했지만 8 바이트는 0으로 설정됩니다. 잘못된 포인터 값을 생성하고 AccessViolationException을 얻기에 충분합니다.

당신이 사용하는 교체 선언은 특히 불쾌한, 당신은 단지 INT, 4 바이트를 저장하는 데 충분한 공간을 통과,하지만 기능은 64 비트 모드에서 8 바이트를 쓴다. 스택 또는 GC 힙이 손상되어 매우 불쾌합니다. AviFileCreateStream과 같은 후속 호출은 실제로 인터페이스 포인터 값이 영향을받지 않으므로 실패 할 가능성이 큽니다.

은 내가 pinvoke.net 선언을 고정.

+1

1 팩 = 1 .... –

+0

이 정말 도움이되었다,하지만 응용 프로그램은 또한 Win7에는 64 비트 때부터 작동이 중지 이유를 나는 아직도 이해하지 못하는거야. 또한, 수정에도 불구하고 나는 여전히 문제가 있습니다. 제 편집 내용을 읽어 주시겠습니까? –

+0

David의 의견에 많은주의를 기울이지 않았습니다. Pack = 1을 잘못 사용했습니다. 그것을 제거하십시오. –

관련 문제