2016-06-04 13 views
6

मैं सी # में वीएचडी एपीआई का उपयोग करके कुछ vhd/vhdx फ़ाइलों को बनाने की कोशिश कर रहा हूं।सी ++ संघ में सी # - अजीब व्यवहार

typedef struct _CREATE_VIRTUAL_DISK_PARAMETERS 
{ 
    CREATE_VIRTUAL_DISK_VERSION Version; 

    union 
    { 
     struct 
     { 
      GUID     UniqueId; 
      ULONGLONG    MaximumSize; 
      ULONG     BlockSizeInBytes; 
      ULONG     SectorSizeInBytes; 
      PCWSTR    ParentPath; 
      PCWSTR    SourcePath; 
     } Version1; 

     struct 
     { 
      GUID     UniqueId; 
      ULONGLONG    MaximumSize; 
      ULONG     BlockSizeInBytes; 
      ULONG     SectorSizeInBytes; 
      ULONG     PhysicalSectorSizeInBytes; 
      PCWSTR     ParentPath; 
      PCWSTR     SourcePath; 
      OPEN_VIRTUAL_DISK_FLAG OpenFlags; 
      VIRTUAL_STORAGE_TYPE ParentVirtualStorageType; 
      VIRTUAL_STORAGE_TYPE SourceVirtualStorageType; 
      GUID     ResiliencyGuid; 
     } Version2; 

     struct 
     { 
      GUID     UniqueId; 
      ULONGLONG    MaximumSize; 
      ULONG     BlockSizeInBytes; 
      ULONG     SectorSizeInBytes; 
      ULONG     PhysicalSectorSizeInBytes; 
      PCWSTR     ParentPath; 
      PCWSTR     SourcePath; 
      OPEN_VIRTUAL_DISK_FLAG OpenFlags; 
      VIRTUAL_STORAGE_TYPE ParentVirtualStorageType; 
      VIRTUAL_STORAGE_TYPE SourceVirtualStorageType; 
      GUID     ResiliencyGuid; 
      PCWSTR     SourceLimitPath; 
      VIRTUAL_STORAGE_TYPE BackingStorageType; 
     } Version3; 
    }; 
} CREATE_VIRTUAL_DISK_PARAMETERS, *PCREATE_VIRTUAL_DISK_PARAMETERS; 

मैं सी # करने के लिए कि कन्वर्ट करने के लिए कोशिश कर रहा हूँ, लेकिन बहुत किस्मत नहीं होने:

एक सी ++ संघ, जो ऐसा दिखता नहीं है। मुझे संस्करण 3 में बिल्कुल दिलचस्पी नहीं है, इसलिए मैं इसे छोड़ रहा हूं।

मैंने कई चीजों की कोशिश की है और सबसे अच्छा मैं वर्जन 2 काम कर रहा था (वास्तव में कुछ विचित्र कर रहा था), लेकिन मैंने कभी भी संस्करण 1 और संस्करण 2 को एक ही समय में काम नहीं किया है।

