Sử dụng bản đồ bộ nhớ với dịch vụ


8

Tôi đã xây dựng một ứng dụng cũng có thể được chạy như một dịch vụ (sử dụng một -servicechuyển đổi). Điều này hoạt động hoàn hảo không có vấn đề gì khi tôi chạy dịch vụ từ dấu nhắc lệnh (Tôi có một cái gì đó được thiết lập cho phép tôi gỡ lỗi nó từ bảng điều khiển khi không được chạy như một dịch vụ thực sự). Tuy nhiên, khi tôi cố chạy nó như một dịch vụ thực sự thì sử dụng ứng dụng của mình để mở bản đồ bộ nhớ hiện có, tôi gặp lỗi ...

Không thể tìm thấy tập tin được chỉ định.

Cách tôi chạy nó như một dịch vụ hoặc trong bảng điều khiển:

[STAThread]
static void Main(string[] args)
{
    //Convert all arguments to lower
    args = Array.ConvertAll(args, e => e.ToLower());

    //Create the container object for the settings to be stored
    Settings.Bag = new SettingsBag();

    //Check if we want to run this as a service
    bool runAsService = args.Contains("-service");

    //Check if debugging
    bool debug = Environment.UserInteractive;

    //Catch all unhandled exceptions as well
    if (!debug || debug)
    {
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }

    if (runAsService)
    {
        //Create service array
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new CRSService()
        };

        //Run services in interactive mode if needed
        if (debug)
            RunInteractive(ServicesToRun);
        else
            ServiceBase.Run(ServicesToRun);
    }
    else
    {
        //Start the main gui
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainGUI());
    }
}

Trong ứng dụng của tôi, tôi có một bên dịch vụ và một bên ứng dụng. Mục đích của ứng dụng chỉ là kiểm soát dịch vụ. Tôi thực hiện tất cả các điều khiển bằng các tệp ánh xạ bộ nhớ và nó có vẻ hoạt động tốt và phù hợp với nhu cầu của tôi. Tuy nhiên, khi tôi chạy ứng dụng như một dịch vụ thực sự, tôi thấy từ nhật ký gỡ lỗi của mình, nó đang tạo tệp bản đồ bộ nhớ với tên và cài đặt truy cập chính xác. Tôi cũng có thể thấy tập tin được tạo ở nơi cần có. Mọi thứ dường như hoạt động chính xác như nhau trong dịch vụ giống như khi tôi gỡ lỗi thông qua bảng điều khiển. Tuy nhiên, ứng dụng của tôi (khi được chạy dưới dạng ứng dụng thay vì dịch vụ) cho tôi biết nó không thể tìm thấy tệp bản đồ bộ nhớ. Tôi cũng bị lỗi đường dẫn tên tệp vì vậy tôi biết nó đang tìm đúng chỗ.

Cách tôi mở bản đồ bộ nhớ (lỗi được ném):

m_mmf = MemoryMappedFile.OpenExisting(
    m_sMapName,
    MemoryMappedFileRights.ReadWrite
);

Lưu ý: Dịch vụ này đang chạy cùng một tài khoản với tôi chạy Visual Studio. Ví dụ như hình ảnh bên dưới hiển thị trình quản lý tác vụ của tôi, dịch vụ.msc gui và tài khoản hiện được xác định của tôi.

nhập mô tả hình ảnh ở đây

Làm cách nào tôi có thể nhận ứng dụng khách của mình để xem tệp bản đồ bộ nhớ sau khi dịch vụ tạo nó? Tại sao nó hoạt động khi tôi chạy nó như một dịch vụ điều khiển mà không phải khi tôi chạy nó như một dịch vụ thực sự?


@Amy Tôi nghĩ rằng phiên bản Visual Studio rất quan trọng vì tôi không thể sử dụng bất cứ thứ gì cao hơn VS2017. Ví dụ: nếu một câu trả lời có thể hoạt động với VS2019 nhưng không phải là 2017 thì câu trả lời sẽ không được chấp nhận. Hy vọng rằng có ý nghĩa.
Arvo Bowen

"Tôi không thể sử dụng bất cứ thứ gì cao hơn VS2017" không phải là lý do để nghi ngờ VS chịu trách nhiệm. Phiên bản nào của C # và .Net Framework bạn đang sử dụng? Thêm những câu hỏi của bạn Các thẻ VS chỉ nên được áp dụng khi câu hỏi về VS.
Amy

Tài khoản nào là dịch vụ được đăng ký để chạy theo? Nếu là tài khoản Hệ thống, vấn đề có thể là tay cầm và tên được bảo vệ khỏi tài khoản người dùng để truy cập chúng.
Joel Lucsy

3
Bạn đã đặt tiền tố tên với Toàn cầu như "Toàn cầu \ MyName" chưa? bạn có thể thấy điều này từ ví dụ tại docs.microsoft.com/en-us/windows/win32/memory/ mẹo
Joel Lucsy

2
Chà, đó là vấn đề sau đó, tên của nó phải là @ "Toàn cầu \ myappauss_mm_tlass" để làm cho nó hoạt động khi bạn chạy nó như một dịch vụ. Các dịch vụ chạy trong một phiên khác với phiên người dùng đã đăng nhập, Windows giữ các không gian tên cho các đối tượng kernel bị cô lập cho các phiên để chúng không thể can thiệp lẫn nhau. Trừ khi bạn chọn tham gia vào không gian tên toàn cầu. Nó hoạt động khi bạn kiểm tra nó bởi vì cả hai chương trình chạy trong cùng một phiên.
Hans Passant

Câu trả lời:


5

Các dịch vụ Windows chạy riêng rẽ, trong Phiên 0, trong khi ứng dụng Console của bạn chạy trong phiên người dùng, để chúng giao tiếp với nhau, tệp ánh xạ bộ nhớ phải được tạo trong Global\không gian tên, để có thể truy cập được vào các phiên khác. ví dụ

var file = MemoryMappedFile.CreateOrOpen(@"Global\MyMemoryMappedFile", ...

Bạn cũng nên đặt quyền thích hợp cho tệp để đảm bảo tất cả người dùng có thể truy cập tệp.

Tôi khuyên bạn nên đọc bài đăng này Triển khai bộ nhớ không bị lưu giữ Các tập tin được ánh xạ phơi bày Truyền thông kiểu IPC với Windows Services , giải thích chi tiết hơn ở trên và có ví dụ về cách đặt quyền, v.v.


Mã nguồn được sao chép từ bài đăng được liên kết ở trên:

Mutex, Mutex Security & MMF Tạo chính sách bảo mật

bool mutexCreated;
Mutex mutex;
MutexSecurity mutexSecurity = new MutexSecurity();
MemoryMappedFileSecurity mmfSecurity = new MemoryMappedFileSecurity();

mutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow));
mmfSecurity.AddAccessRule(new AccessRule<MemoryMappedFileRights>("everyone", MemoryMappedFileRights.FullControl, 
AccessControlType.Allow));

mutex = new Mutex(false, @"Global\MyMutex", out mutexCreated, mutexSecurity);
if (mutexCreated == false) log.DebugFormat("There has been an error creating the mutex"); 
else log.DebugFormat("mutex created successfully");

Tạo và ghi vào MMF

MemoryMappedFile file = MemoryMappedFile.CreateOrOpen(@"Global\MyMemoryMappedFile", 4096, 
MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, mmfSecurity, 
HandleInheritability.Inheritable);

using (MemoryMappedViewAccessor accessor = file.CreateViewAccessor()) {
   string xmlData = SerializeToXml(CurrentJobQueue) + "\0"; // \0 terminates the XML to stop badly formed 
issues when the next string written is shorter than the current

    byte[] buffer = ConvertStringToByteArray(xmlData);
    mutex.WaitOne();
    accessor.WriteArray<byte>(0, buffer, 0, buffer.Length);
    mutex.ReleaseMutex();
    }

Đọc từ MMF

using (MemoryMappedFile file = MemoryMappedFile.OpenExisting(
   @"Global\MyMemoryMappedFile", MemoryMappedFileRights.Read)) {

     using (MemoryMappedViewAccessor accessor =
         file.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read)) {
         byte[] buffer = new byte[accessor.Capacity];

         Mutex mutex = Mutex.OpenExisting(@"Global\MyMutex");
         mutex.WaitOne();
         accessor.ReadArray<byte>(0, buffer, 0, buffer.Length);
         mutex.ReleaseMutex();

         string xmlData = ConvertByteArrayToString(buffer);
         data = DeserializeFromXML(xmlData);
       }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.