समाधान wielded है कि सबसे अच्छा परिणाम अब तक इस किया गया है, लेकिन वहाँ कुछ गड़बड़ है क्योंकि version1 बस काम नहीं करता हो गया है, और version1 में SectorSizeInBytes एक ulong बजाय uint है (अगर मैं इसे करने के लिए बदल uint की तरह यह होना चाहिए, मैं तोड़ Version2 और version1 अभी भी काम नहीं करता है!)

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParameters 
{ 
    [FieldOffset(0)] public CreateVirtualDiskParametersVersion1 Version1; 

    [FieldOffset(0)] public CreateVirtualDiskParametersVersion2 Version2; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParametersVersion1 
{ 
    public CreateVirtualDiskVersion Version; 
    public Guid UniqueId; 
    public ulong MaximumSize; 
    public uint BlockSizeInBytes; 
    public ulong SectorSizeInBytes; 
    public string ParentPath; 
    public string SourcePath; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParametersVersion2 
{ 
    public CreateVirtualDiskVersion Version; 
    public Guid UniqueId; 
    public ulong MaximumSize; 
    public uint BlockSizeInBytes; 
    public uint SectorSizeInBytes; 
    public uint PhysicalSectorSizeInBytes; 
    public string ParentPath; 
    public string SourcePath; 
    public OpenVirtualDiskFlags OpenFlags; 
    public VirtualStorageType ParentVirtualStorageType; 
    public VirtualStorageType SourceVirtualStorageType; 
    public Guid ResiliencyGuid; 
} 

मैं जानता हूँ कि सैद्धांतिक रूप से Version क्षेत्र संस्करण structs के बाहर स्थापित किया जाना चाहिए और मुझे लगता है कि कोशिश की है और साथ ही, लेकिन यह सिर्फ टूट जाता है चीजें और भी मजेदार पर्याप्त ...

तो, क्या कोई सलाह दे सकता है कि ऊपर से सी # का उचित अनुवाद कैसे करें, संस्करण 3 संरचना को छोड़कर इसकी आवश्यकता नहीं है?

+0

'उलझन (64 बिट)' और 'उल (32 बिट)' दोनों को 'उलंग (64 बिट)' के रूप में मैप किया जाना प्रतीत होता है। – AlexD

+0

क्या आपने अपने सी ++ structs के सदस्यों के ऑफसेट को प्रिंट करने का प्रयास किया है? –

+0

@TheodorosChatzigiannakis बिल्कुल यकीन नहीं है कि मैं इस बात को ध्यान में रखकर कैसे करूं जिसमें इसमें enums/structs और तार शामिल हैं। मेरा मतलब है, वे किस आकार का होगा? मैं इसे आजमाने के लिए खुला हूं, मुझे बताएं कि किस मूल्य का उपयोग करना है और मैं इसे एक शॉट दूंगा। – cogumel0

उत्तर

1

Pack = 1StructLayout लिए विशेषताओं का उपयोग करना struct सदस्यों के बीच किसी भी गद्दी दूर करता है। टीसीपी कनेक्शन में स्ट्रक्चर आमतौर पर बिना पैडिंग के पास पास किए जाते हैं ताकि संरचना का उपयोग करने वाले सभी प्रोग्राम स्मृति में अपने लेआउट पर सहमत हो सकें।

हालांकि @ डेविड हेफरनन ने बताया कि विंडोज डीएलएल के लिए structs पास करते समय यह मामला नहीं हो सकता है। मैंने CreateVirtualDisk पर वास्तविक कॉल का परीक्षण नहीं किया क्योंकि यह थोड़ा जोखिम भरा प्रतीत होता है, क्योंकि मैंने यह कॉल पहले नहीं किया है और अगर मैंने कोई गलती की है तो मेरी डिस्क को क्लॉबर नहीं करना चाहता था। ऐसा लगता है कि 8 बाइट्स (Pack = 0 डिफ़ॉल्ट या Pack = 8) के डिफ़ॉल्ट पैकिंग निम्न उद्धरण के आधार पर सही सेटिंग हो सकती है।

देखें 64-bit Windows API struct alignment caused Access Denied error on named pipe

विंडोज एसडीके 8 बाइट्स होने की पैकिंग की उम्मीद। Using the Windows Headers

से परियोजनाओं डिफ़ॉल्ट संरचना पैकिंग, जो वर्तमान में 8 बाइट्स है क्योंकि सबसे बड़ा अभिन्न प्रकार 8 बाइट्स का उपयोग करने के संकलित किया जाना चाहिए। ऐसा करने से यह सुनिश्चित होता है कि हेडर फ़ाइलों के भीतर सभी संरचना प्रकारों को विंडोज एपीआई के समान संरेखण के साथ एप्लिकेशन में संकलित किया गया है। यह यह भी सुनिश्चित करता है कि 8-बाइट मानों के साथ संरचनाओं को सही तरीके से गठबंधन किया गया है और डेटा संरेखण को लागू करने वाले प्रोसेसर पर संरेखण दोष नहीं होंगे।

VersionCreateVirtualDiskParameters के शीर्ष पर ले जाया गया है। दो यूनियनों का पालन करें। दोनों का एक ही ऑफ़सेट sizeof(CREATE_VIRTUAL_DISK_VERSION) है।

SectorSizeInBytesuintulong के बजायहै।

आप marshaller दे सकते हैं विशेषता का उपयोग string सदस्यों भरने का काम, जैसे

[MarshalAs(UnmanagedType.LPWStr)] public string ParentPath; 

या, के रूप में यह स्मृति में प्रकट होता है, जो एक यूनिकोड स्ट्रिंग के लिए एक सूचक है कि आप इसे का प्रतिनिधित्व कर सकते हैं:

public IntPtr ParentPath; 

और फिर स्ट्रिंग खुद के साथ निकालने

Marshal.PtrToStringAuto(vdp.Version1.ParentPath) 

आप एक बाहरी DLL सी # struct गुजर रहे हैं, यह एक अप्रबंधित स्ट्रिंग

vdp.Version1.ParentPath = (IntPtr)Marshal.StringToHGlobalAuto("I am a managed string"); 

से भर तो अप्रबंधित स्ट्रिंग जब आप इसे का काम समाप्त हो

Marshal.FreeHGlobal(vdp.Version1.ParentPath); 

इस प्रयास करें मुक्त।

public enum CREATE_VIRTUAL_DISK_VERSION 
{ 
    CREATE_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0, 
    CREATE_VIRTUAL_DISK_VERSION_1 = 1, 
    CREATE_VIRTUAL_DISK_VERSION_2 = 2 
}; 
public enum OPEN_VIRTUAL_DISK_FLAG 
{ 
    OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000, 
    OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 0x00000001, 
    OPEN_VIRTUAL_DISK_FLAG_BLANK_FILE = 0x00000002, 
    OPEN_VIRTUAL_DISK_FLAG_BOOT_DRIVE = 0x00000004, 
    OPEN_VIRTUAL_DISK_FLAG_CACHED_IO = 0x00000008, 
    OPEN_VIRTUAL_DISK_FLAG_CUSTOM_DIFF_CHAIN = 0x00000010 
}; 

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] 
public struct VIRTUAL_STORAGE_TYPE 
{ 
    uint DeviceId; 
    Guid VendorId; 
}; 

[StructLayout(LayoutKind.Explicit, Pack = 8, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParameters 
{ 
    [FieldOffset(0)] 
    public CREATE_VIRTUAL_DISK_VERSION Version; 

    [FieldOffset(8))] 
    public CreateVirtualDiskParametersVersion1 Version1; 

    [FieldOffset(8))] 
    public CreateVirtualDiskParametersVersion2 Version2; 
} 

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParametersVersion1 
{ 
    public Guid UniqueId; 
    public ulong MaximumSize; 
    public uint BlockSizeInBytes; 
    public uint SectorSizeInBytes; 
    //public IntPtr ParentPath; // PCWSTR in C++ which is a pointer to a Unicode string 
    //public IntPtr SourcePath; //string 
    [MarshalAs(UnmanagedType.LPWStr)] public string ParentPath; 
    [MarshalAs(UnmanagedType.LPWStr)] public string SourcePath; 
} 

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] 
public struct CreateVirtualDiskParametersVersion2 
{ 
    public Guid UniqueId; 
    public ulong MaximumSize; 
    public uint BlockSizeInBytes; 
    public uint SectorSizeInBytes; 
    public uint PhysicalSectorSizeInBytes; 
    //public IntPtr ParentPath; //string 
    //public IntPtr SourcePath; //string 
    [MarshalAs(UnmanagedType.LPWStr)] public string ParentPath; 
    [MarshalAs(UnmanagedType.LPWStr)] public string SourcePath; 
    public OPEN_VIRTUAL_DISK_FLAG OpenFlags; 
    public VIRTUAL_STORAGE_TYPE ParentVirtualStorageType; 
    public VIRTUAL_STORAGE_TYPE SourceVirtualStorageType; 
    public Guid ResiliencyGuid; 
} 
+0

धन्यवाद जॉन डी यह बहुत अच्छा है, लेकिन क्या मैं सिर्फ पूछ सकता हूं कि '[फील्ड ऑफसेट (आकार (CREATE_VIRTUAL_DISK_VERSION))]'? 'CREATE_VIRTUAL_DISK_VERSION' एक enum (int का) है, इसलिए इसका ध्यान किसी भी बाइट के बावजूद 4 बाइट्स का आकार होना चाहिए? – cogumel0

+0

स्ट्रक्चर आमतौर पर गठबंधन होते हैं और पैक नहीं होते हैं। क्या आप इसे अभी बना रहे हैं? –

+0

@cogumeIO यह वर्तमान में सच है - यह उस मामले को संभालने का प्रयास कर रहा था जहां 'CREATE_VIRTUAL_DISK_VERSION' बदल सकता है (उदाहरण के लिए एक प्रमुख और मामूली संस्करण संख्या)। उस स्थिति में आप इसे 'struct' के साथ बदल देंगे। सी ++ स्ट्रक्चर परिभाषा 'उल 'के बजाय' CREATE_VIRTUAL_DISK_VERSION' का उपयोग करती है, इसलिए यह एक संभावना है। –

संबंधित मुद्दे